blob: 5b9a592b0da6f9cf3d1851cc06324723bed376f2 [file] [log] [blame]
Thomas Abrahamcf18bff2016-04-23 22:18:08 +05301/*
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
15DECLARE_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 */
23void 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 */
37static 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 */
70int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
71{
72 const void *fdt = gd->fdt_blob;
Simon Glassdd79d6e2017-01-17 16:52:55 -070073 int node = dev_of_offset(config);
Simon Glassb0ea7402016-10-02 17:59:28 -060074 unsigned int count, idx, pin_num;
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053075 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 */
Masahiro Yamadadb090a22016-10-17 20:43:01 +090083 count = fdt_stringlist_count(fdt, node, "samsung,pins");
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053084 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++) {
Simon Glassb0ea7402016-10-02 17:59:28 -060092 name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
93 if (!name)
Thomas Abrahamcf18bff2016-04-23 22:18:08 +053094 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
122int 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 = dev_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}