blob: e3ac5a6e498de59c3455759c0b63de47f556dbe9 [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
8#include <common.h>
9#include <dm.h>
10#include <errno.h>
11#include <asm/io.h>
12#include "pinctrl-exynos.h"
13
14DECLARE_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 */
22void 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 */
36static 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 */
69int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
70{
71 const void *fdt = gd->fdt_blob;
Simon Glassdd79d6e2017-01-17 16:52:55 -070072 int node = dev_of_offset(config);
Simon Glassb0ea7402016-10-02 17:59:28 -060073 unsigned int count, idx, pin_num;
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053074 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 */
Masahiro Yamadadb090a22016-10-17 20:43:01 +090082 count = fdt_stringlist_count(fdt, node, "samsung,pins");
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053083 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++) {
Simon Glassb0ea7402016-10-02 17:59:28 -060091 name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
92 if (!name)
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053093 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
121int 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
Simon Glassba1dea42017-05-17 17:18:05 -0600130 base = devfdt_get_addr(dev);
Thomas Abrahamcf18bff2016-04-23 22:18:08 +0530131 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}