1 /* 2 * Copyright 2016 Freescale Semiconductor, Inc. 3 * 4 * RGPIO2P driver for the Freescale i.MX7ULP. 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <dm.h> 11 #include <errno.h> 12 #include <fdtdec.h> 13 #include <asm/gpio.h> 14 #include <asm/io.h> 15 #include <malloc.h> 16 17 enum imx_rgpio2p_direction { 18 IMX_RGPIO2P_DIRECTION_IN, 19 IMX_RGPIO2P_DIRECTION_OUT, 20 }; 21 22 #define GPIO_PER_BANK 32 23 24 struct imx_rgpio2p_data { 25 struct gpio_regs *regs; 26 }; 27 28 struct imx_rgpio2p_plat { 29 int bank_index; 30 struct gpio_regs *regs; 31 }; 32 33 static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset) 34 { 35 u32 val; 36 37 val = readl(®s->gpio_pddr); 38 39 return val & (1 << offset) ? 1 : 0; 40 } 41 42 static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset, 43 enum imx_rgpio2p_direction direction) 44 { 45 u32 l; 46 47 l = readl(®s->gpio_pddr); 48 49 switch (direction) { 50 case IMX_RGPIO2P_DIRECTION_OUT: 51 l |= 1 << offset; 52 break; 53 case IMX_RGPIO2P_DIRECTION_IN: 54 l &= ~(1 << offset); 55 } 56 writel(l, ®s->gpio_pddr); 57 } 58 59 static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset, 60 int value) 61 { 62 if (value) 63 writel((1 << offset), ®s->gpio_psor); 64 else 65 writel((1 << offset), ®s->gpio_pcor); 66 } 67 68 static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset) 69 { 70 return (readl(®s->gpio_pdir) >> offset) & 0x01; 71 } 72 73 static int imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset) 74 { 75 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 76 77 /* Configure GPIO direction as input. */ 78 imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN); 79 80 return 0; 81 } 82 83 static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset, 84 int value) 85 { 86 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 87 88 /* Configure GPIO output value. */ 89 imx_rgpio2p_bank_set_value(bank->regs, offset, value); 90 91 /* Configure GPIO direction as output. */ 92 imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT); 93 94 return 0; 95 } 96 97 static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset) 98 { 99 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 100 101 return imx_rgpio2p_bank_get_value(bank->regs, offset); 102 } 103 104 static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset, 105 int value) 106 { 107 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 108 109 imx_rgpio2p_bank_set_value(bank->regs, offset, value); 110 111 return 0; 112 } 113 114 static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset) 115 { 116 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 117 118 /* GPIOF_FUNC is not implemented yet */ 119 if (imx_rgpio2p_is_output(bank->regs, offset)) 120 return GPIOF_OUTPUT; 121 else 122 return GPIOF_INPUT; 123 } 124 125 static const struct dm_gpio_ops imx_rgpio2p_ops = { 126 .direction_input = imx_rgpio2p_direction_input, 127 .direction_output = imx_rgpio2p_direction_output, 128 .get_value = imx_rgpio2p_get_value, 129 .set_value = imx_rgpio2p_set_value, 130 .get_function = imx_rgpio2p_get_function, 131 }; 132 133 static int imx_rgpio2p_probe(struct udevice *dev) 134 { 135 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 136 struct imx_rgpio2p_plat *plat = dev_get_platdata(dev); 137 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 138 int banknum; 139 char name[18], *str; 140 141 banknum = plat->bank_index; 142 sprintf(name, "GPIO%d_", banknum + 1); 143 str = strdup(name); 144 if (!str) 145 return -ENOMEM; 146 uc_priv->bank_name = str; 147 uc_priv->gpio_count = GPIO_PER_BANK; 148 bank->regs = plat->regs; 149 150 return 0; 151 } 152 153 static int imx_rgpio2p_bind(struct udevice *dev) 154 { 155 struct imx_rgpio2p_plat *plat = dev->platdata; 156 fdt_addr_t addr; 157 158 /* 159 * If platdata already exsits, directly return. 160 * Actually only when DT is not supported, platdata 161 * is statically initialized in U_BOOT_DEVICES.Here 162 * will return. 163 */ 164 if (plat) 165 return 0; 166 167 addr = devfdt_get_addr_index(dev, 1); 168 if (addr == FDT_ADDR_T_NONE) 169 return -EINVAL; 170 171 /* 172 * TODO: 173 * When every board is converted to driver model and DT is supported, 174 * this can be done by auto-alloc feature, but not using calloc 175 * to alloc memory for platdata. 176 * 177 * For example imx_rgpio2p_plat uses platform data rather than device 178 * tree. 179 * 180 * NOTE: DO NOT COPY this code if you are using device tree. 181 */ 182 plat = calloc(1, sizeof(*plat)); 183 if (!plat) 184 return -ENOMEM; 185 186 plat->regs = (struct gpio_regs *)addr; 187 plat->bank_index = dev->req_seq; 188 dev->platdata = plat; 189 190 return 0; 191 } 192 193 194 static const struct udevice_id imx_rgpio2p_ids[] = { 195 { .compatible = "fsl,imx7ulp-gpio" }, 196 { } 197 }; 198 199 U_BOOT_DRIVER(imx_rgpio2p) = { 200 .name = "imx_rgpio2p", 201 .id = UCLASS_GPIO, 202 .ops = &imx_rgpio2p_ops, 203 .probe = imx_rgpio2p_probe, 204 .priv_auto_alloc_size = sizeof(struct imx_rgpio2p_plat), 205 .of_match = imx_rgpio2p_ids, 206 .bind = imx_rgpio2p_bind, 207 }; 208 209 #if !CONFIG_IS_ENABLED(OF_CONTROL) 210 static const struct imx_rgpio2p_plat imx_plat[] = { 211 { 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR }, 212 { 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR }, 213 { 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR }, 214 { 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR }, 215 { 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR }, 216 { 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR }, 217 }; 218 219 U_BOOT_DEVICES(imx_rgpio2ps) = { 220 { "imx_rgpio2p", &imx_plat[0] }, 221 { "imx_rgpio2p", &imx_plat[1] }, 222 { "imx_rgpio2p", &imx_plat[2] }, 223 { "imx_rgpio2p", &imx_plat[3] }, 224 { "imx_rgpio2p", &imx_plat[4] }, 225 { "imx_rgpio2p", &imx_plat[5] }, 226 }; 227 #endif 228