Merge tag 'net-5.15-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[platform/kernel/linux-rpi.git] / drivers / gpio / gpio-da9052.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * GPIO Driver for Dialog DA9052 PMICs.
4  *
5  * Copyright(c) 2011 Dialog Semiconductor Ltd.
6  *
7  * Author: David Dajun Chen <dchen@diasemi.com>
8  */
9 #include <linux/module.h>
10 #include <linux/fs.h>
11 #include <linux/uaccess.h>
12 #include <linux/platform_device.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/syscalls.h>
15 #include <linux/seq_file.h>
16
17 #include <linux/mfd/da9052/da9052.h>
18 #include <linux/mfd/da9052/reg.h>
19 #include <linux/mfd/da9052/pdata.h>
20
21 #define DA9052_INPUT                            1
22 #define DA9052_OUTPUT_OPENDRAIN         2
23 #define DA9052_OUTPUT_PUSHPULL                  3
24
25 #define DA9052_SUPPLY_VDD_IO1                   0
26
27 #define DA9052_DEBOUNCING_OFF                   0
28 #define DA9052_DEBOUNCING_ON                    1
29
30 #define DA9052_OUTPUT_LOWLEVEL                  0
31
32 #define DA9052_ACTIVE_LOW                       0
33 #define DA9052_ACTIVE_HIGH                      1
34
35 #define DA9052_GPIO_MAX_PORTS_PER_REGISTER      8
36 #define DA9052_GPIO_SHIFT_COUNT(no)             (no%8)
37 #define DA9052_GPIO_MASK_UPPER_NIBBLE           0xF0
38 #define DA9052_GPIO_MASK_LOWER_NIBBLE           0x0F
39 #define DA9052_GPIO_NIBBLE_SHIFT                4
40 #define DA9052_IRQ_GPI0                 16
41 #define DA9052_GPIO_ODD_SHIFT                   7
42 #define DA9052_GPIO_EVEN_SHIFT                  3
43
44 struct da9052_gpio {
45         struct da9052 *da9052;
46         struct gpio_chip gp;
47 };
48
49 static unsigned char da9052_gpio_port_odd(unsigned offset)
50 {
51         return offset % 2;
52 }
53
54 static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset)
55 {
56         struct da9052_gpio *gpio = gpiochip_get_data(gc);
57         int da9052_port_direction = 0;
58         int ret;
59
60         ret = da9052_reg_read(gpio->da9052,
61                               DA9052_GPIO_0_1_REG + (offset >> 1));
62         if (ret < 0)
63                 return ret;
64
65         if (da9052_gpio_port_odd(offset)) {
66                 da9052_port_direction = ret & DA9052_GPIO_ODD_PORT_PIN;
67                 da9052_port_direction >>= 4;
68         } else {
69                 da9052_port_direction = ret & DA9052_GPIO_EVEN_PORT_PIN;
70         }
71
72         switch (da9052_port_direction) {
73         case DA9052_INPUT:
74                 if (offset < DA9052_GPIO_MAX_PORTS_PER_REGISTER)
75                         ret = da9052_reg_read(gpio->da9052,
76                                               DA9052_STATUS_C_REG);
77                 else
78                         ret = da9052_reg_read(gpio->da9052,
79                                               DA9052_STATUS_D_REG);
80                 if (ret < 0)
81                         return ret;
82                 return !!(ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset)));
83         case DA9052_OUTPUT_PUSHPULL:
84                 if (da9052_gpio_port_odd(offset))
85                         return !!(ret & DA9052_GPIO_ODD_PORT_MODE);
86                 else
87                         return !!(ret & DA9052_GPIO_EVEN_PORT_MODE);
88         default:
89                 return -EINVAL;
90         }
91 }
92
93 static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
94 {
95         struct da9052_gpio *gpio = gpiochip_get_data(gc);
96         int ret;
97
98         if (da9052_gpio_port_odd(offset)) {
99                         ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
100                                                 DA9052_GPIO_0_1_REG,
101                                                 DA9052_GPIO_ODD_PORT_MODE,
102                                                 value << DA9052_GPIO_ODD_SHIFT);
103                         if (ret != 0)
104                                 dev_err(gpio->da9052->dev,
105                                         "Failed to updated gpio odd reg,%d",
106                                         ret);
107         } else {
108                         ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
109                                                 DA9052_GPIO_0_1_REG,
110                                                 DA9052_GPIO_EVEN_PORT_MODE,
111                                                 value << DA9052_GPIO_EVEN_SHIFT);
112                         if (ret != 0)
113                                 dev_err(gpio->da9052->dev,
114                                         "Failed to updated gpio even reg,%d",
115                                         ret);
116         }
117 }
118
119 static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
120 {
121         struct da9052_gpio *gpio = gpiochip_get_data(gc);
122         unsigned char register_value;
123         int ret;
124
125         /* Format: function - 2 bits type - 1 bit mode - 1 bit */
126         register_value = DA9052_INPUT | DA9052_ACTIVE_LOW << 2 |
127                          DA9052_DEBOUNCING_ON << 3;
128
129         if (da9052_gpio_port_odd(offset))
130                 ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
131                                         DA9052_GPIO_0_1_REG,
132                                         DA9052_GPIO_MASK_UPPER_NIBBLE,
133                                         (register_value <<
134                                         DA9052_GPIO_NIBBLE_SHIFT));
135         else
136                 ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
137                                         DA9052_GPIO_0_1_REG,
138                                         DA9052_GPIO_MASK_LOWER_NIBBLE,
139                                         register_value);
140
141         return ret;
142 }
143
144 static int da9052_gpio_direction_output(struct gpio_chip *gc,
145                                         unsigned offset, int value)
146 {
147         struct da9052_gpio *gpio = gpiochip_get_data(gc);
148         unsigned char register_value;
149         int ret;
150
151         /* Format: Function - 2 bits Type - 1 bit Mode - 1 bit */
152         register_value = DA9052_OUTPUT_PUSHPULL | DA9052_SUPPLY_VDD_IO1 << 2 |
153                          value << 3;
154
155         if (da9052_gpio_port_odd(offset))
156                 ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
157                                         DA9052_GPIO_0_1_REG,
158                                         DA9052_GPIO_MASK_UPPER_NIBBLE,
159                                         (register_value <<
160                                         DA9052_GPIO_NIBBLE_SHIFT));
161         else
162                 ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
163                                         DA9052_GPIO_0_1_REG,
164                                         DA9052_GPIO_MASK_LOWER_NIBBLE,
165                                         register_value);
166
167         return ret;
168 }
169
170 static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
171 {
172         struct da9052_gpio *gpio = gpiochip_get_data(gc);
173         struct da9052 *da9052 = gpio->da9052;
174
175         int irq;
176
177         irq = regmap_irq_get_virq(da9052->irq_data, DA9052_IRQ_GPI0 + offset);
178
179         return irq;
180 }
181
182 static const struct gpio_chip reference_gp = {
183         .label = "da9052-gpio",
184         .owner = THIS_MODULE,
185         .get = da9052_gpio_get,
186         .set = da9052_gpio_set,
187         .direction_input = da9052_gpio_direction_input,
188         .direction_output = da9052_gpio_direction_output,
189         .to_irq = da9052_gpio_to_irq,
190         .can_sleep = true,
191         .ngpio = 16,
192         .base = -1,
193 };
194
195 static int da9052_gpio_probe(struct platform_device *pdev)
196 {
197         struct da9052_gpio *gpio;
198         struct da9052_pdata *pdata;
199
200         gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
201         if (!gpio)
202                 return -ENOMEM;
203
204         gpio->da9052 = dev_get_drvdata(pdev->dev.parent);
205         pdata = dev_get_platdata(gpio->da9052->dev);
206
207         gpio->gp = reference_gp;
208         if (pdata && pdata->gpio_base)
209                 gpio->gp.base = pdata->gpio_base;
210
211         return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
212 }
213
214 static struct platform_driver da9052_gpio_driver = {
215         .probe = da9052_gpio_probe,
216         .driver = {
217                 .name   = "da9052-gpio",
218         },
219 };
220
221 module_platform_driver(da9052_gpio_driver);
222
223 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
224 MODULE_DESCRIPTION("DA9052 GPIO Device Driver");
225 MODULE_LICENSE("GPL");
226 MODULE_ALIAS("platform:da9052-gpio");