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 int mpc85xx_gpio_direction_input(struct udevice *dev, unsigned gpio) 77 { 78 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 79 80 mpc85xx_gpio_set_in(data->base, gpio_mask(gpio)); 81 return 0; 82 } 83 84 static int mpc85xx_gpio_set_value(struct udevice *dev, unsigned gpio, 85 int value) 86 { 87 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 88 89 if (value) { 90 data->dat_shadow |= gpio_mask(gpio); 91 mpc85xx_gpio_set_high(data->base, gpio_mask(gpio)); 92 } else { 93 data->dat_shadow &= ~gpio_mask(gpio); 94 mpc85xx_gpio_set_low(data->base, gpio_mask(gpio)); 95 } 96 return 0; 97 } 98 99 static int mpc85xx_gpio_direction_output(struct udevice *dev, unsigned gpio, 100 int value) 101 { 102 return mpc85xx_gpio_set_value(dev, gpio, value); 103 } 104 105 static int mpc85xx_gpio_get_value(struct udevice *dev, unsigned gpio) 106 { 107 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 108 109 if (!!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio))) { 110 /* Output -> use shadowed value */ 111 return !!(data->dat_shadow & gpio_mask(gpio)); 112 } else { 113 /* Input -> read value from GPDAT register */ 114 return !!mpc85xx_gpio_get_val(data->base, gpio_mask(gpio)); 115 } 116 } 117 118 static int mpc85xx_gpio_get_function(struct udevice *dev, unsigned gpio) 119 { 120 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 121 int dir; 122 123 dir = !!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio)); 124 return dir ? GPIOF_OUTPUT : GPIOF_INPUT; 125 } 126 127 static int mpc85xx_gpio_ofdata_to_platdata(struct udevice *dev) { 128 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 129 fdt_addr_t addr; 130 fdt_size_t size; 131 132 addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset, 133 "reg", 0, &size); 134 135 data->addr = addr; 136 data->base = map_sysmem(CONFIG_SYS_IMMR + addr, size); 137 138 if (!data->base) 139 return -ENOMEM; 140 141 data->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 142 "ngpios", 32); 143 data->dat_shadow = 0; 144 145 return 0; 146 } 147 148 static int mpc85xx_gpio_probe(struct udevice *dev) 149 { 150 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 151 struct mpc85xx_gpio_data *data = dev_get_priv(dev); 152 char name[32], *str; 153 154 snprintf(name, sizeof(name), "MPC@%lx_", data->addr); 155 str = strdup(name); 156 157 if (!str) 158 return -ENOMEM; 159 160 uc_priv->bank_name = str; 161 uc_priv->gpio_count = data->gpio_count; 162 163 return 0; 164 } 165 166 static const struct dm_gpio_ops gpio_mpc85xx_ops = { 167 .direction_input = mpc85xx_gpio_direction_input, 168 .direction_output = mpc85xx_gpio_direction_output, 169 .get_value = mpc85xx_gpio_get_value, 170 .set_value = mpc85xx_gpio_set_value, 171 .get_function = mpc85xx_gpio_get_function, 172 }; 173 174 static const struct udevice_id mpc85xx_gpio_ids[] = { 175 { .compatible = "fsl,pq3-gpio" }, 176 { /* sentinel */ } 177 }; 178 179 U_BOOT_DRIVER(gpio_mpc85xx) = { 180 .name = "gpio_mpc85xx", 181 .id = UCLASS_GPIO, 182 .ops = &gpio_mpc85xx_ops, 183 .ofdata_to_platdata = mpc85xx_gpio_ofdata_to_platdata, 184 .of_match = mpc85xx_gpio_ids, 185 .probe = mpc85xx_gpio_probe, 186 .priv_auto_alloc_size = sizeof(struct mpc85xx_gpio_data), 187 }; 188