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