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