xref: /rk3399_rockchip-uboot/drivers/pinctrl/exynos/pinctrl-exynos.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
116ca80adSThomas Abraham /*
216ca80adSThomas Abraham  * Exynos pinctrl driver common code.
316ca80adSThomas Abraham  * Copyright (C) 2016 Samsung Electronics
416ca80adSThomas Abraham  * Thomas Abraham <thomas.ab@samsung.com>
516ca80adSThomas Abraham  *
616ca80adSThomas Abraham  * SPDX-License-Identifier:	GPL-2.0+
716ca80adSThomas Abraham  */
816ca80adSThomas Abraham 
916ca80adSThomas Abraham #include <common.h>
1016ca80adSThomas Abraham #include <dm.h>
1116ca80adSThomas Abraham #include <errno.h>
1216ca80adSThomas Abraham #include <asm/io.h>
1316ca80adSThomas Abraham #include "pinctrl-exynos.h"
1416ca80adSThomas Abraham 
1516ca80adSThomas Abraham DECLARE_GLOBAL_DATA_PTR;
1616ca80adSThomas Abraham 
1716ca80adSThomas Abraham /**
1816ca80adSThomas Abraham  * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral.
1916ca80adSThomas Abraham  * conf: soc specific pin configuration data array
2016ca80adSThomas Abraham  * num_conf: number of configurations in the conf array.
2116ca80adSThomas Abraham  * base: base address of the pin controller.
2216ca80adSThomas Abraham  */
exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data * conf,unsigned int num_conf,unsigned long base)2316ca80adSThomas Abraham void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
2416ca80adSThomas Abraham 		unsigned int num_conf, unsigned long base)
2516ca80adSThomas Abraham {
2616ca80adSThomas Abraham 	unsigned int idx, val;
2716ca80adSThomas Abraham 
2816ca80adSThomas Abraham 	for (idx = 0; idx < num_conf; idx++) {
2916ca80adSThomas Abraham 		val = readl(base + conf[idx].offset);
3016ca80adSThomas Abraham 		val &= ~(conf[idx].mask);
3116ca80adSThomas Abraham 		val |= conf[idx].value;
3216ca80adSThomas Abraham 		writel(val, base + conf[idx].offset);
3316ca80adSThomas Abraham 	}
3416ca80adSThomas Abraham }
3516ca80adSThomas Abraham 
3616ca80adSThomas Abraham /* given a pin-name, return the address of pin config registers */
pin_to_bank_base(struct udevice * dev,const char * pin_name,u32 * pin)3716ca80adSThomas Abraham static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
3816ca80adSThomas Abraham 						u32 *pin)
3916ca80adSThomas Abraham {
4016ca80adSThomas Abraham 	struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
4116ca80adSThomas Abraham 	const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl;
4216ca80adSThomas Abraham 	const struct samsung_pin_bank_data *bank_data = pin_ctrl->pin_banks;
4316ca80adSThomas Abraham 	u32 nr_banks = pin_ctrl->nr_banks, idx = 0;
4416ca80adSThomas Abraham 	char bank[10];
4516ca80adSThomas Abraham 
4616ca80adSThomas Abraham 	/*
4716ca80adSThomas Abraham 	 * The format of the pin name is <bank name>-<pin_number>.
4816ca80adSThomas Abraham 	 * Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number.
4916ca80adSThomas Abraham 	 */
5016ca80adSThomas Abraham 	while (pin_name[idx] != '-') {
5116ca80adSThomas Abraham 		bank[idx] = pin_name[idx];
5216ca80adSThomas Abraham 		idx++;
5316ca80adSThomas Abraham 	}
5416ca80adSThomas Abraham 	bank[idx] = '\0';
5516ca80adSThomas Abraham 	*pin = pin_name[++idx] - '0';
5616ca80adSThomas Abraham 
5716ca80adSThomas Abraham 	/* lookup the pin bank data using the pin bank name */
5816ca80adSThomas Abraham 	for (idx = 0; idx < nr_banks; idx++)
5916ca80adSThomas Abraham 		if (!strcmp(bank, bank_data[idx].name))
6016ca80adSThomas Abraham 			break;
6116ca80adSThomas Abraham 
6216ca80adSThomas Abraham 	return priv->base + bank_data[idx].offset;
6316ca80adSThomas Abraham }
6416ca80adSThomas Abraham 
6516ca80adSThomas Abraham /**
6616ca80adSThomas Abraham  * exynos_pinctrl_set_state: configure a pin state.
6716ca80adSThomas Abraham  * dev: the pinctrl device to be configured.
6816ca80adSThomas Abraham  * config: the state to be configured.
6916ca80adSThomas Abraham  */
exynos_pinctrl_set_state(struct udevice * dev,struct udevice * config)7016ca80adSThomas Abraham int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
7116ca80adSThomas Abraham {
7216ca80adSThomas Abraham 	const void *fdt = gd->fdt_blob;
73e160f7d4SSimon Glass 	int node = dev_of_offset(config);
74b02e4044SSimon Glass 	unsigned int count, idx, pin_num;
7516ca80adSThomas Abraham 	unsigned int pinfunc, pinpud, pindrv;
7616ca80adSThomas Abraham 	unsigned long reg, value;
7716ca80adSThomas Abraham 	const char *name;
7816ca80adSThomas Abraham 
7916ca80adSThomas Abraham 	/*
8016ca80adSThomas Abraham 	 * refer to the following document for the pinctrl bindings
8116ca80adSThomas Abraham 	 * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
8216ca80adSThomas Abraham 	 */
83b02e4044SSimon Glass 	count = fdt_stringlist_count(fdt, node, "samsung,pins");
8416ca80adSThomas Abraham 	if (count <= 0)
8516ca80adSThomas Abraham 		return -EINVAL;
8616ca80adSThomas Abraham 
8716ca80adSThomas Abraham 	pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1);
8816ca80adSThomas Abraham 	pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1);
8916ca80adSThomas Abraham 	pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1);
9016ca80adSThomas Abraham 
9116ca80adSThomas Abraham 	for (idx = 0; idx < count; idx++) {
92b02e4044SSimon Glass 		name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
93b02e4044SSimon Glass 		if (!name)
9416ca80adSThomas Abraham 			continue;
9516ca80adSThomas Abraham 		reg = pin_to_bank_base(dev, name, &pin_num);
9616ca80adSThomas Abraham 
9716ca80adSThomas Abraham 		if (pinfunc != -1) {
9816ca80adSThomas Abraham 			value = readl(reg + PIN_CON);
9916ca80adSThomas Abraham 			value &= ~(0xf << (pin_num << 2));
10016ca80adSThomas Abraham 			value |= (pinfunc << (pin_num << 2));
10116ca80adSThomas Abraham 			writel(value, reg + PIN_CON);
10216ca80adSThomas Abraham 		}
10316ca80adSThomas Abraham 
10416ca80adSThomas Abraham 		if (pinpud != -1) {
10516ca80adSThomas Abraham 			value = readl(reg + PIN_PUD);
10616ca80adSThomas Abraham 			value &= ~(0x3 << (pin_num << 1));
10716ca80adSThomas Abraham 			value |= (pinpud << (pin_num << 1));
10816ca80adSThomas Abraham 			writel(value, reg + PIN_PUD);
10916ca80adSThomas Abraham 		}
11016ca80adSThomas Abraham 
11116ca80adSThomas Abraham 		if (pindrv != -1) {
11216ca80adSThomas Abraham 			value = readl(reg + PIN_DRV);
11316ca80adSThomas Abraham 			value &= ~(0x3 << (pin_num << 1));
11416ca80adSThomas Abraham 			value |= (pindrv << (pin_num << 1));
11516ca80adSThomas Abraham 			writel(value, reg + PIN_DRV);
11616ca80adSThomas Abraham 		}
11716ca80adSThomas Abraham 	}
11816ca80adSThomas Abraham 
11916ca80adSThomas Abraham 	return 0;
12016ca80adSThomas Abraham }
12116ca80adSThomas Abraham 
exynos_pinctrl_probe(struct udevice * dev)12216ca80adSThomas Abraham int exynos_pinctrl_probe(struct udevice *dev)
12316ca80adSThomas Abraham {
12416ca80adSThomas Abraham 	struct exynos_pinctrl_priv *priv;
12516ca80adSThomas Abraham 	fdt_addr_t base;
12616ca80adSThomas Abraham 
12716ca80adSThomas Abraham 	priv = dev_get_priv(dev);
12816ca80adSThomas Abraham 	if (!priv)
12916ca80adSThomas Abraham 		return -EINVAL;
13016ca80adSThomas Abraham 
131*a821c4afSSimon Glass 	base = devfdt_get_addr(dev);
13216ca80adSThomas Abraham 	if (base == FDT_ADDR_T_NONE)
13316ca80adSThomas Abraham 		return -EINVAL;
13416ca80adSThomas Abraham 
13516ca80adSThomas Abraham 	priv->base = base;
13616ca80adSThomas Abraham 	priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
13716ca80adSThomas Abraham 				dev->req_seq;
13816ca80adSThomas Abraham 
13916ca80adSThomas Abraham 	return 0;
14016ca80adSThomas Abraham }
141