add MTK-combo-module
[firefly-linux-kernel-4.4.55.git] / drivers / gpio / tps65910-gpio.c
index 36e1889767d30a8afe178c55dbb3769e8d99e0f1..15097ca616d69606e150ab96c62bfa89a38159cf 100644 (file)
 /*
- * tps65910_gpio.c -- access to GPIOs on TPS65910x chips
+ * tps65910-gpio.c  --  TI TPS6591x
  *
- * Copyright (C) 2010 Mistral solutions Pvt Ltd <www.mistralsolutions.com>
+ * Copyright 2010 Texas Instruments Inc.
  *
- * Based on twl4030-gpio.c
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kthread.h>
-#include <linux/irq.h>
+#include <linux/errno.h>
 #include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <linux/i2c/tps65910.h>
-
-static int gpio_tps65910_remove(struct platform_device *pdev);
-
-/*
- * The GPIO "subchip" supports 1 GPIOs which can be configured as
- * inputs or outputs, with pullups or pulldowns on each pin.  Each
- * GPIO can trigger interrupts on either or both edges.
- */
-
-
-/* Data structures */
-static struct gpio_chip tps65910_gpiochip;
-static DEFINE_MUTEX(gpio_lock);
-static unsigned int gpio_usage_count;
-static struct work_struct  gpio_work;
-static struct mutex work_lock;
-/*
- * To configure TPS65910 GPIO registers
- */
-static inline int gpio_tps65910_write(u8 address, u8 data)
-{
-       return tps65910_i2c_write_u8(TPS65910_I2C_ID0, data, address);
-}
-
-
-/*
- * To read a TPS65910 GPIO module register
- */
-static inline int gpio_tps65910_read(u8 address)
-{
-       u8 data;
-       int ret = 0;
-
-       ret = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &data, address);
-       return (ret < 0) ? ret : data;
-}
-
-static int tps65910_request(struct gpio_chip *chip, unsigned offset)
-{
-       int status = 0;
-
-       mutex_lock(&gpio_lock);
-
-       /* initialize TPS65910 GPIO */
-       /* By default the GPIO_CKSYNC signal is GPIO */
-       if (!gpio_usage_count)
-               gpio_usage_count++;
-
-       mutex_unlock(&gpio_lock);
-       return status;
-}
+#include <linux/i2c.h>
+#include <linux/mfd/tps65910.h>
 
-static void tps65910_free(struct gpio_chip *chip, unsigned offset)
+static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-       mutex_lock(&gpio_lock);
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+       uint8_t val;
 
-       /* on last use, switch off GPIO module */
-       if (!gpio_usage_count)
-               gpio_usage_count--;
+       tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val);
 
-       mutex_unlock(&gpio_lock);
-}
-
-static int tps65910_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-       /* Configure TPS65910 GPIO as input */
-       u8 val;
-
-       mutex_lock(&gpio_lock);
-
-       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
-
-       val &= ~(TPS65910_GPIO_CFG_OUTPUT);
-
-       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
-
-       mutex_unlock(&gpio_lock);
-
-       return 0;
-}
-
-static int tps65910_get(struct gpio_chip *chip, unsigned offset)
-{
-       int status = 0;
-
-       mutex_lock(&gpio_lock);
-
-       status = gpio_tps65910_read(TPS65910_REG_GPIO0);
-
-       mutex_unlock(&gpio_lock);
-       if (status & 0x01)
+       if (val & GPIO_STS_MASK)
                return 1;
-       else
-               return 0;
-}
-static
-int tps65910_direction_out(struct gpio_chip *chip, unsigned offset, int value)
-{
-       /* Configure TPS65910 GPIO as input */
-       u8 val;
-       u32 ret;
-       mutex_lock(&gpio_lock);
-       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
 
-       val |= TPS65910_GPIO_CFG_OUTPUT;
-
-       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
-       mutex_unlock(&gpio_lock);
-
-       if (ret != 0)
-               return -EIO;
        return 0;
 }
 
-static void tps65910_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       int val = 0;
-       u32 ret;
-
-       mutex_lock(&gpio_lock);
-       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
-
-       if (value == 1)
-               val |= 0x01;
-       else
-               val &= 0xFE;
-
-       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
-
-       mutex_unlock(&gpio_lock);
-}
-
-
-
-static void tps65910_gpio_set_debounce(u8 debounce)
+static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
+                             int value)
 {
-       u8 val;
-
-       mutex_lock(&gpio_lock);
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
 
-       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
-
-       if (debounce == TPS65910_DEBOUNCE_91_5_MS)
-               val = (0<<4);
-       else if (debounce == TPS65910_DEBOUNCE_150_MS)
-               val = (1<<4);
+       if (value)
+               tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_SET_MASK);
        else
-               printk(KERN_ERR "Invalid argument to %s\n", __func__);
-
-       gpio_tps65910_write(TPS65910_REG_GPIO0, val);
-
-       mutex_unlock(&gpio_lock);
+               tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_SET_MASK);
 }
-EXPORT_SYMBOL(tps65910_gpio_set_debounce);
 
-
-static void tps65910_gpio_pullup_enable(void)
+static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
 {
-       u8 val;
-       u32 ret;
-
-       mutex_lock(&gpio_lock);
-
-       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
 
-       val = (1<<3);
+       /* Set the initial value */
+       tps65910_gpio_set(gc, 0, value);
 
-       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
-
-       mutex_unlock(&gpio_lock);
-
-       if (ret != 0)
-               printk(KERN_ERR "Error writing to TPS65910_REG_GPIO0 in %s \n",
-                               __func__);
-}
-EXPORT_SYMBOL(tps65910_gpio_pullup_enable);
-
-static void tps65910_gpio_pullup_disable(void)
-{
-       u8 val;
-       u32 ret;
-
-       mutex_lock(&gpio_lock);
-
-       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
-
-       val = (0<<3);
-
-       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
-
-       mutex_unlock(&gpio_lock);
+       return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_CFG_MASK);
 }
-EXPORT_SYMBOL(tps65910_gpio_pullup_disable);
 
-static void tps65910_gpio_work(struct work_struct *work)
+static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
 {
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
 
-       /* Read the status register and take action  */
-       u8 status2;
-       int err;
-       mutex_lock(&work_lock);
-       err =  tps65910_i2c_read_u8(TPS65910_I2C_ID0, &status2,
-                       TPS65910_REG_INT_STS);
-       if (!err) {
-               switch (status2) {
-               case TPS65910_GPIO_F_IT:
-                       printk(KERN_NOTICE "Received TPS65910 GPIO falling \
-                               edge interrupt \n");
-                       /* Clear interrupt */
-                       tps65910_i2c_write_u8(TPS65910_I2C_ID0, status2,
-                                       TPS65910_REG_INT_STS);
-                       /* Add code accroding to board requirment */
-                       break;
-               case TPS65910_GPIO_R_IT:
-                       printk(KERN_NOTICE "Received TPS65910 GPIO Raising \
-                                edge interrupt \n");
-                       /* Clear interrupt */
-                       tps65910_i2c_write_u8(TPS65910_I2C_ID0, status2,
-                                       TPS65910_REG_INT_STS);
-                       /* Add code accroding to board requirment */
-                       break;
-               }
-       } else {
-               printk(KERN_ERR"Could not read TPS65910_REG_INT_STS\n");
-       }
-
-       mutex_unlock(&work_lock);
-
+       return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_CFG_MASK);
 }
 
-
-
-static irqreturn_t tps65910_gpio_isr(int irq, void *_tps65910)
+void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
 {
-       /* Disable IRQ, schedule work, enable IRQ and  acknowledge */
-       disable_irq(irq);
-       (void) schedule_work(&gpio_work);
-       enable_irq(irq);
-       return IRQ_HANDLED;
-}
-
-
-static struct gpio_chip tps65910_gpiochip = {
-       .label                  = "tps65910",
-       .owner                  = THIS_MODULE,
-       .request                = tps65910_request,
-       .free                   = tps65910_free,
-       .direction_input        = tps65910_direction_in,
-       .get                    = tps65910_get,
-       .direction_output       = tps65910_direction_out,
-       .set                    = tps65910_set,
-};
-
-
-static int __devinit gpio_tps65910_probe(struct platform_device *pdev)
-{
-       int ret = -1;
-       int status = 0;
-
-       struct tps65910_gpio *pdata = pdev->dev.platform_data;
-
-       if (pdata->gpio_mode == TPS65910_GPIO_AS_IRQ) {
-
-               if (pdata->irq_num) {
-                       status = request_irq(pdata->irq_num, tps65910_gpio_isr,
-                                       IRQF_SHARED, "tps65910_gpio", pdev);
-                       if (status < 0) {
-                               pr_err("tps65910: could not claim irq%d: %d\n",
-                                       pdata->irq_num, status);
-                       }
-
-               }
+       int ret;
 
-               INIT_WORK(&gpio_work, tps65910_gpio_work);
-               mutex_init(&work_lock);
+       if (!gpio_base)
+               return;
 
-               tps65910_gpiochip.ngpio = TPS65910_GPIO_MAX;
-               tps65910_gpiochip.dev = &pdev->dev;
+       tps65910->gpio.owner            = THIS_MODULE;
+       tps65910->gpio.label            = tps65910->i2c_client->name;
+       tps65910->gpio.dev              = tps65910->dev;
+       tps65910->gpio.base             = gpio_base;
 
-               ret = gpiochip_add(&tps65910_gpiochip);
-
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "could not register gpiochip \
-                                %d\n", ret);
-                       tps65910_gpiochip.ngpio = 0;
-                       gpio_tps65910_remove(pdev);
-                       return -ENODEV;
-               }
-               if (pdata->gpio_setup)
-                       pdata->gpio_setup(pdata);
+       switch(tps65910_chip_id(tps65910)) {
+       case TPS65910:
+               tps65910->gpio.ngpio    = 6;
+               break;
+       case TPS65911:
+               tps65910->gpio.ngpio    = 9;
+               break;
+       default:
+               return;
        }
-       return ret;
-}
-
-static int gpio_tps65910_remove(struct platform_device *pdev)
-{
-       struct tps65910_gpio *pdata = pdev->dev.platform_data;
-       int status;
-
-       if (pdata->gpio_taredown)
-               pdata->gpio_taredown(pdata);
-       if (pdata->gpio_mode == TPS65910_GPIO_AS_IRQ)
-               free_irq(pdata->irq_num, NULL);
-
-       status = gpiochip_remove(&tps65910_gpiochip);
-       if (status < 0)
-               return status;
-       return 0;
-}
+       tps65910->gpio.can_sleep        = 1;
 
-static struct platform_driver gpio_tps65910_driver = {
-       .driver.name    = "tps65910_gpio",
-       .driver.owner   = THIS_MODULE,
-       .probe          = gpio_tps65910_probe,
-       .remove         = gpio_tps65910_remove,
-};
+       tps65910->gpio.direction_input  = tps65910_gpio_input;
+       tps65910->gpio.direction_output = tps65910_gpio_output;
+       tps65910->gpio.set              = tps65910_gpio_set;
+       tps65910->gpio.get              = tps65910_gpio_get;
 
-static int __init gpio_tps65910_init(void)
-{
-       return platform_driver_register(&gpio_tps65910_driver);
-}
-subsys_initcall(gpio_tps65910_init);
+       ret = gpiochip_add(&tps65910->gpio);
 
-static void __exit gpio_tps65910_exit(void)
-{
-       platform_driver_unregister(&gpio_tps65910_driver);
+       if (ret)
+               dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret);
 }
-module_exit(gpio_tps65910_exit);
-
-MODULE_AUTHOR("Mistral Solutions Pvt Ltd.");
-MODULE_DESCRIPTION("GPIO interface for TPS65910");
-MODULE_LICENSE("GPL");