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; 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_stringlist_count(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 name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL); 93 if (!name) 94 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 122 int 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 } 141