1c4ea1424SStefano Babic /* 2c4ea1424SStefano Babic * Copyright (C) 2009 3c4ea1424SStefano Babic * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> 4c4ea1424SStefano Babic * 5d8e0ca85SStefano Babic * Copyright (C) 2011 6d8e0ca85SStefano Babic * Stefano Babic, DENX Software Engineering, <sbabic@denx.de> 7d8e0ca85SStefano Babic * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 9c4ea1424SStefano Babic */ 10c4ea1424SStefano Babic #include <common.h> 11441d0cffSSimon Glass #include <errno.h> 12441d0cffSSimon Glass #include <dm.h> 13441d0cffSSimon Glass #include <malloc.h> 14c4ea1424SStefano Babic #include <asm/arch/imx-regs.h> 15d8e0ca85SStefano Babic #include <asm/gpio.h> 16c4ea1424SStefano Babic #include <asm/io.h> 17c4ea1424SStefano Babic 18d8e0ca85SStefano Babic enum mxc_gpio_direction { 19d8e0ca85SStefano Babic MXC_GPIO_DIRECTION_IN, 20d8e0ca85SStefano Babic MXC_GPIO_DIRECTION_OUT, 21d8e0ca85SStefano Babic }; 22d8e0ca85SStefano Babic 23441d0cffSSimon Glass #define GPIO_PER_BANK 32 24441d0cffSSimon Glass 25441d0cffSSimon Glass struct mxc_gpio_plat { 26637a7693SPeng Fan int bank_index; 27441d0cffSSimon Glass struct gpio_regs *regs; 28441d0cffSSimon Glass }; 29441d0cffSSimon Glass 30441d0cffSSimon Glass struct mxc_bank_info { 31441d0cffSSimon Glass struct gpio_regs *regs; 32441d0cffSSimon Glass }; 33441d0cffSSimon Glass 34441d0cffSSimon Glass #ifndef CONFIG_DM_GPIO 358d28c211SVikram Narayanan #define GPIO_TO_PORT(n) (n / 32) 36d8e0ca85SStefano Babic 37c4ea1424SStefano Babic /* GPIO port description */ 38c4ea1424SStefano Babic static unsigned long gpio_ports[] = { 39c4ea1424SStefano Babic [0] = GPIO1_BASE_ADDR, 40c4ea1424SStefano Babic [1] = GPIO2_BASE_ADDR, 41c4ea1424SStefano Babic [2] = GPIO3_BASE_ADDR, 42e71c39deStrem #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ 435ea6d7c8STroy Kisky defined(CONFIG_MX53) || defined(CONFIG_MX6) 44c4ea1424SStefano Babic [3] = GPIO4_BASE_ADDR, 45c4ea1424SStefano Babic #endif 465ea6d7c8STroy Kisky #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) 4701643ec1SLiu Hui-R64343 [4] = GPIO5_BASE_ADDR, 4801643ec1SLiu Hui-R64343 [5] = GPIO6_BASE_ADDR, 49e71c39deStrem #endif 505ea6d7c8STroy Kisky #if defined(CONFIG_MX53) || defined(CONFIG_MX6) 5101643ec1SLiu Hui-R64343 [6] = GPIO7_BASE_ADDR, 5201643ec1SLiu Hui-R64343 #endif 53c4ea1424SStefano Babic }; 54c4ea1424SStefano Babic 55d8e0ca85SStefano Babic static int mxc_gpio_direction(unsigned int gpio, 56d8e0ca85SStefano Babic enum mxc_gpio_direction direction) 57c4ea1424SStefano Babic { 58be282554SVikram Narayanan unsigned int port = GPIO_TO_PORT(gpio); 59c4ea1424SStefano Babic struct gpio_regs *regs; 60c4ea1424SStefano Babic u32 l; 61c4ea1424SStefano Babic 62c4ea1424SStefano Babic if (port >= ARRAY_SIZE(gpio_ports)) 63365d6070SJoe Hershberger return -1; 64c4ea1424SStefano Babic 65c4ea1424SStefano Babic gpio &= 0x1f; 66c4ea1424SStefano Babic 67c4ea1424SStefano Babic regs = (struct gpio_regs *)gpio_ports[port]; 68c4ea1424SStefano Babic 69c4ea1424SStefano Babic l = readl(®s->gpio_dir); 70c4ea1424SStefano Babic 71c4ea1424SStefano Babic switch (direction) { 72c4ea1424SStefano Babic case MXC_GPIO_DIRECTION_OUT: 73c4ea1424SStefano Babic l |= 1 << gpio; 74c4ea1424SStefano Babic break; 75c4ea1424SStefano Babic case MXC_GPIO_DIRECTION_IN: 76c4ea1424SStefano Babic l &= ~(1 << gpio); 77c4ea1424SStefano Babic } 78c4ea1424SStefano Babic writel(l, ®s->gpio_dir); 79c4ea1424SStefano Babic 80c4ea1424SStefano Babic return 0; 81c4ea1424SStefano Babic } 82c4ea1424SStefano Babic 83365d6070SJoe Hershberger int gpio_set_value(unsigned gpio, int value) 84c4ea1424SStefano Babic { 85be282554SVikram Narayanan unsigned int port = GPIO_TO_PORT(gpio); 86c4ea1424SStefano Babic struct gpio_regs *regs; 87c4ea1424SStefano Babic u32 l; 88c4ea1424SStefano Babic 89c4ea1424SStefano Babic if (port >= ARRAY_SIZE(gpio_ports)) 90365d6070SJoe Hershberger return -1; 91c4ea1424SStefano Babic 92c4ea1424SStefano Babic gpio &= 0x1f; 93c4ea1424SStefano Babic 94c4ea1424SStefano Babic regs = (struct gpio_regs *)gpio_ports[port]; 95c4ea1424SStefano Babic 96c4ea1424SStefano Babic l = readl(®s->gpio_dr); 97c4ea1424SStefano Babic if (value) 98c4ea1424SStefano Babic l |= 1 << gpio; 99c4ea1424SStefano Babic else 100c4ea1424SStefano Babic l &= ~(1 << gpio); 101c4ea1424SStefano Babic writel(l, ®s->gpio_dr); 102365d6070SJoe Hershberger 103365d6070SJoe Hershberger return 0; 104c4ea1424SStefano Babic } 105c4ea1424SStefano Babic 106365d6070SJoe Hershberger int gpio_get_value(unsigned gpio) 107c4ea1424SStefano Babic { 108be282554SVikram Narayanan unsigned int port = GPIO_TO_PORT(gpio); 109c4ea1424SStefano Babic struct gpio_regs *regs; 110365d6070SJoe Hershberger u32 val; 111c4ea1424SStefano Babic 112c4ea1424SStefano Babic if (port >= ARRAY_SIZE(gpio_ports)) 113365d6070SJoe Hershberger return -1; 114c4ea1424SStefano Babic 115c4ea1424SStefano Babic gpio &= 0x1f; 116c4ea1424SStefano Babic 117c4ea1424SStefano Babic regs = (struct gpio_regs *)gpio_ports[port]; 118c4ea1424SStefano Babic 1195dafa454SBenoît Thébaudeau val = (readl(®s->gpio_psr) >> gpio) & 0x01; 120c4ea1424SStefano Babic 121365d6070SJoe Hershberger return val; 122c4ea1424SStefano Babic } 123d8e0ca85SStefano Babic 124365d6070SJoe Hershberger int gpio_request(unsigned gpio, const char *label) 125d8e0ca85SStefano Babic { 126be282554SVikram Narayanan unsigned int port = GPIO_TO_PORT(gpio); 127d8e0ca85SStefano Babic if (port >= ARRAY_SIZE(gpio_ports)) 128365d6070SJoe Hershberger return -1; 129d8e0ca85SStefano Babic return 0; 130d8e0ca85SStefano Babic } 131d8e0ca85SStefano Babic 132365d6070SJoe Hershberger int gpio_free(unsigned gpio) 133d8e0ca85SStefano Babic { 134365d6070SJoe Hershberger return 0; 135d8e0ca85SStefano Babic } 136d8e0ca85SStefano Babic 137365d6070SJoe Hershberger int gpio_direction_input(unsigned gpio) 138d8e0ca85SStefano Babic { 139365d6070SJoe Hershberger return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN); 140d8e0ca85SStefano Babic } 141d8e0ca85SStefano Babic 142365d6070SJoe Hershberger int gpio_direction_output(unsigned gpio, int value) 143d8e0ca85SStefano Babic { 14404c79cbdSDirk Behme int ret = gpio_set_value(gpio, value); 145d8e0ca85SStefano Babic 146d8e0ca85SStefano Babic if (ret < 0) 147d8e0ca85SStefano Babic return ret; 148d8e0ca85SStefano Babic 14904c79cbdSDirk Behme return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT); 150d8e0ca85SStefano Babic } 151441d0cffSSimon Glass #endif 152441d0cffSSimon Glass 153441d0cffSSimon Glass #ifdef CONFIG_DM_GPIO 154*99c0ae16SPeng Fan #include <fdtdec.h> 155*99c0ae16SPeng Fan DECLARE_GLOBAL_DATA_PTR; 156*99c0ae16SPeng Fan 157441d0cffSSimon Glass static int mxc_gpio_is_output(struct gpio_regs *regs, int offset) 158441d0cffSSimon Glass { 159441d0cffSSimon Glass u32 val; 160441d0cffSSimon Glass 161441d0cffSSimon Glass val = readl(®s->gpio_dir); 162441d0cffSSimon Glass 163441d0cffSSimon Glass return val & (1 << offset) ? 1 : 0; 164441d0cffSSimon Glass } 165441d0cffSSimon Glass 166441d0cffSSimon Glass static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset, 167441d0cffSSimon Glass enum mxc_gpio_direction direction) 168441d0cffSSimon Glass { 169441d0cffSSimon Glass u32 l; 170441d0cffSSimon Glass 171441d0cffSSimon Glass l = readl(®s->gpio_dir); 172441d0cffSSimon Glass 173441d0cffSSimon Glass switch (direction) { 174441d0cffSSimon Glass case MXC_GPIO_DIRECTION_OUT: 175441d0cffSSimon Glass l |= 1 << offset; 176441d0cffSSimon Glass break; 177441d0cffSSimon Glass case MXC_GPIO_DIRECTION_IN: 178441d0cffSSimon Glass l &= ~(1 << offset); 179441d0cffSSimon Glass } 180441d0cffSSimon Glass writel(l, ®s->gpio_dir); 181441d0cffSSimon Glass } 182441d0cffSSimon Glass 183441d0cffSSimon Glass static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset, 184441d0cffSSimon Glass int value) 185441d0cffSSimon Glass { 186441d0cffSSimon Glass u32 l; 187441d0cffSSimon Glass 188441d0cffSSimon Glass l = readl(®s->gpio_dr); 189441d0cffSSimon Glass if (value) 190441d0cffSSimon Glass l |= 1 << offset; 191441d0cffSSimon Glass else 192441d0cffSSimon Glass l &= ~(1 << offset); 193441d0cffSSimon Glass writel(l, ®s->gpio_dr); 194441d0cffSSimon Glass } 195441d0cffSSimon Glass 196441d0cffSSimon Glass static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset) 197441d0cffSSimon Glass { 198441d0cffSSimon Glass return (readl(®s->gpio_psr) >> offset) & 0x01; 199441d0cffSSimon Glass } 200441d0cffSSimon Glass 201441d0cffSSimon Glass /* set GPIO pin 'gpio' as an input */ 202441d0cffSSimon Glass static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset) 203441d0cffSSimon Glass { 204441d0cffSSimon Glass struct mxc_bank_info *bank = dev_get_priv(dev); 205441d0cffSSimon Glass 206441d0cffSSimon Glass /* Configure GPIO direction as input. */ 207441d0cffSSimon Glass mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN); 208441d0cffSSimon Glass 209441d0cffSSimon Glass return 0; 210441d0cffSSimon Glass } 211441d0cffSSimon Glass 212441d0cffSSimon Glass /* set GPIO pin 'gpio' as an output, with polarity 'value' */ 213441d0cffSSimon Glass static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset, 214441d0cffSSimon Glass int value) 215441d0cffSSimon Glass { 216441d0cffSSimon Glass struct mxc_bank_info *bank = dev_get_priv(dev); 217441d0cffSSimon Glass 218441d0cffSSimon Glass /* Configure GPIO output value. */ 219441d0cffSSimon Glass mxc_gpio_bank_set_value(bank->regs, offset, value); 220441d0cffSSimon Glass 221441d0cffSSimon Glass /* Configure GPIO direction as output. */ 222441d0cffSSimon Glass mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT); 223441d0cffSSimon Glass 224441d0cffSSimon Glass return 0; 225441d0cffSSimon Glass } 226441d0cffSSimon Glass 227441d0cffSSimon Glass /* read GPIO IN value of pin 'gpio' */ 228441d0cffSSimon Glass static int mxc_gpio_get_value(struct udevice *dev, unsigned offset) 229441d0cffSSimon Glass { 230441d0cffSSimon Glass struct mxc_bank_info *bank = dev_get_priv(dev); 231441d0cffSSimon Glass 232441d0cffSSimon Glass return mxc_gpio_bank_get_value(bank->regs, offset); 233441d0cffSSimon Glass } 234441d0cffSSimon Glass 235441d0cffSSimon Glass /* write GPIO OUT value to pin 'gpio' */ 236441d0cffSSimon Glass static int mxc_gpio_set_value(struct udevice *dev, unsigned offset, 237441d0cffSSimon Glass int value) 238441d0cffSSimon Glass { 239441d0cffSSimon Glass struct mxc_bank_info *bank = dev_get_priv(dev); 240441d0cffSSimon Glass 241441d0cffSSimon Glass mxc_gpio_bank_set_value(bank->regs, offset, value); 242441d0cffSSimon Glass 243441d0cffSSimon Glass return 0; 244441d0cffSSimon Glass } 245441d0cffSSimon Glass 246441d0cffSSimon Glass static int mxc_gpio_get_function(struct udevice *dev, unsigned offset) 247441d0cffSSimon Glass { 248441d0cffSSimon Glass struct mxc_bank_info *bank = dev_get_priv(dev); 249441d0cffSSimon Glass 250441d0cffSSimon Glass /* GPIOF_FUNC is not implemented yet */ 251441d0cffSSimon Glass if (mxc_gpio_is_output(bank->regs, offset)) 252441d0cffSSimon Glass return GPIOF_OUTPUT; 253441d0cffSSimon Glass else 254441d0cffSSimon Glass return GPIOF_INPUT; 255441d0cffSSimon Glass } 256441d0cffSSimon Glass 257441d0cffSSimon Glass static const struct dm_gpio_ops gpio_mxc_ops = { 258441d0cffSSimon Glass .direction_input = mxc_gpio_direction_input, 259441d0cffSSimon Glass .direction_output = mxc_gpio_direction_output, 260441d0cffSSimon Glass .get_value = mxc_gpio_get_value, 261441d0cffSSimon Glass .set_value = mxc_gpio_set_value, 262441d0cffSSimon Glass .get_function = mxc_gpio_get_function, 263441d0cffSSimon Glass }; 264441d0cffSSimon Glass 265441d0cffSSimon Glass static int mxc_gpio_probe(struct udevice *dev) 266441d0cffSSimon Glass { 267441d0cffSSimon Glass struct mxc_bank_info *bank = dev_get_priv(dev); 268441d0cffSSimon Glass struct mxc_gpio_plat *plat = dev_get_platdata(dev); 269441d0cffSSimon Glass struct gpio_dev_priv *uc_priv = dev->uclass_priv; 270441d0cffSSimon Glass int banknum; 271441d0cffSSimon Glass char name[18], *str; 272441d0cffSSimon Glass 273637a7693SPeng Fan banknum = plat->bank_index; 274441d0cffSSimon Glass sprintf(name, "GPIO%d_", banknum + 1); 275441d0cffSSimon Glass str = strdup(name); 276441d0cffSSimon Glass if (!str) 277441d0cffSSimon Glass return -ENOMEM; 278441d0cffSSimon Glass uc_priv->bank_name = str; 279441d0cffSSimon Glass uc_priv->gpio_count = GPIO_PER_BANK; 280441d0cffSSimon Glass bank->regs = plat->regs; 281441d0cffSSimon Glass 282441d0cffSSimon Glass return 0; 283441d0cffSSimon Glass } 284441d0cffSSimon Glass 285*99c0ae16SPeng Fan static int mxc_gpio_bind(struct udevice *dev) 286*99c0ae16SPeng Fan { 287*99c0ae16SPeng Fan struct mxc_gpio_plat *plat = dev->platdata; 288*99c0ae16SPeng Fan fdt_addr_t addr; 289*99c0ae16SPeng Fan 290*99c0ae16SPeng Fan /* 291*99c0ae16SPeng Fan * If platdata already exsits, directly return. 292*99c0ae16SPeng Fan * Actually only when DT is not supported, platdata 293*99c0ae16SPeng Fan * is statically initialized in U_BOOT_DEVICES.Here 294*99c0ae16SPeng Fan * will return. 295*99c0ae16SPeng Fan */ 296*99c0ae16SPeng Fan if (plat) 297*99c0ae16SPeng Fan return 0; 298*99c0ae16SPeng Fan 299*99c0ae16SPeng Fan addr = dev_get_addr(dev); 300*99c0ae16SPeng Fan if (addr == FDT_ADDR_T_NONE) 301*99c0ae16SPeng Fan return -ENODEV; 302*99c0ae16SPeng Fan 303*99c0ae16SPeng Fan /* 304*99c0ae16SPeng Fan * TODO: 305*99c0ae16SPeng Fan * When every board is converted to driver model and DT is supported, 306*99c0ae16SPeng Fan * this can be done by auto-alloc feature, but not using calloc 307*99c0ae16SPeng Fan * to alloc memory for platdata. 308*99c0ae16SPeng Fan */ 309*99c0ae16SPeng Fan plat = calloc(1, sizeof(*plat)); 310*99c0ae16SPeng Fan if (!plat) 311*99c0ae16SPeng Fan return -ENOMEM; 312*99c0ae16SPeng Fan 313*99c0ae16SPeng Fan plat->regs = (struct gpio_regs *)addr; 314*99c0ae16SPeng Fan plat->bank_index = dev->req_seq; 315*99c0ae16SPeng Fan dev->platdata = plat; 316*99c0ae16SPeng Fan 317*99c0ae16SPeng Fan return 0; 318*99c0ae16SPeng Fan } 319*99c0ae16SPeng Fan 320*99c0ae16SPeng Fan static const struct udevice_id mxc_gpio_ids[] = { 321*99c0ae16SPeng Fan { .compatible = "fsl,imx35-gpio" }, 322*99c0ae16SPeng Fan { } 323*99c0ae16SPeng Fan }; 324*99c0ae16SPeng Fan 325441d0cffSSimon Glass U_BOOT_DRIVER(gpio_mxc) = { 326441d0cffSSimon Glass .name = "gpio_mxc", 327441d0cffSSimon Glass .id = UCLASS_GPIO, 328441d0cffSSimon Glass .ops = &gpio_mxc_ops, 329441d0cffSSimon Glass .probe = mxc_gpio_probe, 330441d0cffSSimon Glass .priv_auto_alloc_size = sizeof(struct mxc_bank_info), 331*99c0ae16SPeng Fan .of_match = mxc_gpio_ids, 332*99c0ae16SPeng Fan .bind = mxc_gpio_bind, 333*99c0ae16SPeng Fan }; 334*99c0ae16SPeng Fan 335*99c0ae16SPeng Fan #ifndef CONFIG_OF_CONTROL 336*99c0ae16SPeng Fan static const struct mxc_gpio_plat mxc_plat[] = { 337*99c0ae16SPeng Fan { 0, (struct gpio_regs *)GPIO1_BASE_ADDR }, 338*99c0ae16SPeng Fan { 1, (struct gpio_regs *)GPIO2_BASE_ADDR }, 339*99c0ae16SPeng Fan { 2, (struct gpio_regs *)GPIO3_BASE_ADDR }, 340*99c0ae16SPeng Fan #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ 341*99c0ae16SPeng Fan defined(CONFIG_MX53) || defined(CONFIG_MX6) 342*99c0ae16SPeng Fan { 3, (struct gpio_regs *)GPIO4_BASE_ADDR }, 343*99c0ae16SPeng Fan #endif 344*99c0ae16SPeng Fan #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) 345*99c0ae16SPeng Fan { 4, (struct gpio_regs *)GPIO5_BASE_ADDR }, 346*99c0ae16SPeng Fan { 5, (struct gpio_regs *)GPIO6_BASE_ADDR }, 347*99c0ae16SPeng Fan #endif 348*99c0ae16SPeng Fan #if defined(CONFIG_MX53) || defined(CONFIG_MX6) 349*99c0ae16SPeng Fan { 6, (struct gpio_regs *)GPIO7_BASE_ADDR }, 350*99c0ae16SPeng Fan #endif 351441d0cffSSimon Glass }; 352441d0cffSSimon Glass 353441d0cffSSimon Glass U_BOOT_DEVICES(mxc_gpios) = { 354441d0cffSSimon Glass { "gpio_mxc", &mxc_plat[0] }, 355441d0cffSSimon Glass { "gpio_mxc", &mxc_plat[1] }, 356441d0cffSSimon Glass { "gpio_mxc", &mxc_plat[2] }, 357441d0cffSSimon Glass #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ 358441d0cffSSimon Glass defined(CONFIG_MX53) || defined(CONFIG_MX6) 359441d0cffSSimon Glass { "gpio_mxc", &mxc_plat[3] }, 360441d0cffSSimon Glass #endif 361441d0cffSSimon Glass #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) 362441d0cffSSimon Glass { "gpio_mxc", &mxc_plat[4] }, 363441d0cffSSimon Glass { "gpio_mxc", &mxc_plat[5] }, 364441d0cffSSimon Glass #endif 365441d0cffSSimon Glass #if defined(CONFIG_MX53) || defined(CONFIG_MX6) 366441d0cffSSimon Glass { "gpio_mxc", &mxc_plat[6] }, 367441d0cffSSimon Glass #endif 368441d0cffSSimon Glass }; 369441d0cffSSimon Glass #endif 370*99c0ae16SPeng Fan #endif 371