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