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 = config->of_offset;
74 	unsigned int count, idx, pin_num, ret;
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_count_strings(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 		ret = fdt_get_string_index(fdt, node, "samsung,pins",
93 						idx, &name);
94 		if (ret < 0)
95 			continue;
96 		reg = pin_to_bank_base(dev, name, &pin_num);
97 
98 		if (pinfunc != -1) {
99 			value = readl(reg + PIN_CON);
100 			value &= ~(0xf << (pin_num << 2));
101 			value |= (pinfunc << (pin_num << 2));
102 			writel(value, reg + PIN_CON);
103 		}
104 
105 		if (pinpud != -1) {
106 			value = readl(reg + PIN_PUD);
107 			value &= ~(0x3 << (pin_num << 1));
108 			value |= (pinpud << (pin_num << 1));
109 			writel(value, reg + PIN_PUD);
110 		}
111 
112 		if (pindrv != -1) {
113 			value = readl(reg + PIN_DRV);
114 			value &= ~(0x3 << (pin_num << 1));
115 			value |= (pindrv << (pin_num << 1));
116 			writel(value, reg + PIN_DRV);
117 		}
118 	}
119 
120 	return 0;
121 }
122 
123 int exynos_pinctrl_probe(struct udevice *dev)
124 {
125 	struct exynos_pinctrl_priv *priv;
126 	fdt_addr_t base;
127 
128 	priv = dev_get_priv(dev);
129 	if (!priv)
130 		return -EINVAL;
131 
132 	base = dev_get_addr(dev);
133 	if (base == FDT_ADDR_T_NONE)
134 		return -EINVAL;
135 
136 	priv->base = base;
137 	priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
138 				dev->req_seq;
139 
140 	return 0;
141 }
142