Commit | Line | Data |
---|---|---|
72bd9860 LD |
1 | /* |
2 | * TI TPS6586x GPIO driver | |
3 | * | |
4 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | |
5 | * Author: Laxman dewangan <ldewangan@nvidia.com> | |
6 | * | |
7 | * Based on tps6586x.c | |
8 | * Copyright (c) 2010 CompuLab Ltd. | |
9 | * Mike Rapoport <mike@compulab.co.il> | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify it | |
12 | * under the terms and conditions of the GNU General Public License, | |
13 | * version 2, as published by the Free Software Foundation. | |
14 | * | |
15 | * This program is distributed in the hope it will be useful, but WITHOUT | |
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
18 | * more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
22 | */ | |
23 | ||
24 | #include <linux/errno.h> | |
25 | #include <linux/gpio.h> | |
26 | #include <linux/kernel.h> | |
27 | #include <linux/module.h> | |
28 | #include <linux/mfd/tps6586x.h> | |
29 | #include <linux/of_device.h> | |
30 | #include <linux/platform_device.h> | |
31 | ||
32 | /* GPIO control registers */ | |
33 | #define TPS6586X_GPIOSET1 0x5d | |
34 | #define TPS6586X_GPIOSET2 0x5e | |
35 | ||
36 | struct tps6586x_gpio { | |
37 | struct gpio_chip gpio_chip; | |
38 | struct device *parent; | |
39 | }; | |
40 | ||
41 | static inline struct tps6586x_gpio *to_tps6586x_gpio(struct gpio_chip *chip) | |
42 | { | |
43 | return container_of(chip, struct tps6586x_gpio, gpio_chip); | |
44 | } | |
45 | ||
46 | static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset) | |
47 | { | |
48 | struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); | |
49 | uint8_t val; | |
50 | int ret; | |
51 | ||
52 | ret = tps6586x_read(tps6586x_gpio->parent, TPS6586X_GPIOSET2, &val); | |
53 | if (ret) | |
54 | return ret; | |
55 | ||
56 | return !!(val & (1 << offset)); | |
57 | } | |
58 | ||
59 | static void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset, | |
60 | int value) | |
61 | { | |
62 | struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); | |
63 | ||
64 | tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET2, | |
65 | value << offset, 1 << offset); | |
66 | } | |
67 | ||
68 | static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, | |
69 | int value) | |
70 | { | |
71 | struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); | |
72 | uint8_t val, mask; | |
73 | ||
74 | tps6586x_gpio_set(gc, offset, value); | |
75 | ||
76 | val = 0x1 << (offset * 2); | |
77 | mask = 0x3 << (offset * 2); | |
78 | ||
79 | return tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET1, | |
80 | val, mask); | |
81 | } | |
82 | ||
fe39f2f4 LD |
83 | static int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) |
84 | { | |
85 | struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); | |
86 | ||
87 | return tps6586x_irq_get_virq(tps6586x_gpio->parent, | |
88 | TPS6586X_INT_PLDO_0 + offset); | |
89 | } | |
90 | ||
3836309d | 91 | static int tps6586x_gpio_probe(struct platform_device *pdev) |
72bd9860 LD |
92 | { |
93 | struct tps6586x_platform_data *pdata; | |
94 | struct tps6586x_gpio *tps6586x_gpio; | |
95 | int ret; | |
96 | ||
97 | pdata = dev_get_platdata(pdev->dev.parent); | |
98 | tps6586x_gpio = devm_kzalloc(&pdev->dev, | |
99 | sizeof(*tps6586x_gpio), GFP_KERNEL); | |
100 | if (!tps6586x_gpio) { | |
101 | dev_err(&pdev->dev, "Could not allocate tps6586x_gpio\n"); | |
102 | return -ENOMEM; | |
103 | } | |
104 | ||
105 | tps6586x_gpio->parent = pdev->dev.parent; | |
106 | ||
107 | tps6586x_gpio->gpio_chip.owner = THIS_MODULE; | |
108 | tps6586x_gpio->gpio_chip.label = pdev->name; | |
109 | tps6586x_gpio->gpio_chip.dev = &pdev->dev; | |
110 | tps6586x_gpio->gpio_chip.ngpio = 4; | |
111 | tps6586x_gpio->gpio_chip.can_sleep = 1; | |
112 | ||
113 | /* FIXME: add handling of GPIOs as dedicated inputs */ | |
114 | tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; | |
115 | tps6586x_gpio->gpio_chip.set = tps6586x_gpio_set; | |
116 | tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get; | |
fe39f2f4 | 117 | tps6586x_gpio->gpio_chip.to_irq = tps6586x_gpio_to_irq; |
72bd9860 LD |
118 | |
119 | #ifdef CONFIG_OF_GPIO | |
120 | tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node; | |
121 | #endif | |
122 | if (pdata && pdata->gpio_base) | |
123 | tps6586x_gpio->gpio_chip.base = pdata->gpio_base; | |
124 | else | |
125 | tps6586x_gpio->gpio_chip.base = -1; | |
126 | ||
127 | ret = gpiochip_add(&tps6586x_gpio->gpio_chip); | |
128 | if (ret < 0) { | |
129 | dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); | |
130 | return ret; | |
131 | } | |
132 | ||
133 | platform_set_drvdata(pdev, tps6586x_gpio); | |
134 | ||
135 | return ret; | |
136 | } | |
137 | ||
206210ce | 138 | static int tps6586x_gpio_remove(struct platform_device *pdev) |
72bd9860 LD |
139 | { |
140 | struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev); | |
141 | ||
142 | return gpiochip_remove(&tps6586x_gpio->gpio_chip); | |
143 | } | |
144 | ||
145 | static struct platform_driver tps6586x_gpio_driver = { | |
146 | .driver.name = "tps6586x-gpio", | |
147 | .driver.owner = THIS_MODULE, | |
148 | .probe = tps6586x_gpio_probe, | |
8283c4ff | 149 | .remove = tps6586x_gpio_remove, |
72bd9860 LD |
150 | }; |
151 | ||
152 | static int __init tps6586x_gpio_init(void) | |
153 | { | |
154 | return platform_driver_register(&tps6586x_gpio_driver); | |
155 | } | |
156 | subsys_initcall(tps6586x_gpio_init); | |
157 | ||
158 | static void __exit tps6586x_gpio_exit(void) | |
159 | { | |
160 | platform_driver_unregister(&tps6586x_gpio_driver); | |
161 | } | |
162 | module_exit(tps6586x_gpio_exit); | |
163 | ||
164 | MODULE_ALIAS("platform:tps6586x-gpio"); | |
165 | MODULE_DESCRIPTION("GPIO interface for TPS6586X PMIC"); | |
166 | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | |
167 | MODULE_LICENSE("GPL"); |