12c62c56aSWenyou Yang /* 22c62c56aSWenyou Yang * Atmel PIO4 device driver 32c62c56aSWenyou Yang * 42c62c56aSWenyou Yang * Copyright (C) 2015 Atmel Corporation 52c62c56aSWenyou Yang * Wenyou.Yang <wenyou.yang@atmel.com> 62c62c56aSWenyou Yang * 72c62c56aSWenyou Yang * SPDX-License-Identifier: GPL-2.0+ 82c62c56aSWenyou Yang */ 92c62c56aSWenyou Yang #include <common.h> 10ee3311dbSWenyou Yang #include <clk.h> 112c62c56aSWenyou Yang #include <dm.h> 12ee3311dbSWenyou Yang #include <fdtdec.h> 132c62c56aSWenyou Yang #include <asm/arch/hardware.h> 14ee3311dbSWenyou Yang #include <asm/gpio.h> 152c62c56aSWenyou Yang #include <mach/gpio.h> 162c62c56aSWenyou Yang #include <mach/atmel_pio4.h> 172c62c56aSWenyou Yang 18ee3311dbSWenyou Yang DECLARE_GLOBAL_DATA_PTR; 19ee3311dbSWenyou Yang 202c62c56aSWenyou Yang static struct atmel_pio4_port *atmel_pio4_port_base(u32 port) 212c62c56aSWenyou Yang { 222c62c56aSWenyou Yang struct atmel_pio4_port *base = NULL; 232c62c56aSWenyou Yang 242c62c56aSWenyou Yang switch (port) { 252c62c56aSWenyou Yang case AT91_PIO_PORTA: 262c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA; 272c62c56aSWenyou Yang break; 282c62c56aSWenyou Yang case AT91_PIO_PORTB: 292c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB; 302c62c56aSWenyou Yang break; 312c62c56aSWenyou Yang case AT91_PIO_PORTC: 322c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC; 332c62c56aSWenyou Yang break; 342c62c56aSWenyou Yang case AT91_PIO_PORTD: 352c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD; 362c62c56aSWenyou Yang break; 372c62c56aSWenyou Yang default: 382c62c56aSWenyou Yang printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n", 392c62c56aSWenyou Yang port); 402c62c56aSWenyou Yang break; 412c62c56aSWenyou Yang } 422c62c56aSWenyou Yang 432c62c56aSWenyou Yang return base; 442c62c56aSWenyou Yang } 452c62c56aSWenyou Yang 462c62c56aSWenyou Yang static int atmel_pio4_config_io_func(u32 port, u32 pin, 472c62c56aSWenyou Yang u32 func, u32 use_pullup) 482c62c56aSWenyou Yang { 492c62c56aSWenyou Yang struct atmel_pio4_port *port_base; 502c62c56aSWenyou Yang u32 reg, mask; 512c62c56aSWenyou Yang 5246ed9381SWenyou Yang if (pin >= ATMEL_PIO_NPINS_PER_BANK) 53*7c84319aSSimon Glass return -EINVAL; 542c62c56aSWenyou Yang 552c62c56aSWenyou Yang port_base = atmel_pio4_port_base(port); 562c62c56aSWenyou Yang if (!port_base) 57*7c84319aSSimon Glass return -EINVAL; 582c62c56aSWenyou Yang 592c62c56aSWenyou Yang mask = 1 << pin; 602c62c56aSWenyou Yang reg = func; 6146ed9381SWenyou Yang reg |= use_pullup ? ATMEL_PIO_PUEN_MASK : 0; 622c62c56aSWenyou Yang 632c62c56aSWenyou Yang writel(mask, &port_base->mskr); 642c62c56aSWenyou Yang writel(reg, &port_base->cfgr); 652c62c56aSWenyou Yang 662c62c56aSWenyou Yang return 0; 672c62c56aSWenyou Yang } 682c62c56aSWenyou Yang 692c62c56aSWenyou Yang int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup) 702c62c56aSWenyou Yang { 712c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 7246ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_GPIO, 732c62c56aSWenyou Yang use_pullup); 742c62c56aSWenyou Yang } 752c62c56aSWenyou Yang 762c62c56aSWenyou Yang int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup) 772c62c56aSWenyou Yang { 782c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 7946ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_A, 802c62c56aSWenyou Yang use_pullup); 812c62c56aSWenyou Yang } 822c62c56aSWenyou Yang 832c62c56aSWenyou Yang int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup) 842c62c56aSWenyou Yang { 852c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 8646ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_B, 872c62c56aSWenyou Yang use_pullup); 882c62c56aSWenyou Yang } 892c62c56aSWenyou Yang 902c62c56aSWenyou Yang int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup) 912c62c56aSWenyou Yang { 922c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 9346ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_C, 942c62c56aSWenyou Yang use_pullup); 952c62c56aSWenyou Yang } 962c62c56aSWenyou Yang 972c62c56aSWenyou Yang int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup) 982c62c56aSWenyou Yang { 992c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 10046ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_D, 1012c62c56aSWenyou Yang use_pullup); 1022c62c56aSWenyou Yang } 1032c62c56aSWenyou Yang 1042c62c56aSWenyou Yang int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup) 1052c62c56aSWenyou Yang { 1062c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 10746ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_E, 1082c62c56aSWenyou Yang use_pullup); 1092c62c56aSWenyou Yang } 1102c62c56aSWenyou Yang 1112c62c56aSWenyou Yang int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup) 1122c62c56aSWenyou Yang { 1132c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 11446ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_F, 1152c62c56aSWenyou Yang use_pullup); 1162c62c56aSWenyou Yang } 1172c62c56aSWenyou Yang 1182c62c56aSWenyou Yang int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup) 1192c62c56aSWenyou Yang { 1202c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 12146ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_G, 1222c62c56aSWenyou Yang use_pullup); 1232c62c56aSWenyou Yang } 1242c62c56aSWenyou Yang 1252c62c56aSWenyou Yang int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value) 1262c62c56aSWenyou Yang { 1272c62c56aSWenyou Yang struct atmel_pio4_port *port_base; 1282c62c56aSWenyou Yang u32 reg, mask; 1292c62c56aSWenyou Yang 13046ed9381SWenyou Yang if (pin >= ATMEL_PIO_NPINS_PER_BANK) 131*7c84319aSSimon Glass return -EINVAL; 1322c62c56aSWenyou Yang 1332c62c56aSWenyou Yang port_base = atmel_pio4_port_base(port); 1342c62c56aSWenyou Yang if (!port_base) 135*7c84319aSSimon Glass return -EINVAL; 1362c62c56aSWenyou Yang 1372c62c56aSWenyou Yang mask = 0x01 << pin; 13846ed9381SWenyou Yang reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK; 1392c62c56aSWenyou Yang 1402c62c56aSWenyou Yang writel(mask, &port_base->mskr); 1412c62c56aSWenyou Yang writel(reg, &port_base->cfgr); 1422c62c56aSWenyou Yang 1432c62c56aSWenyou Yang if (value) 1442c62c56aSWenyou Yang writel(mask, &port_base->sodr); 1452c62c56aSWenyou Yang else 1462c62c56aSWenyou Yang writel(mask, &port_base->codr); 1472c62c56aSWenyou Yang 1482c62c56aSWenyou Yang return 0; 1492c62c56aSWenyou Yang } 1502c62c56aSWenyou Yang 1512c62c56aSWenyou Yang int atmel_pio4_get_pio_input(u32 port, u32 pin) 1522c62c56aSWenyou Yang { 1532c62c56aSWenyou Yang struct atmel_pio4_port *port_base; 1542c62c56aSWenyou Yang u32 reg, mask; 1552c62c56aSWenyou Yang 15646ed9381SWenyou Yang if (pin >= ATMEL_PIO_NPINS_PER_BANK) 157*7c84319aSSimon Glass return -EINVAL; 1582c62c56aSWenyou Yang 1592c62c56aSWenyou Yang port_base = atmel_pio4_port_base(port); 1602c62c56aSWenyou Yang if (!port_base) 161*7c84319aSSimon Glass return -EINVAL; 1622c62c56aSWenyou Yang 1632c62c56aSWenyou Yang mask = 0x01 << pin; 16446ed9381SWenyou Yang reg = ATMEL_PIO_CFGR_FUNC_GPIO; 1652c62c56aSWenyou Yang 1662c62c56aSWenyou Yang writel(mask, &port_base->mskr); 1672c62c56aSWenyou Yang writel(reg, &port_base->cfgr); 1682c62c56aSWenyou Yang 1692c62c56aSWenyou Yang return (readl(&port_base->pdsr) & mask) ? 1 : 0; 1702c62c56aSWenyou Yang } 1712c62c56aSWenyou Yang 1722c62c56aSWenyou Yang #ifdef CONFIG_DM_GPIO 173ee3311dbSWenyou Yang 174ee3311dbSWenyou Yang struct atmel_pioctrl_data { 175ee3311dbSWenyou Yang u32 nbanks; 176ee3311dbSWenyou Yang }; 177ee3311dbSWenyou Yang 178ee3311dbSWenyou Yang struct atmel_pio4_platdata { 179ee3311dbSWenyou Yang struct atmel_pio4_port *reg_base; 180ee3311dbSWenyou Yang }; 181ee3311dbSWenyou Yang 182ee3311dbSWenyou Yang static struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev, 183ee3311dbSWenyou Yang u32 bank) 184ee3311dbSWenyou Yang { 185ee3311dbSWenyou Yang struct atmel_pio4_platdata *plat = dev_get_platdata(dev); 186ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = 187ee3311dbSWenyou Yang (struct atmel_pio4_port *)((u32)plat->reg_base + 188ee3311dbSWenyou Yang ATMEL_PIO_BANK_OFFSET * bank); 189ee3311dbSWenyou Yang 190ee3311dbSWenyou Yang return port_base; 191ee3311dbSWenyou Yang } 192ee3311dbSWenyou Yang 1932c62c56aSWenyou Yang static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset) 1942c62c56aSWenyou Yang { 195ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 196ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 197ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 198ee3311dbSWenyou Yang u32 mask = BIT(line); 1992c62c56aSWenyou Yang 2002c62c56aSWenyou Yang writel(mask, &port_base->mskr); 201ee3311dbSWenyou Yang 202ee3311dbSWenyou Yang clrbits_le32(&port_base->cfgr, 203ee3311dbSWenyou Yang ATMEL_PIO_CFGR_FUNC_MASK | ATMEL_PIO_DIR_MASK); 2042c62c56aSWenyou Yang 2052c62c56aSWenyou Yang return 0; 2062c62c56aSWenyou Yang } 2072c62c56aSWenyou Yang 2082c62c56aSWenyou Yang static int atmel_pio4_direction_output(struct udevice *dev, 2092c62c56aSWenyou Yang unsigned offset, int value) 2102c62c56aSWenyou Yang { 211ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 212ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 213ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 214ee3311dbSWenyou Yang u32 mask = BIT(line); 2152c62c56aSWenyou Yang 2162c62c56aSWenyou Yang writel(mask, &port_base->mskr); 217ee3311dbSWenyou Yang 218ee3311dbSWenyou Yang clrsetbits_le32(&port_base->cfgr, 219ee3311dbSWenyou Yang ATMEL_PIO_CFGR_FUNC_MASK, ATMEL_PIO_DIR_MASK); 2202c62c56aSWenyou Yang 2212c62c56aSWenyou Yang if (value) 2222c62c56aSWenyou Yang writel(mask, &port_base->sodr); 2232c62c56aSWenyou Yang else 2242c62c56aSWenyou Yang writel(mask, &port_base->codr); 2252c62c56aSWenyou Yang 2262c62c56aSWenyou Yang return 0; 2272c62c56aSWenyou Yang } 2282c62c56aSWenyou Yang 2292c62c56aSWenyou Yang static int atmel_pio4_get_value(struct udevice *dev, unsigned offset) 2302c62c56aSWenyou Yang { 231ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 232ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 233ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 234ee3311dbSWenyou Yang u32 mask = BIT(line); 2352c62c56aSWenyou Yang 2362c62c56aSWenyou Yang return (readl(&port_base->pdsr) & mask) ? 1 : 0; 2372c62c56aSWenyou Yang } 2382c62c56aSWenyou Yang 2392c62c56aSWenyou Yang static int atmel_pio4_set_value(struct udevice *dev, 2402c62c56aSWenyou Yang unsigned offset, int value) 2412c62c56aSWenyou Yang { 242ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 243ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 244ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 245ee3311dbSWenyou Yang u32 mask = BIT(line); 2462c62c56aSWenyou Yang 2472c62c56aSWenyou Yang if (value) 2482c62c56aSWenyou Yang writel(mask, &port_base->sodr); 2492c62c56aSWenyou Yang else 2502c62c56aSWenyou Yang writel(mask, &port_base->codr); 2512c62c56aSWenyou Yang 2522c62c56aSWenyou Yang return 0; 2532c62c56aSWenyou Yang } 2542c62c56aSWenyou Yang 2552c62c56aSWenyou Yang static int atmel_pio4_get_function(struct udevice *dev, unsigned offset) 2562c62c56aSWenyou Yang { 257ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 258ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 259ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 260ee3311dbSWenyou Yang u32 mask = BIT(line); 2612c62c56aSWenyou Yang 2622c62c56aSWenyou Yang writel(mask, &port_base->mskr); 2632c62c56aSWenyou Yang 2642c62c56aSWenyou Yang return (readl(&port_base->cfgr) & 26546ed9381SWenyou Yang ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT; 2662c62c56aSWenyou Yang } 2672c62c56aSWenyou Yang 2682c62c56aSWenyou Yang static const struct dm_gpio_ops atmel_pio4_ops = { 2692c62c56aSWenyou Yang .direction_input = atmel_pio4_direction_input, 2702c62c56aSWenyou Yang .direction_output = atmel_pio4_direction_output, 2712c62c56aSWenyou Yang .get_value = atmel_pio4_get_value, 2722c62c56aSWenyou Yang .set_value = atmel_pio4_set_value, 2732c62c56aSWenyou Yang .get_function = atmel_pio4_get_function, 2742c62c56aSWenyou Yang }; 2752c62c56aSWenyou Yang 276ee3311dbSWenyou Yang static int atmel_pio4_bind(struct udevice *dev) 277ee3311dbSWenyou Yang { 27879fc0c78SSimon Glass return dm_scan_fdt_dev(dev); 279ee3311dbSWenyou Yang } 280ee3311dbSWenyou Yang 2812c62c56aSWenyou Yang static int atmel_pio4_probe(struct udevice *dev) 2822c62c56aSWenyou Yang { 283ee3311dbSWenyou Yang struct atmel_pio4_platdata *plat = dev_get_platdata(dev); 2842c62c56aSWenyou Yang struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 285ee3311dbSWenyou Yang struct atmel_pioctrl_data *pioctrl_data; 286ee3311dbSWenyou Yang struct clk clk; 287ee3311dbSWenyou Yang fdt_addr_t addr_base; 288ee3311dbSWenyou Yang u32 nbanks; 289ee3311dbSWenyou Yang int ret; 2902c62c56aSWenyou Yang 291ee3311dbSWenyou Yang ret = clk_get_by_index(dev, 0, &clk); 292ee3311dbSWenyou Yang if (ret) 293ee3311dbSWenyou Yang return ret; 294ee3311dbSWenyou Yang 295ee3311dbSWenyou Yang ret = clk_enable(&clk); 296ee3311dbSWenyou Yang if (ret) 297ee3311dbSWenyou Yang return ret; 298ee3311dbSWenyou Yang 299ee3311dbSWenyou Yang clk_free(&clk); 300ee3311dbSWenyou Yang 301a821c4afSSimon Glass addr_base = devfdt_get_addr(dev); 302ee3311dbSWenyou Yang if (addr_base == FDT_ADDR_T_NONE) 303ee3311dbSWenyou Yang return -EINVAL; 304ee3311dbSWenyou Yang 305ee3311dbSWenyou Yang plat->reg_base = (struct atmel_pio4_port *)addr_base; 306ee3311dbSWenyou Yang 307ee3311dbSWenyou Yang pioctrl_data = (struct atmel_pioctrl_data *)dev_get_driver_data(dev); 308ee3311dbSWenyou Yang nbanks = pioctrl_data->nbanks; 309ee3311dbSWenyou Yang 310e160f7d4SSimon Glass uc_priv->bank_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), 311e160f7d4SSimon Glass NULL); 312ee3311dbSWenyou Yang uc_priv->gpio_count = nbanks * ATMEL_PIO_NPINS_PER_BANK; 3132c62c56aSWenyou Yang 3142c62c56aSWenyou Yang return 0; 3152c62c56aSWenyou Yang } 3162c62c56aSWenyou Yang 317ee3311dbSWenyou Yang /* 318ee3311dbSWenyou Yang * The number of banks can be different from a SoC to another one. 319ee3311dbSWenyou Yang * We can have up to 16 banks. 320ee3311dbSWenyou Yang */ 321ee3311dbSWenyou Yang static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = { 322ee3311dbSWenyou Yang .nbanks = 4, 323ee3311dbSWenyou Yang }; 324ee3311dbSWenyou Yang 325ee3311dbSWenyou Yang static const struct udevice_id atmel_pio4_ids[] = { 326ee3311dbSWenyou Yang { 327ee3311dbSWenyou Yang .compatible = "atmel,sama5d2-gpio", 328ee3311dbSWenyou Yang .data = (ulong)&atmel_sama5d2_pioctrl_data, 329ee3311dbSWenyou Yang }, 330ee3311dbSWenyou Yang {} 331ee3311dbSWenyou Yang }; 332ee3311dbSWenyou Yang 3332c62c56aSWenyou Yang U_BOOT_DRIVER(gpio_atmel_pio4) = { 3342c62c56aSWenyou Yang .name = "gpio_atmel_pio4", 3352c62c56aSWenyou Yang .id = UCLASS_GPIO, 3362c62c56aSWenyou Yang .ops = &atmel_pio4_ops, 3372c62c56aSWenyou Yang .probe = atmel_pio4_probe, 338ee3311dbSWenyou Yang .bind = atmel_pio4_bind, 339ee3311dbSWenyou Yang .of_match = atmel_pio4_ids, 340ee3311dbSWenyou Yang .platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata), 3412c62c56aSWenyou Yang }; 342ee3311dbSWenyou Yang 3432c62c56aSWenyou Yang #endif 344