183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 22c62c56aSWenyou Yang /* 32c62c56aSWenyou Yang * Atmel PIO4 device driver 42c62c56aSWenyou Yang * 52c62c56aSWenyou Yang * Copyright (C) 2015 Atmel Corporation 62c62c56aSWenyou Yang * Wenyou.Yang <wenyou.yang@atmel.com> 72c62c56aSWenyou Yang */ 82c62c56aSWenyou Yang #include <common.h> 9ee3311dbSWenyou Yang #include <clk.h> 102c62c56aSWenyou Yang #include <dm.h> 11ee3311dbSWenyou Yang #include <fdtdec.h> 122c62c56aSWenyou Yang #include <asm/arch/hardware.h> 13ee3311dbSWenyou Yang #include <asm/gpio.h> 142c62c56aSWenyou Yang #include <mach/gpio.h> 152c62c56aSWenyou Yang #include <mach/atmel_pio4.h> 162c62c56aSWenyou Yang 17ee3311dbSWenyou Yang DECLARE_GLOBAL_DATA_PTR; 18ee3311dbSWenyou Yang 192c62c56aSWenyou Yang static struct atmel_pio4_port *atmel_pio4_port_base(u32 port) 202c62c56aSWenyou Yang { 212c62c56aSWenyou Yang struct atmel_pio4_port *base = NULL; 222c62c56aSWenyou Yang 232c62c56aSWenyou Yang switch (port) { 242c62c56aSWenyou Yang case AT91_PIO_PORTA: 252c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA; 262c62c56aSWenyou Yang break; 272c62c56aSWenyou Yang case AT91_PIO_PORTB: 282c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB; 292c62c56aSWenyou Yang break; 302c62c56aSWenyou Yang case AT91_PIO_PORTC: 312c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC; 322c62c56aSWenyou Yang break; 332c62c56aSWenyou Yang case AT91_PIO_PORTD: 342c62c56aSWenyou Yang base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD; 352c62c56aSWenyou Yang break; 362c62c56aSWenyou Yang default: 372c62c56aSWenyou Yang printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n", 382c62c56aSWenyou Yang port); 392c62c56aSWenyou Yang break; 402c62c56aSWenyou Yang } 412c62c56aSWenyou Yang 422c62c56aSWenyou Yang return base; 432c62c56aSWenyou Yang } 442c62c56aSWenyou Yang 452c62c56aSWenyou Yang static int atmel_pio4_config_io_func(u32 port, u32 pin, 46*8ee54672SLudovic Desroches u32 func, u32 config) 472c62c56aSWenyou Yang { 482c62c56aSWenyou Yang struct atmel_pio4_port *port_base; 492c62c56aSWenyou Yang u32 reg, mask; 502c62c56aSWenyou Yang 5146ed9381SWenyou Yang if (pin >= ATMEL_PIO_NPINS_PER_BANK) 527c84319aSSimon Glass return -EINVAL; 532c62c56aSWenyou Yang 542c62c56aSWenyou Yang port_base = atmel_pio4_port_base(port); 552c62c56aSWenyou Yang if (!port_base) 567c84319aSSimon Glass return -EINVAL; 572c62c56aSWenyou Yang 582c62c56aSWenyou Yang mask = 1 << pin; 592c62c56aSWenyou Yang reg = func; 60*8ee54672SLudovic Desroches reg |= config; 612c62c56aSWenyou Yang 622c62c56aSWenyou Yang writel(mask, &port_base->mskr); 632c62c56aSWenyou Yang writel(reg, &port_base->cfgr); 642c62c56aSWenyou Yang 652c62c56aSWenyou Yang return 0; 662c62c56aSWenyou Yang } 672c62c56aSWenyou Yang 68*8ee54672SLudovic Desroches int atmel_pio4_set_gpio(u32 port, u32 pin, u32 config) 692c62c56aSWenyou Yang { 702c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 7146ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_GPIO, 72*8ee54672SLudovic Desroches config); 732c62c56aSWenyou Yang } 742c62c56aSWenyou Yang 75*8ee54672SLudovic Desroches int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 config) 762c62c56aSWenyou Yang { 772c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 7846ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_A, 79*8ee54672SLudovic Desroches config); 802c62c56aSWenyou Yang } 812c62c56aSWenyou Yang 82*8ee54672SLudovic Desroches int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 config) 832c62c56aSWenyou Yang { 842c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 8546ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_B, 86*8ee54672SLudovic Desroches config); 872c62c56aSWenyou Yang } 882c62c56aSWenyou Yang 89*8ee54672SLudovic Desroches int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 config) 902c62c56aSWenyou Yang { 912c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 9246ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_C, 93*8ee54672SLudovic Desroches config); 942c62c56aSWenyou Yang } 952c62c56aSWenyou Yang 96*8ee54672SLudovic Desroches int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 config) 972c62c56aSWenyou Yang { 982c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 9946ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_D, 100*8ee54672SLudovic Desroches config); 1012c62c56aSWenyou Yang } 1022c62c56aSWenyou Yang 103*8ee54672SLudovic Desroches int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 config) 1042c62c56aSWenyou Yang { 1052c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 10646ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_E, 107*8ee54672SLudovic Desroches config); 1082c62c56aSWenyou Yang } 1092c62c56aSWenyou Yang 110*8ee54672SLudovic Desroches int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 config) 1112c62c56aSWenyou Yang { 1122c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 11346ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_F, 114*8ee54672SLudovic Desroches config); 1152c62c56aSWenyou Yang } 1162c62c56aSWenyou Yang 117*8ee54672SLudovic Desroches int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 config) 1182c62c56aSWenyou Yang { 1192c62c56aSWenyou Yang return atmel_pio4_config_io_func(port, pin, 12046ed9381SWenyou Yang ATMEL_PIO_CFGR_FUNC_PERIPH_G, 121*8ee54672SLudovic Desroches config); 1222c62c56aSWenyou Yang } 1232c62c56aSWenyou Yang 1242c62c56aSWenyou Yang int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value) 1252c62c56aSWenyou Yang { 1262c62c56aSWenyou Yang struct atmel_pio4_port *port_base; 1272c62c56aSWenyou Yang u32 reg, mask; 1282c62c56aSWenyou Yang 12946ed9381SWenyou Yang if (pin >= ATMEL_PIO_NPINS_PER_BANK) 1307c84319aSSimon Glass return -EINVAL; 1312c62c56aSWenyou Yang 1322c62c56aSWenyou Yang port_base = atmel_pio4_port_base(port); 1332c62c56aSWenyou Yang if (!port_base) 1347c84319aSSimon Glass return -EINVAL; 1352c62c56aSWenyou Yang 1362c62c56aSWenyou Yang mask = 0x01 << pin; 13746ed9381SWenyou Yang reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK; 1382c62c56aSWenyou Yang 1392c62c56aSWenyou Yang writel(mask, &port_base->mskr); 1402c62c56aSWenyou Yang writel(reg, &port_base->cfgr); 1412c62c56aSWenyou Yang 1422c62c56aSWenyou Yang if (value) 1432c62c56aSWenyou Yang writel(mask, &port_base->sodr); 1442c62c56aSWenyou Yang else 1452c62c56aSWenyou Yang writel(mask, &port_base->codr); 1462c62c56aSWenyou Yang 1472c62c56aSWenyou Yang return 0; 1482c62c56aSWenyou Yang } 1492c62c56aSWenyou Yang 1502c62c56aSWenyou Yang int atmel_pio4_get_pio_input(u32 port, u32 pin) 1512c62c56aSWenyou Yang { 1522c62c56aSWenyou Yang struct atmel_pio4_port *port_base; 1532c62c56aSWenyou Yang u32 reg, mask; 1542c62c56aSWenyou Yang 15546ed9381SWenyou Yang if (pin >= ATMEL_PIO_NPINS_PER_BANK) 1567c84319aSSimon Glass return -EINVAL; 1572c62c56aSWenyou Yang 1582c62c56aSWenyou Yang port_base = atmel_pio4_port_base(port); 1592c62c56aSWenyou Yang if (!port_base) 1607c84319aSSimon Glass return -EINVAL; 1612c62c56aSWenyou Yang 1622c62c56aSWenyou Yang mask = 0x01 << pin; 16346ed9381SWenyou Yang reg = ATMEL_PIO_CFGR_FUNC_GPIO; 1642c62c56aSWenyou Yang 1652c62c56aSWenyou Yang writel(mask, &port_base->mskr); 1662c62c56aSWenyou Yang writel(reg, &port_base->cfgr); 1672c62c56aSWenyou Yang 1682c62c56aSWenyou Yang return (readl(&port_base->pdsr) & mask) ? 1 : 0; 1692c62c56aSWenyou Yang } 1702c62c56aSWenyou Yang 1712c62c56aSWenyou Yang #ifdef CONFIG_DM_GPIO 172ee3311dbSWenyou Yang 173ee3311dbSWenyou Yang struct atmel_pioctrl_data { 174ee3311dbSWenyou Yang u32 nbanks; 175ee3311dbSWenyou Yang }; 176ee3311dbSWenyou Yang 177ee3311dbSWenyou Yang struct atmel_pio4_platdata { 178ee3311dbSWenyou Yang struct atmel_pio4_port *reg_base; 179ee3311dbSWenyou Yang }; 180ee3311dbSWenyou Yang 181ee3311dbSWenyou Yang static struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev, 182ee3311dbSWenyou Yang u32 bank) 183ee3311dbSWenyou Yang { 184ee3311dbSWenyou Yang struct atmel_pio4_platdata *plat = dev_get_platdata(dev); 185ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = 186ee3311dbSWenyou Yang (struct atmel_pio4_port *)((u32)plat->reg_base + 187ee3311dbSWenyou Yang ATMEL_PIO_BANK_OFFSET * bank); 188ee3311dbSWenyou Yang 189ee3311dbSWenyou Yang return port_base; 190ee3311dbSWenyou Yang } 191ee3311dbSWenyou Yang 1922c62c56aSWenyou Yang static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset) 1932c62c56aSWenyou Yang { 194ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 195ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 196ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 197ee3311dbSWenyou Yang u32 mask = BIT(line); 1982c62c56aSWenyou Yang 1992c62c56aSWenyou Yang writel(mask, &port_base->mskr); 200ee3311dbSWenyou Yang 201ee3311dbSWenyou Yang clrbits_le32(&port_base->cfgr, 202ee3311dbSWenyou Yang ATMEL_PIO_CFGR_FUNC_MASK | ATMEL_PIO_DIR_MASK); 2032c62c56aSWenyou Yang 2042c62c56aSWenyou Yang return 0; 2052c62c56aSWenyou Yang } 2062c62c56aSWenyou Yang 2072c62c56aSWenyou Yang static int atmel_pio4_direction_output(struct udevice *dev, 2082c62c56aSWenyou Yang unsigned offset, int value) 2092c62c56aSWenyou Yang { 210ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 211ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 212ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 213ee3311dbSWenyou Yang u32 mask = BIT(line); 2142c62c56aSWenyou Yang 2152c62c56aSWenyou Yang writel(mask, &port_base->mskr); 216ee3311dbSWenyou Yang 217ee3311dbSWenyou Yang clrsetbits_le32(&port_base->cfgr, 218ee3311dbSWenyou Yang ATMEL_PIO_CFGR_FUNC_MASK, ATMEL_PIO_DIR_MASK); 2192c62c56aSWenyou Yang 2202c62c56aSWenyou Yang if (value) 2212c62c56aSWenyou Yang writel(mask, &port_base->sodr); 2222c62c56aSWenyou Yang else 2232c62c56aSWenyou Yang writel(mask, &port_base->codr); 2242c62c56aSWenyou Yang 2252c62c56aSWenyou Yang return 0; 2262c62c56aSWenyou Yang } 2272c62c56aSWenyou Yang 2282c62c56aSWenyou Yang static int atmel_pio4_get_value(struct udevice *dev, unsigned offset) 2292c62c56aSWenyou Yang { 230ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 231ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 232ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 233ee3311dbSWenyou Yang u32 mask = BIT(line); 2342c62c56aSWenyou Yang 2352c62c56aSWenyou Yang return (readl(&port_base->pdsr) & mask) ? 1 : 0; 2362c62c56aSWenyou Yang } 2372c62c56aSWenyou Yang 2382c62c56aSWenyou Yang static int atmel_pio4_set_value(struct udevice *dev, 2392c62c56aSWenyou Yang unsigned offset, int value) 2402c62c56aSWenyou Yang { 241ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 242ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 243ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 244ee3311dbSWenyou Yang u32 mask = BIT(line); 2452c62c56aSWenyou Yang 2462c62c56aSWenyou Yang if (value) 2472c62c56aSWenyou Yang writel(mask, &port_base->sodr); 2482c62c56aSWenyou Yang else 2492c62c56aSWenyou Yang writel(mask, &port_base->codr); 2502c62c56aSWenyou Yang 2512c62c56aSWenyou Yang return 0; 2522c62c56aSWenyou Yang } 2532c62c56aSWenyou Yang 2542c62c56aSWenyou Yang static int atmel_pio4_get_function(struct udevice *dev, unsigned offset) 2552c62c56aSWenyou Yang { 256ee3311dbSWenyou Yang u32 bank = ATMEL_PIO_BANK(offset); 257ee3311dbSWenyou Yang u32 line = ATMEL_PIO_LINE(offset); 258ee3311dbSWenyou Yang struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank); 259ee3311dbSWenyou Yang u32 mask = BIT(line); 2602c62c56aSWenyou Yang 2612c62c56aSWenyou Yang writel(mask, &port_base->mskr); 2622c62c56aSWenyou Yang 2632c62c56aSWenyou Yang return (readl(&port_base->cfgr) & 26446ed9381SWenyou Yang ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT; 2652c62c56aSWenyou Yang } 2662c62c56aSWenyou Yang 2672c62c56aSWenyou Yang static const struct dm_gpio_ops atmel_pio4_ops = { 2682c62c56aSWenyou Yang .direction_input = atmel_pio4_direction_input, 2692c62c56aSWenyou Yang .direction_output = atmel_pio4_direction_output, 2702c62c56aSWenyou Yang .get_value = atmel_pio4_get_value, 2712c62c56aSWenyou Yang .set_value = atmel_pio4_set_value, 2722c62c56aSWenyou Yang .get_function = atmel_pio4_get_function, 2732c62c56aSWenyou Yang }; 2742c62c56aSWenyou Yang 275ee3311dbSWenyou Yang static int atmel_pio4_bind(struct udevice *dev) 276ee3311dbSWenyou Yang { 27779fc0c78SSimon Glass return dm_scan_fdt_dev(dev); 278ee3311dbSWenyou Yang } 279ee3311dbSWenyou Yang 2802c62c56aSWenyou Yang static int atmel_pio4_probe(struct udevice *dev) 2812c62c56aSWenyou Yang { 282ee3311dbSWenyou Yang struct atmel_pio4_platdata *plat = dev_get_platdata(dev); 2832c62c56aSWenyou Yang struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 284ee3311dbSWenyou Yang struct atmel_pioctrl_data *pioctrl_data; 285ee3311dbSWenyou Yang struct clk clk; 286ee3311dbSWenyou Yang fdt_addr_t addr_base; 287ee3311dbSWenyou Yang u32 nbanks; 288ee3311dbSWenyou Yang int ret; 2892c62c56aSWenyou Yang 290ee3311dbSWenyou Yang ret = clk_get_by_index(dev, 0, &clk); 291ee3311dbSWenyou Yang if (ret) 292ee3311dbSWenyou Yang return ret; 293ee3311dbSWenyou Yang 294ee3311dbSWenyou Yang ret = clk_enable(&clk); 295ee3311dbSWenyou Yang if (ret) 296ee3311dbSWenyou Yang return ret; 297ee3311dbSWenyou Yang 298ee3311dbSWenyou Yang clk_free(&clk); 299ee3311dbSWenyou Yang 300a821c4afSSimon Glass addr_base = devfdt_get_addr(dev); 301ee3311dbSWenyou Yang if (addr_base == FDT_ADDR_T_NONE) 302ee3311dbSWenyou Yang return -EINVAL; 303ee3311dbSWenyou Yang 304ee3311dbSWenyou Yang plat->reg_base = (struct atmel_pio4_port *)addr_base; 305ee3311dbSWenyou Yang 306ee3311dbSWenyou Yang pioctrl_data = (struct atmel_pioctrl_data *)dev_get_driver_data(dev); 307ee3311dbSWenyou Yang nbanks = pioctrl_data->nbanks; 308ee3311dbSWenyou Yang 309e160f7d4SSimon Glass uc_priv->bank_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), 310e160f7d4SSimon Glass NULL); 311ee3311dbSWenyou Yang uc_priv->gpio_count = nbanks * ATMEL_PIO_NPINS_PER_BANK; 3122c62c56aSWenyou Yang 3132c62c56aSWenyou Yang return 0; 3142c62c56aSWenyou Yang } 3152c62c56aSWenyou Yang 316ee3311dbSWenyou Yang /* 317ee3311dbSWenyou Yang * The number of banks can be different from a SoC to another one. 318ee3311dbSWenyou Yang * We can have up to 16 banks. 319ee3311dbSWenyou Yang */ 320ee3311dbSWenyou Yang static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = { 321ee3311dbSWenyou Yang .nbanks = 4, 322ee3311dbSWenyou Yang }; 323ee3311dbSWenyou Yang 324ee3311dbSWenyou Yang static const struct udevice_id atmel_pio4_ids[] = { 325ee3311dbSWenyou Yang { 326ee3311dbSWenyou Yang .compatible = "atmel,sama5d2-gpio", 327ee3311dbSWenyou Yang .data = (ulong)&atmel_sama5d2_pioctrl_data, 328ee3311dbSWenyou Yang }, 329ee3311dbSWenyou Yang {} 330ee3311dbSWenyou Yang }; 331ee3311dbSWenyou Yang 3322c62c56aSWenyou Yang U_BOOT_DRIVER(gpio_atmel_pio4) = { 3332c62c56aSWenyou Yang .name = "gpio_atmel_pio4", 3342c62c56aSWenyou Yang .id = UCLASS_GPIO, 3352c62c56aSWenyou Yang .ops = &atmel_pio4_ops, 3362c62c56aSWenyou Yang .probe = atmel_pio4_probe, 337ee3311dbSWenyou Yang .bind = atmel_pio4_bind, 338ee3311dbSWenyou Yang .of_match = atmel_pio4_ids, 339ee3311dbSWenyou Yang .platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata), 3402c62c56aSWenyou Yang }; 341ee3311dbSWenyou Yang 3422c62c56aSWenyou Yang #endif 343