blob: 2d194ba0a4b5ff90548146da83da1b32294cfbe3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Thomas Abrahamcf18bff2016-04-23 22:18:08 +05302/*
3 * Exynos pinctrl driver common code.
4 * Copyright (C) 2016 Samsung Electronics
5 * Thomas Abraham <thomas.ab@samsung.com>
Thomas Abrahamcf18bff2016-04-23 22:18:08 +05306 */
7
Dzmitry Sankouski0024e442021-10-17 13:45:40 +03008#include <log.h>
Thomas Abrahamcf18bff2016-04-23 22:18:08 +05309#include <common.h>
10#include <dm.h>
11#include <errno.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060012#include <asm/global_data.h>
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053013#include <asm/io.h>
14#include "pinctrl-exynos.h"
15
16DECLARE_GLOBAL_DATA_PTR;
17
18/**
19 * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral.
20 * conf: soc specific pin configuration data array
21 * num_conf: number of configurations in the conf array.
22 * base: base address of the pin controller.
23 */
24void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
25 unsigned int num_conf, unsigned long base)
26{
27 unsigned int idx, val;
28
29 for (idx = 0; idx < num_conf; idx++) {
30 val = readl(base + conf[idx].offset);
31 val &= ~(conf[idx].mask);
32 val |= conf[idx].value;
33 writel(val, base + conf[idx].offset);
34 }
35}
36
Sam Protsenko18357b32023-11-30 14:13:47 -060037static void parse_pin(const char *pin_name, u32 *pin, char *bank_name)
38{
39 u32 idx = 0;
40
41 /*
42 * The format of the pin name is <bank_name name>-<pin_number>.
43 * Example: gpa0-4 (gpa0 is the bank_name name and 4 is the pin number.
44 */
45 while (pin_name[idx] != '-') {
46 bank_name[idx] = pin_name[idx];
47 idx++;
48 }
49 bank_name[idx] = '\0';
50 *pin = pin_name[++idx] - '0';
51}
52
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053053/* given a pin-name, return the address of pin config registers */
54static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
55 u32 *pin)
56{
57 struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
Dzmitry Sankouski0024e442021-10-17 13:45:40 +030058 const struct samsung_pin_ctrl *pin_ctrl_array = priv->pin_ctrl;
59 const struct samsung_pin_bank_data *bank_data;
60 u32 nr_banks, pin_ctrl_idx = 0, idx = 0, bank_base;
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053061 char bank[10];
62
Sam Protsenko18357b32023-11-30 14:13:47 -060063 parse_pin(pin_name, pin, bank);
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053064
65 /* lookup the pin bank data using the pin bank name */
Dzmitry Sankouski0024e442021-10-17 13:45:40 +030066 while (true) {
Sam Protsenko769abf72023-11-30 14:13:46 -060067 const struct samsung_pin_ctrl *pin_ctrl =
68 &pin_ctrl_array[pin_ctrl_idx];
Dzmitry Sankouski0024e442021-10-17 13:45:40 +030069
70 nr_banks = pin_ctrl->nr_banks;
71 if (!nr_banks)
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053072 break;
73
Dzmitry Sankouski0024e442021-10-17 13:45:40 +030074 bank_data = pin_ctrl->pin_banks;
75 for (idx = 0; idx < nr_banks; idx++) {
76 debug("pinctrl[%d] bank_data[%d] name is: %s\n",
77 pin_ctrl_idx, idx, bank_data[idx].name);
78 if (!strcmp(bank, bank_data[idx].name)) {
79 bank_base = priv->base + bank_data[idx].offset;
80 break;
81 }
82 }
83 pin_ctrl_idx++;
84 }
85
86 return bank_base;
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053087}
88
89/**
90 * exynos_pinctrl_set_state: configure a pin state.
91 * dev: the pinctrl device to be configured.
92 * config: the state to be configured.
93 */
94int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
95{
96 const void *fdt = gd->fdt_blob;
Simon Glassdd79d6e2017-01-17 16:52:55 -070097 int node = dev_of_offset(config);
Simon Glassb0ea7402016-10-02 17:59:28 -060098 unsigned int count, idx, pin_num;
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053099 unsigned int pinfunc, pinpud, pindrv;
100 unsigned long reg, value;
101 const char *name;
102
103 /*
104 * refer to the following document for the pinctrl bindings
105 * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
106 */
Masahiro Yamadadb090a22016-10-17 20:43:01 +0900107 count = fdt_stringlist_count(fdt, node, "samsung,pins");
Thomas Abrahamcf18bff2016-04-23 22:18:08 +0530108 if (count <= 0)
109 return -EINVAL;
110
111 pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1);
112 pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1);
113 pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1);
114
115 for (idx = 0; idx < count; idx++) {
Simon Glassb0ea7402016-10-02 17:59:28 -0600116 name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
117 if (!name)
Thomas Abrahamcf18bff2016-04-23 22:18:08 +0530118 continue;
119 reg = pin_to_bank_base(dev, name, &pin_num);
120
121 if (pinfunc != -1) {
122 value = readl(reg + PIN_CON);
123 value &= ~(0xf << (pin_num << 2));
124 value |= (pinfunc << (pin_num << 2));
125 writel(value, reg + PIN_CON);
126 }
127
128 if (pinpud != -1) {
129 value = readl(reg + PIN_PUD);
130 value &= ~(0x3 << (pin_num << 1));
131 value |= (pinpud << (pin_num << 1));
132 writel(value, reg + PIN_PUD);
133 }
134
135 if (pindrv != -1) {
136 value = readl(reg + PIN_DRV);
137 value &= ~(0x3 << (pin_num << 1));
138 value |= (pindrv << (pin_num << 1));
139 writel(value, reg + PIN_DRV);
140 }
141 }
142
143 return 0;
144}
145
146int exynos_pinctrl_probe(struct udevice *dev)
147{
148 struct exynos_pinctrl_priv *priv;
149 fdt_addr_t base;
150
151 priv = dev_get_priv(dev);
152 if (!priv)
153 return -EINVAL;
154
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900155 base = dev_read_addr(dev);
Thomas Abrahamcf18bff2016-04-23 22:18:08 +0530156 if (base == FDT_ADDR_T_NONE)
157 return -EINVAL;
158
159 priv->base = base;
160 priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
Simon Glass99382ba2020-12-16 21:20:25 -0700161 dev_seq(dev);
Thomas Abrahamcf18bff2016-04-23 22:18:08 +0530162
163 return 0;
164}