linux/drivers/gpio/gpio-tps65910.c
<<
>>
Prefs
   1/*
   2 * TI TPS6591x GPIO driver
   3 *
   4 * Copyright 2010 Texas Instruments Inc.
   5 *
   6 * Author: Graeme Gregory <gg@slimlogic.co.uk>
   7 * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk>
   8 *
   9 *  This program is free software; you can redistribute it and/or modify it
  10 *  under  the terms of the GNU General  Public License as published by the
  11 *  Free Software Foundation;  either version 2 of the License, or (at your
  12 *  option) any later version.
  13 *
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/errno.h>
  19#include <linux/gpio.h>
  20#include <linux/i2c.h>
  21#include <linux/platform_device.h>
  22#include <linux/mfd/tps65910.h>
  23#include <linux/of_device.h>
  24
  25struct tps65910_gpio {
  26        struct gpio_chip gpio_chip;
  27        struct tps65910 *tps65910;
  28};
  29
  30static inline struct tps65910_gpio *to_tps65910_gpio(struct gpio_chip *chip)
  31{
  32        return container_of(chip, struct tps65910_gpio, gpio_chip);
  33}
  34
  35static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
  36{
  37        struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
  38        struct tps65910 *tps65910 = tps65910_gpio->tps65910;
  39        unsigned int val;
  40
  41        tps65910_reg_read(tps65910, TPS65910_GPIO0 + offset, &val);
  42
  43        if (val & GPIO_STS_MASK)
  44                return 1;
  45
  46        return 0;
  47}
  48
  49static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
  50                              int value)
  51{
  52        struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
  53        struct tps65910 *tps65910 = tps65910_gpio->tps65910;
  54
  55        if (value)
  56                tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset,
  57                                                GPIO_SET_MASK);
  58        else
  59                tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
  60                                                GPIO_SET_MASK);
  61}
  62
  63static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
  64                                int value)
  65{
  66        struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
  67        struct tps65910 *tps65910 = tps65910_gpio->tps65910;
  68
  69        /* Set the initial value */
  70        tps65910_gpio_set(gc, offset, value);
  71
  72        return tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset,
  73                                                GPIO_CFG_MASK);
  74}
  75
  76static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
  77{
  78        struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
  79        struct tps65910 *tps65910 = tps65910_gpio->tps65910;
  80
  81        return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
  82                                                GPIO_CFG_MASK);
  83}
  84
  85#ifdef CONFIG_OF
  86static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev,
  87                struct tps65910 *tps65910, int chip_ngpio)
  88{
  89        struct tps65910_board *tps65910_board = tps65910->of_plat_data;
  90        unsigned int prop_array[TPS6591X_MAX_NUM_GPIO];
  91        int ngpio = min(chip_ngpio, TPS6591X_MAX_NUM_GPIO);
  92        int ret;
  93        int idx;
  94
  95        tps65910_board->gpio_base = -1;
  96        ret = of_property_read_u32_array(tps65910->dev->of_node,
  97                        "ti,en-gpio-sleep", prop_array, ngpio);
  98        if (ret < 0) {
  99                dev_dbg(dev, "ti,en-gpio-sleep not specified\n");
 100                return tps65910_board;
 101        }
 102
 103        for (idx = 0; idx < ngpio; idx++)
 104                tps65910_board->en_gpio_sleep[idx] = (prop_array[idx] != 0);
 105
 106        return tps65910_board;
 107}
 108#else
 109static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev,
 110                struct tps65910 *tps65910, int chip_ngpio)
 111{
 112        return NULL;
 113}
 114#endif
 115
 116static int tps65910_gpio_probe(struct platform_device *pdev)
 117{
 118        struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
 119        struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
 120        struct tps65910_gpio *tps65910_gpio;
 121        int ret;
 122        int i;
 123
 124        tps65910_gpio = devm_kzalloc(&pdev->dev,
 125                                sizeof(*tps65910_gpio), GFP_KERNEL);
 126        if (!tps65910_gpio) {
 127                dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n");
 128                return -ENOMEM;
 129        }
 130
 131        tps65910_gpio->tps65910 = tps65910;
 132
 133        tps65910_gpio->gpio_chip.owner = THIS_MODULE;
 134        tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name;
 135
 136        switch (tps65910_chip_id(tps65910)) {
 137        case TPS65910:
 138                tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO;
 139                break;
 140        case TPS65911:
 141                tps65910_gpio->gpio_chip.ngpio = TPS65911_NUM_GPIO;
 142                break;
 143        default:
 144                return -EINVAL;
 145        }
 146        tps65910_gpio->gpio_chip.can_sleep = 1;
 147        tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input;
 148        tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output;
 149        tps65910_gpio->gpio_chip.set    = tps65910_gpio_set;
 150        tps65910_gpio->gpio_chip.get    = tps65910_gpio_get;
 151        tps65910_gpio->gpio_chip.dev = &pdev->dev;
 152#ifdef CONFIG_OF_GPIO
 153        tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node;
 154#endif
 155        if (pdata && pdata->gpio_base)
 156                tps65910_gpio->gpio_chip.base = pdata->gpio_base;
 157        else
 158                tps65910_gpio->gpio_chip.base = -1;
 159
 160        if (!pdata && tps65910->dev->of_node)
 161                pdata = tps65910_parse_dt_for_gpio(&pdev->dev, tps65910,
 162                        tps65910_gpio->gpio_chip.ngpio);
 163
 164        if (!pdata)
 165                goto skip_init;
 166
 167        /* Configure sleep control for gpios if provided */
 168        for (i = 0; i < tps65910_gpio->gpio_chip.ngpio; ++i) {
 169                if (!pdata->en_gpio_sleep[i])
 170                        continue;
 171
 172                ret = tps65910_reg_set_bits(tps65910,
 173                        TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
 174                if (ret < 0)
 175                        dev_warn(tps65910->dev,
 176                                "GPIO Sleep setting failed with err %d\n", ret);
 177        }
 178
 179skip_init:
 180        ret = gpiochip_add(&tps65910_gpio->gpio_chip);
 181        if (ret < 0) {
 182                dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 183                return ret;
 184        }
 185
 186        platform_set_drvdata(pdev, tps65910_gpio);
 187
 188        return ret;
 189}
 190
 191static int tps65910_gpio_remove(struct platform_device *pdev)
 192{
 193        struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev);
 194
 195        return gpiochip_remove(&tps65910_gpio->gpio_chip);
 196}
 197
 198static struct platform_driver tps65910_gpio_driver = {
 199        .driver.name    = "tps65910-gpio",
 200        .driver.owner   = THIS_MODULE,
 201        .probe          = tps65910_gpio_probe,
 202        .remove         = tps65910_gpio_remove,
 203};
 204
 205static int __init tps65910_gpio_init(void)
 206{
 207        return platform_driver_register(&tps65910_gpio_driver);
 208}
 209subsys_initcall(tps65910_gpio_init);
 210
 211static void __exit tps65910_gpio_exit(void)
 212{
 213        platform_driver_unregister(&tps65910_gpio_driver);
 214}
 215module_exit(tps65910_gpio_exit);
 216
 217MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
 218MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>");
 219MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs");
 220MODULE_LICENSE("GPL v2");
 221MODULE_ALIAS("platform:tps65910-gpio");
 222
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.