1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Exynos pinctrl driver common code.
4  * Copyright (C) 2016 Samsung Electronics
5  * Thomas Abraham <thomas.ab@samsung.com>
6  */
7 
8 #include <log.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <asm/io.h>
12 #include "pinctrl-exynos.h"
13 
14 /* CON, DAT, PUD, DRV */
15 const struct samsung_pin_bank_type bank_type_alive = {
16 	.fld_width = { 4, 1, 2, 2, },
17 	.reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
18 };
19 
20 static const char * const exynos_pinctrl_props[PINCFG_TYPE_NUM] = {
21 	[PINCFG_TYPE_FUNC]	= "samsung,pin-function",
22 	[PINCFG_TYPE_DAT]	= "samsung,pin-val",
23 	[PINCFG_TYPE_PUD]	= "samsung,pin-pud",
24 	[PINCFG_TYPE_DRV]	= "samsung,pin-drv",
25 };
26 
27 /**
28  * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral.
29  * conf: soc specific pin configuration data array
30  * num_conf: number of configurations in the conf array.
31  * base: base address of the pin controller.
32  */
exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data * conf,unsigned int num_conf,unsigned long base)33 void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
34 		unsigned int num_conf, unsigned long base)
35 {
36 	unsigned int idx, val;
37 
38 	for (idx = 0; idx < num_conf; idx++) {
39 		val = readl(base + conf[idx].offset);
40 		val &= ~(conf[idx].mask);
41 		val |= conf[idx].value;
42 		writel(val, base + conf[idx].offset);
43 	}
44 }
45 
parse_pin(const char * pin_name,u32 * pin,char * bank_name)46 static void parse_pin(const char *pin_name, u32 *pin, char *bank_name)
47 {
48 	u32 idx = 0;
49 
50 	/*
51 	 * The format of the pin name is <bank_name name>-<pin_number>.
52 	 * Example: gpa0-4 (gpa0 is the bank_name name and 4 is the pin number.
53 	 */
54 	while (pin_name[idx] != '-') {
55 		bank_name[idx] = pin_name[idx];
56 		idx++;
57 	}
58 	bank_name[idx] = '\0';
59 	*pin = pin_name[++idx] - '0';
60 }
61 
62 /* given a bank name, find out the pin bank structure */
get_bank(struct udevice * dev,const char * bank_name)63 static const struct samsung_pin_bank_data *get_bank(struct udevice *dev,
64 						    const char *bank_name)
65 {
66 	struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
67 	const struct samsung_pin_ctrl *pin_ctrl_array = priv->pin_ctrl;
68 	const struct samsung_pin_bank_data *bank_data;
69 	u32 nr_banks, pin_ctrl_idx = 0, idx = 0;
70 
71 	/* lookup the pin bank data using the pin bank name */
72 	while (true) {
73 		const struct samsung_pin_ctrl *pin_ctrl =
74 			&pin_ctrl_array[pin_ctrl_idx];
75 
76 		nr_banks = pin_ctrl->nr_banks;
77 		if (!nr_banks)
78 			break;
79 
80 		bank_data = pin_ctrl->pin_banks;
81 		for (idx = 0; idx < nr_banks; idx++) {
82 			debug("pinctrl[%d] bank_data[%d] name is: %s\n",
83 					pin_ctrl_idx, idx, bank_data[idx].name);
84 			if (!strcmp(bank_name, bank_data[idx].name))
85 				return &bank_data[idx];
86 		}
87 		pin_ctrl_idx++;
88 	}
89 
90 	return NULL;
91 }
92 
exynos_pinctrl_set_pincfg(unsigned long reg_base,u32 pin_num,u32 val,enum pincfg_type pincfg,const struct samsung_pin_bank_type * type)93 static void exynos_pinctrl_set_pincfg(unsigned long reg_base, u32 pin_num,
94 				      u32 val, enum pincfg_type pincfg,
95 				      const struct samsung_pin_bank_type *type)
96 {
97 	u32 width = type->fld_width[pincfg];
98 	u32 reg_offset = type->reg_offset[pincfg];
99 	u32 mask = (1 << width) - 1;
100 	u32 shift = pin_num * width;
101 	u32 data;
102 
103 	data = readl(reg_base + reg_offset);
104 	data &= ~(mask << shift);
105 	data |= val << shift;
106 	writel(data, reg_base + reg_offset);
107 }
108 
109 /**
110  * exynos_pinctrl_set_state: configure a pin state.
111  * dev: the pinctrl device to be configured.
112  * config: the state to be configured.
113  */
exynos_pinctrl_set_state(struct udevice * dev,struct udevice * config)114 int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
115 {
116 	struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
117 	int count;
118 	unsigned int idx, pinvals[PINCFG_TYPE_NUM];
119 
120 	/*
121 	 * refer to the following document for the pinctrl bindings
122 	 * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
123 	 */
124 	count = dev_read_string_count(config, "samsung,pins");
125 	if (count <= 0)
126 		return -EINVAL;
127 
128 	for (idx = 0; idx < PINCFG_TYPE_NUM; ++idx) {
129 		pinvals[idx] = dev_read_u32_default(config,
130 						exynos_pinctrl_props[idx], -1);
131 	}
132 	pinvals[PINCFG_TYPE_DAT] = -1; /* ignore GPIO data register */
133 
134 	for (idx = 0; idx < count; idx++) {
135 		const struct samsung_pin_bank_data *bank;
136 		unsigned int pin_num;
137 		char bank_name[10];
138 		unsigned long reg;
139 		const char *name = NULL;
140 		int pincfg, err;
141 
142 		err = dev_read_string_index(config, "samsung,pins", idx, &name);
143 		if (err || !name)
144 			continue;
145 
146 		parse_pin(name, &pin_num, bank_name);
147 		bank = get_bank(dev, bank_name);
148 		reg = priv->base + bank->offset;
149 
150 		for (pincfg = 0; pincfg < PINCFG_TYPE_NUM; ++pincfg) {
151 			unsigned int val = pinvals[pincfg];
152 
153 			if (val != -1)
154 				exynos_pinctrl_set_pincfg(reg, pin_num, val,
155 							  pincfg, bank->type);
156 		}
157 	}
158 
159 	return 0;
160 }
161 
exynos_pinctrl_probe(struct udevice * dev)162 int exynos_pinctrl_probe(struct udevice *dev)
163 {
164 	struct exynos_pinctrl_priv *priv;
165 	fdt_addr_t base;
166 
167 	priv = dev_get_priv(dev);
168 	if (!priv)
169 		return -EINVAL;
170 
171 	base = dev_read_addr(dev);
172 	if (base == FDT_ADDR_T_NONE)
173 		return -EINVAL;
174 
175 	priv->base = base;
176 	priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
177 				dev_seq(dev);
178 
179 	return 0;
180 }
181