diff options
author | Keerthy <j-keerthy@ti.com> | 2016-08-31 04:58:11 -0400 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2016-08-31 08:20:37 -0400 |
commit | 83f141030cec8861969121582f13ab2caff5c4ba (patch) | |
tree | 3d83c58ba442fccc360967b6b672cf7658a5460d /drivers/gpio | |
parent | dc21c7ad3a8aad79cb14128c321833a47dc921c2 (diff) |
gpio: lp873x: Add support for General Purpose Outputs
Add driver for lp873x PMIC family GPOs. Two GPOs are supported
and can be configured in Open-drain output or Push-pull output.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 10 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-lp873x.c | 193 |
3 files changed, 204 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 98dd47a30fc7..346e9a9b4397 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -874,6 +874,16 @@ config GPIO_LP3943 | |||
874 | LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. | 874 | LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. |
875 | Open drain outputs are required for this usage. | 875 | Open drain outputs are required for this usage. |
876 | 876 | ||
877 | config GPIO_LP873X | ||
878 | tristate "TI LP873X GPO" | ||
879 | depends on MFD_TI_LP873X | ||
880 | help | ||
881 | This driver supports the GPO on TI Lp873x PMICs. 2 GPOs are present | ||
882 | on LP873X PMICs. | ||
883 | |||
884 | This driver can also be built as a module. If so, the module will be | ||
885 | called gpio-lp873x. | ||
886 | |||
877 | config GPIO_MAX77620 | 887 | config GPIO_MAX77620 |
878 | tristate "GPIO support for PMIC MAX77620 and MAX20024" | 888 | tristate "GPIO support for PMIC MAX77620 and MAX20024" |
879 | depends on MFD_MAX77620 | 889 | depends on MFD_MAX77620 |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 2a035ed8f168..d60432f2a126 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -56,6 +56,7 @@ obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o | |||
56 | obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o | 56 | obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o |
57 | obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o | 57 | obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o |
58 | obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o | 58 | obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o |
59 | obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o | ||
59 | obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o | 60 | obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o |
60 | obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o | 61 | obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o |
61 | obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o | 62 | obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o |
diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c new file mode 100644 index 000000000000..f10d49da1554 --- /dev/null +++ b/drivers/gpio/gpio-lp873x.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * Keerthy <j-keerthy@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
10 | * kind, whether expressed or implied; without even the implied warranty | ||
11 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License version 2 for more details. | ||
13 | * | ||
14 | * Based on the TPS65218 driver | ||
15 | */ | ||
16 | |||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/regmap.h> | ||
21 | |||
22 | #include <linux/mfd/lp873x.h> | ||
23 | |||
24 | #define BITS_PER_GPO 0x4 | ||
25 | #define LP873X_GPO_CTRL_OD 0x2 | ||
26 | |||
27 | struct lp873x_gpio { | ||
28 | struct gpio_chip chip; | ||
29 | struct lp873x *lp873; | ||
30 | }; | ||
31 | |||
32 | static int lp873x_gpio_get_direction(struct gpio_chip *chip, | ||
33 | unsigned int offset) | ||
34 | { | ||
35 | /* This device is output only */ | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int lp873x_gpio_direction_input(struct gpio_chip *chip, | ||
40 | unsigned int offset) | ||
41 | { | ||
42 | /* This device is output only */ | ||
43 | return -EINVAL; | ||
44 | } | ||
45 | |||
46 | static int lp873x_gpio_direction_output(struct gpio_chip *chip, | ||
47 | unsigned int offset, int value) | ||
48 | { | ||
49 | struct lp873x_gpio *gpio = gpiochip_get_data(chip); | ||
50 | |||
51 | /* Set the initial value */ | ||
52 | return regmap_update_bits(gpio->lp873->regmap, LP873X_REG_GPO_CTRL, | ||
53 | BIT(offset * BITS_PER_GPO), | ||
54 | value ? BIT(offset * BITS_PER_GPO) : 0); | ||
55 | } | ||
56 | |||
57 | static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset) | ||
58 | { | ||
59 | struct lp873x_gpio *gpio = gpiochip_get_data(chip); | ||
60 | int ret, val; | ||
61 | |||
62 | ret = regmap_read(gpio->lp873->regmap, LP873X_REG_GPO_CTRL, &val); | ||
63 | if (ret < 0) | ||
64 | return ret; | ||
65 | |||
66 | return val & BIT(offset * BITS_PER_GPO); | ||
67 | } | ||
68 | |||
69 | static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset, | ||
70 | int value) | ||
71 | { | ||
72 | struct lp873x_gpio *gpio = gpiochip_get_data(chip); | ||
73 | |||
74 | regmap_update_bits(gpio->lp873->regmap, LP873X_REG_GPO_CTRL, | ||
75 | BIT(offset * BITS_PER_GPO), | ||
76 | value ? BIT(offset * BITS_PER_GPO) : 0); | ||
77 | } | ||
78 | |||
79 | static int lp873x_gpio_request(struct gpio_chip *gc, unsigned int offset) | ||
80 | { | ||
81 | struct lp873x_gpio *gpio = gpiochip_get_data(gc); | ||
82 | int ret; | ||
83 | |||
84 | switch (offset) { | ||
85 | case 0: | ||
86 | /* No MUX Set up Needed for GPO */ | ||
87 | break; | ||
88 | case 1: | ||
89 | /* Setup the CLKIN_PIN_SEL MUX to GPO2 */ | ||
90 | ret = regmap_update_bits(gpio->lp873->regmap, LP873X_REG_CONFIG, | ||
91 | LP873X_CONFIG_CLKIN_PIN_SEL, 0); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | break; | ||
96 | default: | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int lp873x_gpio_set_single_ended(struct gpio_chip *gc, | ||
104 | unsigned int offset, | ||
105 | enum single_ended_mode mode) | ||
106 | { | ||
107 | struct lp873x_gpio *gpio = gpiochip_get_data(gc); | ||
108 | |||
109 | switch (mode) { | ||
110 | case LINE_MODE_OPEN_DRAIN: | ||
111 | return regmap_update_bits(gpio->lp873->regmap, | ||
112 | LP873X_REG_GPO_CTRL, | ||
113 | BIT(offset * BITS_PER_GPO + | ||
114 | LP873X_GPO_CTRL_OD), | ||
115 | BIT(offset * BITS_PER_GPO + | ||
116 | LP873X_GPO_CTRL_OD)); | ||
117 | case LINE_MODE_PUSH_PULL: | ||
118 | return regmap_update_bits(gpio->lp873->regmap, | ||
119 | LP873X_REG_GPO_CTRL, | ||
120 | BIT(offset * BITS_PER_GPO + | ||
121 | LP873X_GPO_CTRL_OD), 0); | ||
122 | default: | ||
123 | return -ENOTSUPP; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static struct gpio_chip template_chip = { | ||
128 | .label = "lp873x-gpio", | ||
129 | .owner = THIS_MODULE, | ||
130 | .request = lp873x_gpio_request, | ||
131 | .get_direction = lp873x_gpio_get_direction, | ||
132 | .direction_input = lp873x_gpio_direction_input, | ||
133 | .direction_output = lp873x_gpio_direction_output, | ||
134 | .get = lp873x_gpio_get, | ||
135 | .set = lp873x_gpio_set, | ||
136 | .set_single_ended = lp873x_gpio_set_single_ended, | ||
137 | .base = -1, | ||
138 | .ngpio = 2, | ||
139 | .can_sleep = true, | ||
140 | }; | ||
141 | |||
142 | static int lp873x_gpio_probe(struct platform_device *pdev) | ||
143 | { | ||
144 | struct lp873x_gpio *gpio; | ||
145 | int ret; | ||
146 | |||
147 | gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); | ||
148 | if (!gpio) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | platform_set_drvdata(pdev, gpio); | ||
152 | |||
153 | gpio->lp873 = dev_get_drvdata(pdev->dev.parent); | ||
154 | gpio->chip = template_chip; | ||
155 | gpio->chip.parent = gpio->lp873->dev; | ||
156 | |||
157 | ret = gpiochip_add_data(&gpio->chip, gpio); | ||
158 | if (ret < 0) { | ||
159 | dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int lp873x_gpio_remove(struct platform_device *pdev) | ||
167 | { | ||
168 | struct lp873x_gpio *gpio = platform_get_drvdata(pdev); | ||
169 | |||
170 | gpiochip_remove(&gpio->chip); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static const struct platform_device_id lp873x_gpio_id_table[] = { | ||
176 | { "lp873x-gpio", }, | ||
177 | { /* sentinel */ } | ||
178 | }; | ||
179 | MODULE_DEVICE_TABLE(platform, lp873x_gpio_id_table); | ||
180 | |||
181 | static struct platform_driver lp873x_gpio_driver = { | ||
182 | .driver = { | ||
183 | .name = "lp873x-gpio", | ||
184 | }, | ||
185 | .probe = lp873x_gpio_probe, | ||
186 | .remove = lp873x_gpio_remove, | ||
187 | .id_table = lp873x_gpio_id_table, | ||
188 | }; | ||
189 | module_platform_driver(lp873x_gpio_driver); | ||
190 | |||
191 | MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>"); | ||
192 | MODULE_DESCRIPTION("LP873X GPIO driver"); | ||
193 | MODULE_LICENSE("GPL v2"); | ||