xref: /OK3568_Linux_fs/u-boot/drivers/pinctrl/exynos/pinctrl-exynos.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Exynos pinctrl driver common code.
3*4882a593Smuzhiyun  * Copyright (C) 2016 Samsung Electronics
4*4882a593Smuzhiyun  * Thomas Abraham <thomas.ab@samsung.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <errno.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun #include "pinctrl-exynos.h"
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /**
18*4882a593Smuzhiyun  * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral.
19*4882a593Smuzhiyun  * conf: soc specific pin configuration data array
20*4882a593Smuzhiyun  * num_conf: number of configurations in the conf array.
21*4882a593Smuzhiyun  * base: base address of the pin controller.
22*4882a593Smuzhiyun  */
exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data * conf,unsigned int num_conf,unsigned long base)23*4882a593Smuzhiyun void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
24*4882a593Smuzhiyun 		unsigned int num_conf, unsigned long base)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	unsigned int idx, val;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	for (idx = 0; idx < num_conf; idx++) {
29*4882a593Smuzhiyun 		val = readl(base + conf[idx].offset);
30*4882a593Smuzhiyun 		val &= ~(conf[idx].mask);
31*4882a593Smuzhiyun 		val |= conf[idx].value;
32*4882a593Smuzhiyun 		writel(val, base + conf[idx].offset);
33*4882a593Smuzhiyun 	}
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* given a pin-name, return the address of pin config registers */
pin_to_bank_base(struct udevice * dev,const char * pin_name,u32 * pin)37*4882a593Smuzhiyun static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
38*4882a593Smuzhiyun 						u32 *pin)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
41*4882a593Smuzhiyun 	const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl;
42*4882a593Smuzhiyun 	const struct samsung_pin_bank_data *bank_data = pin_ctrl->pin_banks;
43*4882a593Smuzhiyun 	u32 nr_banks = pin_ctrl->nr_banks, idx = 0;
44*4882a593Smuzhiyun 	char bank[10];
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	/*
47*4882a593Smuzhiyun 	 * The format of the pin name is <bank name>-<pin_number>.
48*4882a593Smuzhiyun 	 * Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number.
49*4882a593Smuzhiyun 	 */
50*4882a593Smuzhiyun 	while (pin_name[idx] != '-') {
51*4882a593Smuzhiyun 		bank[idx] = pin_name[idx];
52*4882a593Smuzhiyun 		idx++;
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun 	bank[idx] = '\0';
55*4882a593Smuzhiyun 	*pin = pin_name[++idx] - '0';
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	/* lookup the pin bank data using the pin bank name */
58*4882a593Smuzhiyun 	for (idx = 0; idx < nr_banks; idx++)
59*4882a593Smuzhiyun 		if (!strcmp(bank, bank_data[idx].name))
60*4882a593Smuzhiyun 			break;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return priv->base + bank_data[idx].offset;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /**
66*4882a593Smuzhiyun  * exynos_pinctrl_set_state: configure a pin state.
67*4882a593Smuzhiyun  * dev: the pinctrl device to be configured.
68*4882a593Smuzhiyun  * config: the state to be configured.
69*4882a593Smuzhiyun  */
exynos_pinctrl_set_state(struct udevice * dev,struct udevice * config)70*4882a593Smuzhiyun int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	const void *fdt = gd->fdt_blob;
73*4882a593Smuzhiyun 	int node = dev_of_offset(config);
74*4882a593Smuzhiyun 	unsigned int count, idx, pin_num;
75*4882a593Smuzhiyun 	unsigned int pinfunc, pinpud, pindrv;
76*4882a593Smuzhiyun 	unsigned long reg, value;
77*4882a593Smuzhiyun 	const char *name;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	/*
80*4882a593Smuzhiyun 	 * refer to the following document for the pinctrl bindings
81*4882a593Smuzhiyun 	 * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
82*4882a593Smuzhiyun 	 */
83*4882a593Smuzhiyun 	count = fdt_stringlist_count(fdt, node, "samsung,pins");
84*4882a593Smuzhiyun 	if (count <= 0)
85*4882a593Smuzhiyun 		return -EINVAL;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1);
88*4882a593Smuzhiyun 	pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1);
89*4882a593Smuzhiyun 	pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	for (idx = 0; idx < count; idx++) {
92*4882a593Smuzhiyun 		name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
93*4882a593Smuzhiyun 		if (!name)
94*4882a593Smuzhiyun 			continue;
95*4882a593Smuzhiyun 		reg = pin_to_bank_base(dev, name, &pin_num);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 		if (pinfunc != -1) {
98*4882a593Smuzhiyun 			value = readl(reg + PIN_CON);
99*4882a593Smuzhiyun 			value &= ~(0xf << (pin_num << 2));
100*4882a593Smuzhiyun 			value |= (pinfunc << (pin_num << 2));
101*4882a593Smuzhiyun 			writel(value, reg + PIN_CON);
102*4882a593Smuzhiyun 		}
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 		if (pinpud != -1) {
105*4882a593Smuzhiyun 			value = readl(reg + PIN_PUD);
106*4882a593Smuzhiyun 			value &= ~(0x3 << (pin_num << 1));
107*4882a593Smuzhiyun 			value |= (pinpud << (pin_num << 1));
108*4882a593Smuzhiyun 			writel(value, reg + PIN_PUD);
109*4882a593Smuzhiyun 		}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		if (pindrv != -1) {
112*4882a593Smuzhiyun 			value = readl(reg + PIN_DRV);
113*4882a593Smuzhiyun 			value &= ~(0x3 << (pin_num << 1));
114*4882a593Smuzhiyun 			value |= (pindrv << (pin_num << 1));
115*4882a593Smuzhiyun 			writel(value, reg + PIN_DRV);
116*4882a593Smuzhiyun 		}
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
exynos_pinctrl_probe(struct udevice * dev)122*4882a593Smuzhiyun int exynos_pinctrl_probe(struct udevice *dev)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	struct exynos_pinctrl_priv *priv;
125*4882a593Smuzhiyun 	fdt_addr_t base;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	priv = dev_get_priv(dev);
128*4882a593Smuzhiyun 	if (!priv)
129*4882a593Smuzhiyun 		return -EINVAL;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	base = devfdt_get_addr(dev);
132*4882a593Smuzhiyun 	if (base == FDT_ADDR_T_NONE)
133*4882a593Smuzhiyun 		return -EINVAL;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	priv->base = base;
136*4882a593Smuzhiyun 	priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
137*4882a593Smuzhiyun 				dev->req_seq;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return 0;
140*4882a593Smuzhiyun }
141