linux/drivers/gpio/gpio-palmas.c
<<
>>
Prefs
   1/*
   2 * TI Palma series PMIC's GPIO driver.
   3 *
   4 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
   5 *
   6 * Author: Laxman Dewangan <ldewangan@nvidia.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms and conditions of the GNU General Public License,
  10 * version 2, as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope it will be useful, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15 * more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include <linux/gpio.h>
  22#include <linux/kernel.h>
  23#include <linux/init.h>
  24#include <linux/mfd/palmas.h>
  25#include <linux/of.h>
  26#include <linux/of_device.h>
  27#include <linux/platform_device.h>
  28
  29struct palmas_gpio {
  30        struct gpio_chip gpio_chip;
  31        struct palmas *palmas;
  32};
  33
  34struct palmas_device_data {
  35        int ngpio;
  36};
  37
  38static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
  39{
  40        struct palmas_gpio *pg = gpiochip_get_data(gc);
  41        struct palmas *palmas = pg->palmas;
  42        unsigned int val;
  43        int ret;
  44        unsigned int reg;
  45        int gpio16 = (offset/8);
  46
  47        offset %= 8;
  48        reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
  49
  50        ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
  51        if (ret < 0) {
  52                dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
  53                return ret;
  54        }
  55
  56        if (val & BIT(offset))
  57                reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT;
  58        else
  59                reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN;
  60
  61        ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
  62        if (ret < 0) {
  63                dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
  64                return ret;
  65        }
  66        return !!(val & BIT(offset));
  67}
  68
  69static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
  70                        int value)
  71{
  72        struct palmas_gpio *pg = gpiochip_get_data(gc);
  73        struct palmas *palmas = pg->palmas;
  74        int ret;
  75        unsigned int reg;
  76        int gpio16 = (offset/8);
  77
  78        offset %= 8;
  79        if (gpio16)
  80                reg = (value) ?
  81                        PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2;
  82        else
  83                reg = (value) ?
  84                        PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT;
  85
  86        ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset));
  87        if (ret < 0)
  88                dev_err(gc->parent, "Reg 0x%02x write failed, %d\n", reg, ret);
  89}
  90
  91static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
  92                                int value)
  93{
  94        struct palmas_gpio *pg = gpiochip_get_data(gc);
  95        struct palmas *palmas = pg->palmas;
  96        int ret;
  97        unsigned int reg;
  98        int gpio16 = (offset/8);
  99
 100        offset %= 8;
 101        reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
 102
 103        /* Set the initial value */
 104        palmas_gpio_set(gc, offset, value);
 105
 106        ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg,
 107                                BIT(offset), BIT(offset));
 108        if (ret < 0)
 109                dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
 110                        ret);
 111        return ret;
 112}
 113
 114static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
 115{
 116        struct palmas_gpio *pg = gpiochip_get_data(gc);
 117        struct palmas *palmas = pg->palmas;
 118        int ret;
 119        unsigned int reg;
 120        int gpio16 = (offset/8);
 121
 122        offset %= 8;
 123        reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
 124
 125        ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);
 126        if (ret < 0)
 127                dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
 128                        ret);
 129        return ret;
 130}
 131
 132static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 133{
 134        struct palmas_gpio *pg = gpiochip_get_data(gc);
 135        struct palmas *palmas = pg->palmas;
 136
 137        return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
 138}
 139
 140static const struct palmas_device_data palmas_dev_data = {
 141        .ngpio = 8,
 142};
 143
 144static const struct palmas_device_data tps80036_dev_data = {
 145        .ngpio = 16,
 146};
 147
 148static const struct of_device_id of_palmas_gpio_match[] = {
 149        { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,},
 150        { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,},
 151        { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,},
 152        { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,},
 153        { },
 154};
 155
 156static int palmas_gpio_probe(struct platform_device *pdev)
 157{
 158        struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
 159        struct palmas_platform_data *palmas_pdata;
 160        struct palmas_gpio *palmas_gpio;
 161        int ret;
 162        const struct of_device_id *match;
 163        const struct palmas_device_data *dev_data;
 164
 165        match = of_match_device(of_palmas_gpio_match, &pdev->dev);
 166        if (!match)
 167                return -ENODEV;
 168        dev_data = match->data;
 169        if (!dev_data)
 170                dev_data = &palmas_dev_data;
 171
 172        palmas_gpio = devm_kzalloc(&pdev->dev,
 173                                sizeof(*palmas_gpio), GFP_KERNEL);
 174        if (!palmas_gpio)
 175                return -ENOMEM;
 176
 177        palmas_gpio->palmas = palmas;
 178        palmas_gpio->gpio_chip.owner = THIS_MODULE;
 179        palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
 180        palmas_gpio->gpio_chip.ngpio = dev_data->ngpio;
 181        palmas_gpio->gpio_chip.can_sleep = true;
 182        palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
 183        palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
 184        palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
 185        palmas_gpio->gpio_chip.set      = palmas_gpio_set;
 186        palmas_gpio->gpio_chip.get      = palmas_gpio_get;
 187        palmas_gpio->gpio_chip.parent = &pdev->dev;
 188#ifdef CONFIG_OF_GPIO
 189        palmas_gpio->gpio_chip.of_node = pdev->dev.of_node;
 190#endif
 191        palmas_pdata = dev_get_platdata(palmas->dev);
 192        if (palmas_pdata && palmas_pdata->gpio_base)
 193                palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
 194        else
 195                palmas_gpio->gpio_chip.base = -1;
 196
 197        ret = devm_gpiochip_add_data(&pdev->dev, &palmas_gpio->gpio_chip,
 198                                     palmas_gpio);
 199        if (ret < 0) {
 200                dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 201                return ret;
 202        }
 203
 204        platform_set_drvdata(pdev, palmas_gpio);
 205        return ret;
 206}
 207
 208static struct platform_driver palmas_gpio_driver = {
 209        .driver.name    = "palmas-gpio",
 210        .driver.of_match_table = of_palmas_gpio_match,
 211        .probe          = palmas_gpio_probe,
 212};
 213
 214static int __init palmas_gpio_init(void)
 215{
 216        return platform_driver_register(&palmas_gpio_driver);
 217}
 218subsys_initcall(palmas_gpio_init);
 219