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, ret; 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_count_strings(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 ret = fdt_get_string_index(fdt, node, "samsung,pins", 93 idx, &name); 94 if (ret < 0) 95 continue; 96 reg = pin_to_bank_base(dev, name, &pin_num); 97 98 if (pinfunc != -1) { 99 value = readl(reg + PIN_CON); 100 value &= ~(0xf << (pin_num << 2)); 101 value |= (pinfunc << (pin_num << 2)); 102 writel(value, reg + PIN_CON); 103 } 104 105 if (pinpud != -1) { 106 value = readl(reg + PIN_PUD); 107 value &= ~(0x3 << (pin_num << 1)); 108 value |= (pinpud << (pin_num << 1)); 109 writel(value, reg + PIN_PUD); 110 } 111 112 if (pindrv != -1) { 113 value = readl(reg + PIN_DRV); 114 value &= ~(0x3 << (pin_num << 1)); 115 value |= (pindrv << (pin_num << 1)); 116 writel(value, reg + PIN_DRV); 117 } 118 } 119 120 return 0; 121 } 122 123 int exynos_pinctrl_probe(struct udevice *dev) 124 { 125 struct exynos_pinctrl_priv *priv; 126 fdt_addr_t base; 127 128 priv = dev_get_priv(dev); 129 if (!priv) 130 return -EINVAL; 131 132 base = dev_get_addr(dev); 133 if (base == FDT_ADDR_T_NONE) 134 return -EINVAL; 135 136 priv->base = base; 137 priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) + 138 dev->req_seq; 139 140 return 0; 141 } 142