1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw> 4 * Copyright (C) 2011 Missing Link Electronics 5 * Joachim Foerster <joachim@missinglinkelectronics.com> 6 */ 7 #include <common.h> 8 #include <dm.h> 9 #include <errno.h> 10 #include <malloc.h> 11 #include <fdtdec.h> 12 #include <asm/io.h> 13 #include <asm/gpio.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 struct altera_pio_regs { 18 u32 data; /* Data register */ 19 u32 direction; /* Direction register */ 20 }; 21 22 struct altera_pio_platdata { 23 struct altera_pio_regs *regs; 24 int gpio_count; 25 const char *bank_name; 26 }; 27 28 static int altera_pio_direction_input(struct udevice *dev, unsigned pin) 29 { 30 struct altera_pio_platdata *plat = dev_get_platdata(dev); 31 struct altera_pio_regs *const regs = plat->regs; 32 33 clrbits_le32(®s->direction, 1 << pin); 34 35 return 0; 36 } 37 38 static int altera_pio_direction_output(struct udevice *dev, unsigned pin, 39 int val) 40 { 41 struct altera_pio_platdata *plat = dev_get_platdata(dev); 42 struct altera_pio_regs *const regs = plat->regs; 43 44 if (val) 45 setbits_le32(®s->data, 1 << pin); 46 else 47 clrbits_le32(®s->data, 1 << pin); 48 /* change the data first, then the direction. to avoid glitch */ 49 setbits_le32(®s->direction, 1 << pin); 50 51 return 0; 52 } 53 54 static int altera_pio_get_value(struct udevice *dev, unsigned pin) 55 { 56 struct altera_pio_platdata *plat = dev_get_platdata(dev); 57 struct altera_pio_regs *const regs = plat->regs; 58 59 return !!(readl(®s->data) & (1 << pin)); 60 } 61 62 63 static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val) 64 { 65 struct altera_pio_platdata *plat = dev_get_platdata(dev); 66 struct altera_pio_regs *const regs = plat->regs; 67 68 if (val) 69 setbits_le32(®s->data, 1 << pin); 70 else 71 clrbits_le32(®s->data, 1 << pin); 72 73 return 0; 74 } 75 76 static int altera_pio_probe(struct udevice *dev) 77 { 78 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 79 struct altera_pio_platdata *plat = dev_get_platdata(dev); 80 81 uc_priv->gpio_count = plat->gpio_count; 82 uc_priv->bank_name = plat->bank_name; 83 84 return 0; 85 } 86 87 static int altera_pio_ofdata_to_platdata(struct udevice *dev) 88 { 89 struct altera_pio_platdata *plat = dev_get_platdata(dev); 90 91 plat->regs = map_physmem(devfdt_get_addr(dev), 92 sizeof(struct altera_pio_regs), 93 MAP_NOCACHE); 94 plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 95 "altr,gpio-bank-width", 32); 96 plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), 97 "gpio-bank-name", NULL); 98 99 return 0; 100 } 101 102 static const struct dm_gpio_ops altera_pio_ops = { 103 .direction_input = altera_pio_direction_input, 104 .direction_output = altera_pio_direction_output, 105 .get_value = altera_pio_get_value, 106 .set_value = altera_pio_set_value, 107 }; 108 109 static const struct udevice_id altera_pio_ids[] = { 110 { .compatible = "altr,pio-1.0" }, 111 { } 112 }; 113 114 U_BOOT_DRIVER(altera_pio) = { 115 .name = "altera_pio", 116 .id = UCLASS_GPIO, 117 .of_match = altera_pio_ids, 118 .ops = &altera_pio_ops, 119 .ofdata_to_platdata = altera_pio_ofdata_to_platdata, 120 .platdata_auto_alloc_size = sizeof(struct altera_pio_platdata), 121 .probe = altera_pio_probe, 122 }; 123