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