1 /* 2 * (C) Copyright 2016 3 * Mario Six, Guntermann & Drunck GmbH, six@gdsys.de 4 * 5 * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is 6 * 7 * Copyright 2010 eXMeritus, A Boeing Company 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <dm.h> 14 #include <asm/gpio.h> 15 #include <mapmem.h> 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 struct ccsr_gpio { 20 u32 gpdir; 21 u32 gpodr; 22 u32 gpdat; 23 u32 gpier; 24 u32 gpimr; 25 u32 gpicr; 26 }; 27 28 struct mpc85xx_gpio_data { 29 /* The bank's register base in memory */ 30 struct ccsr_gpio __iomem *base; 31 /* The address of the registers; used to identify the bank */ 32 ulong addr; 33 /* The GPIO count of the bank */ 34 uint gpio_count; 35 /* The GPDAT register cannot be used to determine the value of output 36 * pins on MPC8572/MPC8536, so we shadow it and use the shadowed value 37 * for output pins */ 38 u32 dat_shadow; 39 }; 40 41 inline u32 gpio_mask(unsigned gpio) { 42 return (1U << (31 - (gpio))); 43 } 44 45 static inline u32 mpc85xx_gpio_get_val(struct ccsr_gpio *base, u32 mask) 46 { 47 return in_be32(&base->gpdat) & mask; 48 } 49 50 static inline u32 mpc85xx_gpio_get_dir(struct ccsr_gpio *base, u32 mask) 51 { 52 return in_be32(&base->gpdir) & mask; 53 } 54 55 static inline void mpc85xx_gpio_set_in(struct ccsr_gpio *base, u32 gpios) 56 { 57 clrbits_be32(&base->gpdat, gpios); 58 /* GPDIR register 0 -> input */ 59 clrbits_be32(&base->gpdir, gpios); 60 } 61 62 static inline void mpc85xx_gpio_set_low(struct ccsr_gpio *base, u32 gpios) 63 { 64 clrbits_be32(&base->gpdat, gpios); 65 /* GPDIR register 1 -> output */ 66 setbits_be32(&base->gpdir, gpios); 67 } 68 69 static inline void mpc85xx_gpio_set_high(struct ccsr_gpio *base, u32 gpios) 70 { 71 setbits_be32(&base->gpdat, gpios); 72 /* GPDIR register 1 -> output */ 73 setbits_be32(&base->gpdir, gpios); 74 } 75 76 static inline int mpc85xx_gpio_open_drain_val(struct ccsr_gpio *base, u32 mask) 77 { 78 return in_be32(&base->gpodr) & mask; 79 } 80 81 static inline void mpc85xx_gpio_open_drain_on(struct ccsr_gpio *base, u32 82 gpios) 83 { 84 /* GPODR register 1 -> open drain on */ 85 setbits_be32(&base->gpodr, gpios); 86 } 87 88 static inline void mpc85xx_gpio_open_drain_off(struct ccsr_gpio *base, 89 u32 gpios) 90 { 91 /* GPODR register 0 -> open drain off (actively driven) */ 92 clrbits_be32(&base->gpodr, gpios); 93 } 94 95 static int mpc85xx_gpio_direction_input(struct udevice *dev, unsigned gpio) 96 { 97 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 98 99 mpc85xx_gpio_set_in(data->base, gpio_mask(gpio)); 100 return 0; 101 } 102 103 static int mpc85xx_gpio_set_value(struct udevice *dev, unsigned gpio, 104 int value) 105 { 106 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 107 108 if (value) { 109 data->dat_shadow |= gpio_mask(gpio); 110 mpc85xx_gpio_set_high(data->base, gpio_mask(gpio)); 111 } else { 112 data->dat_shadow &= ~gpio_mask(gpio); 113 mpc85xx_gpio_set_low(data->base, gpio_mask(gpio)); 114 } 115 return 0; 116 } 117 118 static int mpc85xx_gpio_direction_output(struct udevice *dev, unsigned gpio, 119 int value) 120 { 121 return mpc85xx_gpio_set_value(dev, gpio, value); 122 } 123 124 static int mpc85xx_gpio_get_value(struct udevice *dev, unsigned gpio) 125 { 126 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 127 128 if (!!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio))) { 129 /* Output -> use shadowed value */ 130 return !!(data->dat_shadow & gpio_mask(gpio)); 131 } else { 132 /* Input -> read value from GPDAT register */ 133 return !!mpc85xx_gpio_get_val(data->base, gpio_mask(gpio)); 134 } 135 } 136 137 static int mpc85xx_gpio_get_open_drain(struct udevice *dev, unsigned gpio) 138 { 139 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 140 141 return !!mpc85xx_gpio_open_drain_val(data->base, gpio_mask(gpio)); 142 } 143 144 static int mpc85xx_gpio_set_open_drain(struct udevice *dev, unsigned gpio, 145 int value) 146 { 147 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 148 149 if (value) { 150 mpc85xx_gpio_open_drain_on(data->base, gpio_mask(gpio)); 151 } else { 152 mpc85xx_gpio_open_drain_off(data->base, gpio_mask(gpio)); 153 } 154 return 0; 155 } 156 157 static int mpc85xx_gpio_get_function(struct udevice *dev, unsigned gpio) 158 { 159 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 160 int dir; 161 162 dir = !!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio)); 163 return dir ? GPIOF_OUTPUT : GPIOF_INPUT; 164 } 165 166 #if CONFIG_IS_ENABLED(OF_CONTROL) 167 static int mpc85xx_gpio_ofdata_to_platdata(struct udevice *dev) { 168 struct mpc85xx_gpio_plat *plat = dev_get_platdata(dev); 169 fdt_addr_t addr; 170 fdt_size_t size; 171 172 addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, 173 dev_of_offset(dev), "reg", 0, &size, false); 174 175 plat->addr = addr; 176 plat->size = size; 177 plat->ngpios = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 178 "ngpios", 32); 179 180 return 0; 181 } 182 #endif 183 184 static int mpc85xx_gpio_platdata_to_priv(struct udevice *dev) 185 { 186 struct mpc85xx_gpio_data *priv = dev_get_priv(dev); 187 struct mpc85xx_gpio_plat *plat = dev_get_platdata(dev); 188 unsigned long size = plat->size; 189 190 if (size == 0) 191 size = 0x100; 192 193 priv->addr = plat->addr; 194 priv->base = map_sysmem(CONFIG_SYS_IMMR + plat->addr, size); 195 196 if (!priv->base) 197 return -ENOMEM; 198 199 priv->gpio_count = plat->ngpios; 200 priv->dat_shadow = 0; 201 202 return 0; 203 } 204 205 static int mpc85xx_gpio_probe(struct udevice *dev) 206 { 207 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 208 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 209 char name[32], *str; 210 211 mpc85xx_gpio_platdata_to_priv(dev); 212 213 snprintf(name, sizeof(name), "MPC@%lx_", data->addr); 214 str = strdup(name); 215 216 if (!str) 217 return -ENOMEM; 218 219 uc_priv->bank_name = str; 220 uc_priv->gpio_count = data->gpio_count; 221 222 return 0; 223 } 224 225 static const struct dm_gpio_ops gpio_mpc85xx_ops = { 226 .direction_input = mpc85xx_gpio_direction_input, 227 .direction_output = mpc85xx_gpio_direction_output, 228 .get_value = mpc85xx_gpio_get_value, 229 .set_value = mpc85xx_gpio_set_value, 230 .get_open_drain = mpc85xx_gpio_get_open_drain, 231 .set_open_drain = mpc85xx_gpio_set_open_drain, 232 .get_function = mpc85xx_gpio_get_function, 233 }; 234 235 static const struct udevice_id mpc85xx_gpio_ids[] = { 236 { .compatible = "fsl,pq3-gpio" }, 237 { /* sentinel */ } 238 }; 239 240 U_BOOT_DRIVER(gpio_mpc85xx) = { 241 .name = "gpio_mpc85xx", 242 .id = UCLASS_GPIO, 243 .ops = &gpio_mpc85xx_ops, 244 #if CONFIG_IS_ENABLED(OF_CONTROL) 245 .ofdata_to_platdata = mpc85xx_gpio_ofdata_to_platdata, 246 .platdata_auto_alloc_size = sizeof(struct mpc85xx_gpio_plat), 247 .of_match = mpc85xx_gpio_ids, 248 #endif 249 .probe = mpc85xx_gpio_probe, 250 .priv_auto_alloc_size = sizeof(struct mpc85xx_gpio_data), 251 }; 252