Commit | Line | Data |
---|---|---|
d5a4da15 | 1 | // SPDX-License-Identifier: GPL-2.0 |
668a6cc7 | 2 | /* |
ca801a22 | 3 | * GPIO driver for TI TPS65912x PMICs |
668a6cc7 | 4 | * |
ca801a22 AD |
5 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ |
6 | * Andrew F. Davis <afd@ti.com> | |
668a6cc7 | 7 | * |
ca801a22 AD |
8 | * Based on the Arizona GPIO driver and the previous TPS65912 driver by |
9 | * Margarita Olaya Cabrera <magi@slimlogic.co.uk> | |
668a6cc7 MO |
10 | */ |
11 | ||
5d75683e | 12 | #include <linux/gpio/driver.h> |
ca801a22 | 13 | #include <linux/module.h> |
668a6cc7 | 14 | #include <linux/platform_device.h> |
ca801a22 | 15 | |
668a6cc7 MO |
16 | #include <linux/mfd/tps65912.h> |
17 | ||
ca801a22 | 18 | struct tps65912_gpio { |
668a6cc7 | 19 | struct gpio_chip gpio_chip; |
ca801a22 | 20 | struct tps65912 *tps; |
668a6cc7 MO |
21 | }; |
22 | ||
ca801a22 AD |
23 | static int tps65912_gpio_get_direction(struct gpio_chip *gc, |
24 | unsigned offset) | |
668a6cc7 | 25 | { |
ca801a22 | 26 | struct tps65912_gpio *gpio = gpiochip_get_data(gc); |
668a6cc7 | 27 | |
ca801a22 | 28 | int ret, val; |
668a6cc7 | 29 | |
ca801a22 AD |
30 | ret = regmap_read(gpio->tps->regmap, TPS65912_GPIO1 + offset, &val); |
31 | if (ret) | |
32 | return ret; | |
668a6cc7 | 33 | |
ca801a22 | 34 | if (val & GPIO_CFG_MASK) |
5d75683e | 35 | return 0; |
ca801a22 | 36 | else |
5d75683e | 37 | return 1; |
668a6cc7 MO |
38 | } |
39 | ||
ca801a22 | 40 | static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset) |
668a6cc7 | 41 | { |
ca801a22 | 42 | struct tps65912_gpio *gpio = gpiochip_get_data(gc); |
668a6cc7 | 43 | |
ca801a22 AD |
44 | return regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, |
45 | GPIO_CFG_MASK, 0); | |
668a6cc7 MO |
46 | } |
47 | ||
ca801a22 AD |
48 | static int tps65912_gpio_direction_output(struct gpio_chip *gc, |
49 | unsigned offset, int value) | |
668a6cc7 | 50 | { |
ca801a22 | 51 | struct tps65912_gpio *gpio = gpiochip_get_data(gc); |
668a6cc7 MO |
52 | |
53 | /* Set the initial value */ | |
ca801a22 AD |
54 | regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, |
55 | GPIO_SET_MASK, value ? GPIO_SET_MASK : 0); | |
668a6cc7 | 56 | |
ca801a22 AD |
57 | return regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, |
58 | GPIO_CFG_MASK, GPIO_CFG_MASK); | |
668a6cc7 MO |
59 | } |
60 | ||
ca801a22 | 61 | static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset) |
668a6cc7 | 62 | { |
ca801a22 AD |
63 | struct tps65912_gpio *gpio = gpiochip_get_data(gc); |
64 | int ret, val; | |
65 | ||
66 | ret = regmap_read(gpio->tps->regmap, TPS65912_GPIO1 + offset, &val); | |
67 | if (ret) | |
68 | return ret; | |
668a6cc7 | 69 | |
ca801a22 AD |
70 | if (val & GPIO_STS_MASK) |
71 | return 1; | |
72 | ||
73 | return 0; | |
74 | } | |
75 | ||
76 | static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset, | |
77 | int value) | |
78 | { | |
79 | struct tps65912_gpio *gpio = gpiochip_get_data(gc); | |
80 | ||
81 | regmap_update_bits(gpio->tps->regmap, TPS65912_GPIO1 + offset, | |
82 | GPIO_SET_MASK, value ? GPIO_SET_MASK : 0); | |
668a6cc7 MO |
83 | } |
84 | ||
e35b5ab0 | 85 | static const struct gpio_chip template_chip = { |
ca801a22 | 86 | .label = "tps65912-gpio", |
668a6cc7 | 87 | .owner = THIS_MODULE, |
ca801a22 AD |
88 | .get_direction = tps65912_gpio_get_direction, |
89 | .direction_input = tps65912_gpio_direction_input, | |
90 | .direction_output = tps65912_gpio_direction_output, | |
668a6cc7 MO |
91 | .get = tps65912_gpio_get, |
92 | .set = tps65912_gpio_set, | |
668a6cc7 | 93 | .base = -1, |
ca801a22 AD |
94 | .ngpio = 5, |
95 | .can_sleep = true, | |
668a6cc7 MO |
96 | }; |
97 | ||
3836309d | 98 | static int tps65912_gpio_probe(struct platform_device *pdev) |
668a6cc7 | 99 | { |
ca801a22 AD |
100 | struct tps65912 *tps = dev_get_drvdata(pdev->dev.parent); |
101 | struct tps65912_gpio *gpio; | |
668a6cc7 MO |
102 | int ret; |
103 | ||
ca801a22 AD |
104 | gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); |
105 | if (!gpio) | |
668a6cc7 MO |
106 | return -ENOMEM; |
107 | ||
ca801a22 AD |
108 | gpio->tps = dev_get_drvdata(pdev->dev.parent); |
109 | gpio->gpio_chip = template_chip; | |
110 | gpio->gpio_chip.parent = tps->dev; | |
668a6cc7 | 111 | |
9d93efe3 LW |
112 | ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio_chip, |
113 | gpio); | |
668a6cc7 | 114 | if (ret < 0) { |
ca801a22 | 115 | dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); |
45e253a7 | 116 | return ret; |
668a6cc7 MO |
117 | } |
118 | ||
ca801a22 | 119 | platform_set_drvdata(pdev, gpio); |
668a6cc7 | 120 | |
ca801a22 | 121 | return 0; |
668a6cc7 MO |
122 | } |
123 | ||
ca801a22 AD |
124 | static const struct platform_device_id tps65912_gpio_id_table[] = { |
125 | { "tps65912-gpio", }, | |
126 | { /* sentinel */ } | |
127 | }; | |
128 | MODULE_DEVICE_TABLE(platform, tps65912_gpio_id_table); | |
129 | ||
668a6cc7 MO |
130 | static struct platform_driver tps65912_gpio_driver = { |
131 | .driver = { | |
132 | .name = "tps65912-gpio", | |
668a6cc7 MO |
133 | }, |
134 | .probe = tps65912_gpio_probe, | |
ca801a22 | 135 | .id_table = tps65912_gpio_id_table, |
668a6cc7 | 136 | }; |
ca801a22 | 137 | module_platform_driver(tps65912_gpio_driver); |
668a6cc7 | 138 | |
ca801a22 AD |
139 | MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); |
140 | MODULE_DESCRIPTION("TPS65912 GPIO driver"); | |
668a6cc7 | 141 | MODULE_LICENSE("GPL v2"); |