]> git.sur5r.net Git - u-boot/blob - drivers/pinctrl/exynos/pinctrl-exynos.c
spi: cadence_qspi: Fix compilation warning
[u-boot] / drivers / pinctrl / exynos / pinctrl-exynos.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Exynos pinctrl driver common code.
4  * Copyright (C) 2016 Samsung Electronics
5  * Thomas Abraham <thomas.ab@samsung.com>
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <asm/io.h>
12 #include "pinctrl-exynos.h"
13
14 DECLARE_GLOBAL_DATA_PTR;
15
16 /**
17  * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral.
18  * conf: soc specific pin configuration data array
19  * num_conf: number of configurations in the conf array.
20  * base: base address of the pin controller.
21  */
22 void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
23                 unsigned int num_conf, unsigned long base)
24 {
25         unsigned int idx, val;
26
27         for (idx = 0; idx < num_conf; idx++) {
28                 val = readl(base + conf[idx].offset);
29                 val &= ~(conf[idx].mask);
30                 val |= conf[idx].value;
31                 writel(val, base + conf[idx].offset);
32         }
33 }
34
35 /* given a pin-name, return the address of pin config registers */
36 static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
37                                                 u32 *pin)
38 {
39         struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
40         const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl;
41         const struct samsung_pin_bank_data *bank_data = pin_ctrl->pin_banks;
42         u32 nr_banks = pin_ctrl->nr_banks, idx = 0;
43         char bank[10];
44
45         /*
46          * The format of the pin name is <bank name>-<pin_number>.
47          * Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number.
48          */
49         while (pin_name[idx] != '-') {
50                 bank[idx] = pin_name[idx];
51                 idx++;
52         }
53         bank[idx] = '\0';
54         *pin = pin_name[++idx] - '0';
55
56         /* lookup the pin bank data using the pin bank name */
57         for (idx = 0; idx < nr_banks; idx++)
58                 if (!strcmp(bank, bank_data[idx].name))
59                         break;
60
61         return priv->base + bank_data[idx].offset;
62 }
63
64 /**
65  * exynos_pinctrl_set_state: configure a pin state.
66  * dev: the pinctrl device to be configured.
67  * config: the state to be configured.
68  */
69 int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
70 {
71         const void *fdt = gd->fdt_blob;
72         int node = dev_of_offset(config);
73         unsigned int count, idx, pin_num;
74         unsigned int pinfunc, pinpud, pindrv;
75         unsigned long reg, value;
76         const char *name;
77
78         /*
79          * refer to the following document for the pinctrl bindings
80          * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
81          */
82         count = fdt_stringlist_count(fdt, node, "samsung,pins");
83         if (count <= 0)
84                 return -EINVAL;
85
86         pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1);
87         pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1);
88         pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1);
89
90         for (idx = 0; idx < count; idx++) {
91                 name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
92                 if (!name)
93                         continue;
94                 reg = pin_to_bank_base(dev, name, &pin_num);
95
96                 if (pinfunc != -1) {
97                         value = readl(reg + PIN_CON);
98                         value &= ~(0xf << (pin_num << 2));
99                         value |= (pinfunc << (pin_num << 2));
100                         writel(value, reg + PIN_CON);
101                 }
102
103                 if (pinpud != -1) {
104                         value = readl(reg + PIN_PUD);
105                         value &= ~(0x3 << (pin_num << 1));
106                         value |= (pinpud << (pin_num << 1));
107                         writel(value, reg + PIN_PUD);
108                 }
109
110                 if (pindrv != -1) {
111                         value = readl(reg + PIN_DRV);
112                         value &= ~(0x3 << (pin_num << 1));
113                         value |= (pindrv << (pin_num << 1));
114                         writel(value, reg + PIN_DRV);
115                 }
116         }
117
118         return 0;
119 }
120
121 int exynos_pinctrl_probe(struct udevice *dev)
122 {
123         struct exynos_pinctrl_priv *priv;
124         fdt_addr_t base;
125
126         priv = dev_get_priv(dev);
127         if (!priv)
128                 return -EINVAL;
129
130         base = devfdt_get_addr(dev);
131         if (base == FDT_ADDR_T_NONE)
132                 return -EINVAL;
133
134         priv->base = base;
135         priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
136                                 dev->req_seq;
137
138         return 0;
139 }