]> Git Repo - J-u-boot.git/blob - drivers/gpio/qcom_pmic_gpio.c
Merge patch series "drivers: ata: Remove duplicate newlines"
[J-u-boot.git] / drivers / gpio / qcom_pmic_gpio.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Qualcomm generic pmic gpio driver
4  *
5  * (C) Copyright 2015 Mateusz Kulikowski <[email protected]>
6  */
7
8 #include <dm.h>
9 #include <dm/device-internal.h>
10 #include <dm/lists.h>
11 #include <dm/pinctrl.h>
12 #include <log.h>
13 #include <power/pmic.h>
14 #include <spmi/spmi.h>
15 #include <asm/io.h>
16 #include <stdlib.h>
17 #include <asm/gpio.h>
18 #include <linux/bitops.h>
19
20 /* Register offset for each gpio */
21 #define REG_OFFSET(x)          ((x) * 0x100)
22
23 /* Register maps */
24
25 /* Type and subtype are shared for all PMIC peripherals */
26 #define REG_TYPE               0x4
27 #define REG_SUBTYPE            0x5
28
29 /* GPIO peripheral type and subtype out_values */
30 #define REG_TYPE_VAL            0x10
31 #define REG_SUBTYPE_GPIO_4CH    0x1
32 #define REG_SUBTYPE_GPIOC_4CH   0x5
33 #define REG_SUBTYPE_GPIO_8CH    0x9
34 #define REG_SUBTYPE_GPIOC_8CH   0xd
35 #define REG_SUBTYPE_GPIO_LV     0x10
36 #define REG_SUBTYPE_GPIO_MV     0x11
37 #define REG_SUBTYPE_GPIO_LV_VIN2          0x12
38 #define REG_SUBTYPE_GPIO_MV_VIN3          0x13
39
40 #define REG_STATUS             0x08
41 #define REG_STATUS_VAL_MASK    0x1
42
43 /* MODE_CTL */
44 #define REG_CTL         0x40
45 #define REG_CTL_MODE_MASK       0x70
46 #define REG_CTL_MODE_INPUT      0x00
47 #define REG_CTL_MODE_INOUT      0x20
48 #define REG_CTL_MODE_OUTPUT     0x10
49 #define REG_CTL_OUTPUT_MASK     0x0F
50 #define REG_CTL_LV_MV_MODE_MASK         0x3
51 #define REG_CTL_LV_MV_MODE_INPUT        0x0
52 #define REG_CTL_LV_MV_MODE_INOUT        0x2
53 #define REG_CTL_LV_MV_MODE_OUTPUT       0x1
54
55 #define REG_DIG_VIN_CTL        0x41
56 #define REG_DIG_VIN_VIN0       0
57
58 #define REG_DIG_PULL_CTL       0x42
59 #define REG_DIG_PULL_NO_PU     0x5
60
61 #define REG_LV_MV_OUTPUT_CTL    0x44
62 #define REG_LV_MV_OUTPUT_CTL_MASK       0x80
63 #define REG_LV_MV_OUTPUT_CTL_SHIFT      7
64
65 #define REG_DIG_OUT_CTL        0x45
66 #define REG_DIG_OUT_CTL_CMOS   (0x0 << 4)
67 #define REG_DIG_OUT_CTL_DRIVE_L 0x1
68
69 #define REG_EN_CTL             0x46
70 #define REG_EN_CTL_ENABLE      (1 << 7)
71
72 /**
73  * pmic_gpio_match_data - platform specific configuration
74  *
75  * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them.
76  * This is a workaround for an unknown bug on some platforms where trying to write the
77  * GPIO configuration registers causes the board to hang.
78  */
79 enum pmic_gpio_quirks {
80         QCOM_PMIC_QUIRK_READONLY = (1 << 0),
81 };
82
83 struct qcom_pmic_gpio_data {
84         uint32_t pid; /* Peripheral ID on SPMI bus */
85         bool     lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */
86         u32 pin_count;
87         struct udevice *pmic; /* Reference to pmic device for read/write */
88 };
89
90 /* dev can be the GPIO or pinctrl device */
91 static int _qcom_gpio_set_direction(struct udevice *dev, u32 offset, bool input, int value)
92 {
93         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
94         u32 gpio_base = plat->pid + REG_OFFSET(offset);
95         u32 reg_ctl_val;
96         int ret = 0;
97
98         /* Select the mode and output */
99         if (plat->lv_mv_type) {
100                 if (input)
101                         reg_ctl_val = REG_CTL_LV_MV_MODE_INPUT;
102                 else
103                         reg_ctl_val = REG_CTL_LV_MV_MODE_INOUT;
104         } else {
105                 if (input)
106                         reg_ctl_val = REG_CTL_MODE_INPUT;
107                 else
108                         reg_ctl_val = REG_CTL_MODE_INOUT | !!value;
109         }
110
111         ret = pmic_reg_write(plat->pmic, gpio_base + REG_CTL, reg_ctl_val);
112         if (ret < 0)
113                 return ret;
114
115         if (plat->lv_mv_type && !input) {
116                 ret = pmic_reg_write(plat->pmic,
117                                      gpio_base + REG_LV_MV_OUTPUT_CTL,
118                                      !!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
119                 if (ret < 0)
120                         return ret;
121         }
122
123         return 0;
124 }
125
126 static int qcom_gpio_set_direction(struct udevice *dev, unsigned int offset,
127                                    bool input, int value)
128 {
129         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
130         uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
131         ulong quirks = dev_get_driver_data(dev);
132         int ret = 0;
133
134         /* Some PMICs don't like their GPIOs being configured */
135         if (quirks & QCOM_PMIC_QUIRK_READONLY)
136                 return 0;
137
138         /* Disable the GPIO */
139         ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
140                               REG_EN_CTL_ENABLE, 0);
141         if (ret < 0)
142                 return ret;
143
144         _qcom_gpio_set_direction(dev, offset, input, value);
145
146         /* Set the right pull (no pull) */
147         ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_PULL_CTL,
148                              REG_DIG_PULL_NO_PU);
149         if (ret < 0)
150                 return ret;
151
152         /* Configure output pin drivers if needed */
153         if (!input) {
154                 /* Select the VIN - VIN0, pin is input so it doesn't matter */
155                 ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_VIN_CTL,
156                                      REG_DIG_VIN_VIN0);
157                 if (ret < 0)
158                         return ret;
159
160                 /* Set the right dig out control */
161                 ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_OUT_CTL,
162                                      REG_DIG_OUT_CTL_CMOS |
163                                      REG_DIG_OUT_CTL_DRIVE_L);
164                 if (ret < 0)
165                         return ret;
166         }
167
168         /* Enable the GPIO */
169         return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
170                                REG_EN_CTL_ENABLE);
171 }
172
173 static int qcom_gpio_direction_input(struct udevice *dev, unsigned offset)
174 {
175         return qcom_gpio_set_direction(dev, offset, true, 0);
176 }
177
178 static int qcom_gpio_direction_output(struct udevice *dev, unsigned offset,
179                                       int value)
180 {
181         return qcom_gpio_set_direction(dev, offset, false, value);
182 }
183
184 static int qcom_gpio_get_function(struct udevice *dev, unsigned offset)
185 {
186         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
187         uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
188         int reg;
189
190         reg = pmic_reg_read(plat->pmic, gpio_base + REG_CTL);
191         if (reg < 0)
192                 return reg;
193
194         if (plat->lv_mv_type) {
195                 switch (reg & REG_CTL_LV_MV_MODE_MASK) {
196                 case REG_CTL_LV_MV_MODE_INPUT:
197                         return GPIOF_INPUT;
198                 case REG_CTL_LV_MV_MODE_INOUT: /* Fallthrough */
199                 case REG_CTL_LV_MV_MODE_OUTPUT:
200                         return GPIOF_OUTPUT;
201                 default:
202                         return GPIOF_UNKNOWN;
203                 }
204         } else {
205                 switch (reg & REG_CTL_MODE_MASK) {
206                 case REG_CTL_MODE_INPUT:
207                         return GPIOF_INPUT;
208                 case REG_CTL_MODE_INOUT: /* Fallthrough */
209                 case REG_CTL_MODE_OUTPUT:
210                         return GPIOF_OUTPUT;
211                 default:
212                         return GPIOF_UNKNOWN;
213                 }
214         }
215 }
216
217 static int qcom_gpio_get_value(struct udevice *dev, unsigned offset)
218 {
219         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
220         uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
221         int reg;
222
223         reg = pmic_reg_read(plat->pmic, gpio_base + REG_STATUS);
224         if (reg < 0)
225                 return reg;
226
227         return !!(reg & REG_STATUS_VAL_MASK);
228 }
229
230 static int qcom_gpio_set_value(struct udevice *dev, unsigned offset,
231                                int value)
232 {
233         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
234         uint32_t gpio_base = plat->pid + REG_OFFSET(offset);
235
236         /* Set the output value of the gpio */
237         if (plat->lv_mv_type)
238                 return pmic_clrsetbits(dev->parent,
239                                        gpio_base + REG_LV_MV_OUTPUT_CTL,
240                                        REG_LV_MV_OUTPUT_CTL_MASK,
241                                        !!value << REG_LV_MV_OUTPUT_CTL_SHIFT);
242         else
243                 return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
244                                        REG_CTL_OUTPUT_MASK, !!value);
245 }
246
247 static int qcom_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
248                            struct ofnode_phandle_args *args)
249 {
250         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
251
252         if (args->args_count < 1)
253                 return -EINVAL;
254
255         /* GPIOs in DT are 1-based */
256         desc->offset = args->args[0] - 1;
257         if (desc->offset >= uc_priv->gpio_count)
258                 return -EINVAL;
259
260         if (args->args_count < 2)
261                 return 0;
262
263         desc->flags = gpio_flags_xlate(args->args[1]);
264
265         return 0;
266 }
267
268 static const struct dm_gpio_ops qcom_gpio_ops = {
269         .direction_input        = qcom_gpio_direction_input,
270         .direction_output       = qcom_gpio_direction_output,
271         .get_value              = qcom_gpio_get_value,
272         .set_value              = qcom_gpio_set_value,
273         .get_function           = qcom_gpio_get_function,
274         .xlate                  = qcom_gpio_xlate,
275 };
276
277 static int qcom_gpio_bind(struct udevice *dev)
278 {
279
280         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
281         ulong quirks = dev_get_driver_data(dev);
282         struct udevice *child;
283         struct driver *drv;
284         int ret;
285
286         drv = lists_driver_lookup_name("qcom_pmic_pinctrl");
287         if (!drv) {
288                 log_warning("Cannot find driver '%s'\n", "qcom_pmic_pinctrl");
289                 return -ENOENT;
290         }
291
292         /* Bind the GPIO driver as a child of the PMIC. */
293         ret = device_bind_with_driver_data(dev, drv,
294                                            dev->name,
295                                            quirks, dev_ofnode(dev), &child);
296         if (ret)
297                 return log_msg_ret("bind", ret);
298
299         dev_set_plat(child, plat);
300
301         return 0;
302 }
303
304 static int qcom_gpio_probe(struct udevice *dev)
305 {
306         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
307         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
308         struct ofnode_phandle_args args;
309         int val, ret;
310         u64 pid;
311
312         plat->pmic = dev->parent;
313
314         pid = dev_read_addr(dev);
315         if (pid == FDT_ADDR_T_NONE)
316                 return log_msg_ret("bad address", -EINVAL);
317
318         plat->pid = pid;
319
320         /* Do a sanity check */
321         val = pmic_reg_read(plat->pmic, plat->pid + REG_TYPE);
322         if (val != REG_TYPE_VAL)
323                 return log_msg_ret("bad type", -ENXIO);
324
325         val = pmic_reg_read(plat->pmic, plat->pid + REG_SUBTYPE);
326         switch (val) {
327         case REG_SUBTYPE_GPIO_4CH:
328         case REG_SUBTYPE_GPIOC_4CH:
329                 plat->lv_mv_type = false;
330                 break;
331         case REG_SUBTYPE_GPIO_LV:
332         case REG_SUBTYPE_GPIO_MV:
333         case REG_SUBTYPE_GPIO_LV_VIN2:
334         case REG_SUBTYPE_GPIO_MV_VIN3:
335                 plat->lv_mv_type = true;
336                 break;
337         default:
338                 return log_msg_ret("bad subtype", -ENXIO);
339         }
340
341         plat->lv_mv_type = val == REG_SUBTYPE_GPIO_LV ||
342                            val == REG_SUBTYPE_GPIO_MV;
343
344         /*
345          * Parse basic GPIO count specified via the gpio-ranges property
346          * as specified in upstream devicetrees
347          */
348         ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges",
349                                              NULL, 3, 0, &args);
350         if (ret)
351                 return log_msg_ret("gpio-ranges", ret);
352
353         plat->pin_count = args.args[2];
354
355         uc_priv->gpio_count = plat->pin_count;
356         uc_priv->bank_name = "pmic";
357
358         return 0;
359 }
360
361 static const struct udevice_id qcom_gpio_ids[] = {
362         { .compatible = "qcom,pm8916-gpio" },
363         { .compatible = "qcom,pm8994-gpio" },   /* 22 GPIO's */
364         { .compatible = "qcom,pm8998-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
365         { .compatible = "qcom,pms405-gpio" },
366         { .compatible = "qcom,pm6125-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
367         { .compatible = "qcom,pm8150-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
368         { .compatible = "qcom,pm8550-gpio", .data = QCOM_PMIC_QUIRK_READONLY },
369         { }
370 };
371
372 U_BOOT_DRIVER(qcom_pmic_gpio) = {
373         .name   = "qcom_pmic_gpio",
374         .id     = UCLASS_GPIO,
375         .of_match = qcom_gpio_ids,
376         .bind   = qcom_gpio_bind,
377         .probe = qcom_gpio_probe,
378         .ops    = &qcom_gpio_ops,
379         .plat_auto = sizeof(struct qcom_pmic_gpio_data),
380         .flags = DM_FLAG_ALLOC_PDATA,
381 };
382
383 static const struct pinconf_param qcom_pmic_pinctrl_conf_params[] = {
384         { "output-high", PIN_CONFIG_OUTPUT_ENABLE, 1 },
385         { "output-low", PIN_CONFIG_OUTPUT, 0 },
386 };
387
388 static int qcom_pmic_pinctrl_get_pins_count(struct udevice *dev)
389 {
390         struct qcom_pmic_gpio_data *plat = dev_get_plat(dev);
391
392         return plat->pin_count;
393 }
394
395 static const char *qcom_pmic_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector)
396 {
397         static char name[8];
398
399         /* DT indexes from 1 */
400         snprintf(name, sizeof(name), "gpio%u", selector + 1);
401
402         return name;
403 }
404
405 static int qcom_pmic_pinctrl_pinconf_set(struct udevice *dev, unsigned int selector,
406                                          unsigned int param, unsigned int arg)
407 {
408         /* We only support configuring the pin as an output, either low or high */
409         return _qcom_gpio_set_direction(dev, selector, false,
410                                         param == PIN_CONFIG_OUTPUT_ENABLE);
411 }
412
413 static const char *qcom_pmic_pinctrl_get_function_name(struct udevice *dev, unsigned int selector)
414 {
415         if (!selector)
416                 return "normal";
417         return NULL;
418 }
419
420 static int qcom_pmic_pinctrl_generic_get_functions_count(struct udevice *dev)
421 {
422         return 1;
423 }
424
425 static int qcom_pmic_pinctrl_generic_pinmux_set_mux(struct udevice *dev, unsigned int selector,
426                                                     unsigned int func_selector)
427 {
428         return 0;
429 }
430
431 struct pinctrl_ops qcom_pmic_pinctrl_ops = {
432         .get_pins_count = qcom_pmic_pinctrl_get_pins_count,
433         .get_pin_name = qcom_pmic_pinctrl_get_pin_name,
434         .set_state = pinctrl_generic_set_state,
435         .pinconf_num_params = ARRAY_SIZE(qcom_pmic_pinctrl_conf_params),
436         .pinconf_params = qcom_pmic_pinctrl_conf_params,
437         .pinconf_set = qcom_pmic_pinctrl_pinconf_set,
438         .get_function_name = qcom_pmic_pinctrl_get_function_name,
439         .get_functions_count = qcom_pmic_pinctrl_generic_get_functions_count,
440         .pinmux_set = qcom_pmic_pinctrl_generic_pinmux_set_mux,
441 };
442
443 U_BOOT_DRIVER(qcom_pmic_pinctrl) = {
444         .name   = "qcom_pmic_pinctrl",
445         .id     = UCLASS_PINCTRL,
446         .ops    = &qcom_pmic_pinctrl_ops,
447 };
This page took 0.05376 seconds and 4 git commands to generate.