1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Atmel PIO4 pinctrl driver 4 * 5 * Copyright (C) 2016 Atmel Corporation 6 * Wenyou.Yang <wenyou.yang@atmel.com> 7 */ 8 9 #include <common.h> 10 #include <dm.h> 11 #include <dm/pinctrl.h> 12 #include <linux/io.h> 13 #include <linux/err.h> 14 #include <mach/atmel_pio4.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 /* 19 * Warning: 20 * In order to not introduce confusion between Atmel PIO groups and pinctrl 21 * framework groups, Atmel PIO groups will be called banks. 22 */ 23 24 struct atmel_pio4_platdata { 25 struct atmel_pio4_port *reg_base; 26 }; 27 28 static const struct pinconf_param conf_params[] = { 29 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, 30 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, 31 { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, 32 { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, 33 { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, 34 { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, 35 { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, 36 }; 37 38 static u32 atmel_pinctrl_get_pinconf(const void *blob, int node) 39 { 40 const struct pinconf_param *params; 41 u32 param, arg, conf = 0; 42 u32 i; 43 44 for (i = 0; i < ARRAY_SIZE(conf_params); i++) { 45 params = &conf_params[i]; 46 if (!fdt_get_property(blob, node, params->property, NULL)) 47 continue; 48 49 param = params->param; 50 arg = params->default_value; 51 52 switch (param) { 53 case PIN_CONFIG_BIAS_DISABLE: 54 conf &= (~ATMEL_PIO_PUEN_MASK); 55 conf &= (~ATMEL_PIO_PDEN_MASK); 56 break; 57 case PIN_CONFIG_BIAS_PULL_UP: 58 conf |= ATMEL_PIO_PUEN_MASK; 59 break; 60 case PIN_CONFIG_BIAS_PULL_DOWN: 61 conf |= ATMEL_PIO_PDEN_MASK; 62 break; 63 case PIN_CONFIG_DRIVE_OPEN_DRAIN: 64 if (arg == 0) 65 conf &= (~ATMEL_PIO_OPD_MASK); 66 else 67 conf |= ATMEL_PIO_OPD_MASK; 68 break; 69 case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 70 if (arg == 0) 71 conf |= ATMEL_PIO_SCHMITT_MASK; 72 else 73 conf &= (~ATMEL_PIO_SCHMITT_MASK); 74 break; 75 case PIN_CONFIG_INPUT_DEBOUNCE: 76 if (arg == 0) { 77 conf &= (~ATMEL_PIO_IFEN_MASK); 78 conf &= (~ATMEL_PIO_IFSCEN_MASK); 79 } else { 80 conf |= ATMEL_PIO_IFEN_MASK; 81 conf |= ATMEL_PIO_IFSCEN_MASK; 82 } 83 break; 84 default: 85 printf("%s: Unsupported configuration parameter: %u\n", 86 __func__, param); 87 break; 88 } 89 } 90 91 return conf; 92 } 93 94 static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev, 95 u32 bank) 96 { 97 struct atmel_pio4_platdata *plat = dev_get_platdata(dev); 98 struct atmel_pio4_port *bank_base = 99 (struct atmel_pio4_port *)((u32)plat->reg_base + 100 ATMEL_PIO_BANK_OFFSET * bank); 101 102 return bank_base; 103 } 104 105 #define MAX_PINMUX_ENTRIES 40 106 107 static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config) 108 { 109 struct atmel_pio4_port *bank_base; 110 const void *blob = gd->fdt_blob; 111 int node = dev_of_offset(config); 112 u32 offset, func, bank, line; 113 u32 cells[MAX_PINMUX_ENTRIES]; 114 u32 i, conf; 115 int count; 116 117 conf = atmel_pinctrl_get_pinconf(blob, node); 118 119 count = fdtdec_get_int_array_count(blob, node, "pinmux", 120 cells, ARRAY_SIZE(cells)); 121 if (count < 0) { 122 printf("%s: bad pinmux array %d\n", __func__, count); 123 return -EINVAL; 124 } 125 126 if (count > MAX_PINMUX_ENTRIES) { 127 printf("%s: unsupported pinmux array count %d\n", 128 __func__, count); 129 return -EINVAL; 130 } 131 132 for (i = 0 ; i < count; i++) { 133 offset = ATMEL_GET_PIN_NO(cells[i]); 134 func = ATMEL_GET_PIN_FUNC(cells[i]); 135 136 bank = ATMEL_PIO_BANK(offset); 137 line = ATMEL_PIO_LINE(offset); 138 139 bank_base = atmel_pio4_bank_base(dev, bank); 140 141 writel(BIT(line), &bank_base->mskr); 142 conf &= (~ATMEL_PIO_CFGR_FUNC_MASK); 143 conf |= (func & ATMEL_PIO_CFGR_FUNC_MASK); 144 writel(conf, &bank_base->cfgr); 145 } 146 147 return 0; 148 } 149 150 const struct pinctrl_ops atmel_pinctrl_ops = { 151 .set_state = atmel_pinctrl_set_state, 152 }; 153 154 static int atmel_pinctrl_probe(struct udevice *dev) 155 { 156 struct atmel_pio4_platdata *plat = dev_get_platdata(dev); 157 fdt_addr_t addr_base; 158 159 dev = dev_get_parent(dev); 160 addr_base = devfdt_get_addr(dev); 161 if (addr_base == FDT_ADDR_T_NONE) 162 return -EINVAL; 163 164 plat->reg_base = (struct atmel_pio4_port *)addr_base; 165 166 return 0; 167 } 168 169 static const struct udevice_id atmel_pinctrl_match[] = { 170 { .compatible = "atmel,sama5d2-pinctrl" }, 171 {} 172 }; 173 174 U_BOOT_DRIVER(atmel_pinctrl) = { 175 .name = "pinctrl_atmel_pio4", 176 .id = UCLASS_PINCTRL, 177 .of_match = atmel_pinctrl_match, 178 .probe = atmel_pinctrl_probe, 179 .platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata), 180 .ops = &atmel_pinctrl_ops, 181 }; 182