1 /* 2 * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com> 3 * 4 * Derived from linux/arch/mips/bcm63xx/gpio.c: 5 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 6 * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org> 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <dm.h> 13 #include <errno.h> 14 #include <asm/gpio.h> 15 #include <asm/io.h> 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 struct bcm6345_gpio_priv { 20 void __iomem *reg_dirout; 21 void __iomem *reg_data; 22 }; 23 24 static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset) 25 { 26 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 27 28 return !!(readl_be(priv->reg_data) & BIT(offset)); 29 } 30 31 static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset, 32 int value) 33 { 34 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 35 36 if (value) 37 setbits_be32(priv->reg_data, BIT(offset)); 38 else 39 clrbits_be32(priv->reg_data, BIT(offset)); 40 41 return 0; 42 } 43 44 static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset, 45 bool input) 46 { 47 if (input) 48 clrbits_be32(dirout, BIT(offset)); 49 else 50 setbits_be32(dirout, BIT(offset)); 51 52 return 0; 53 } 54 55 static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset) 56 { 57 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 58 59 return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1); 60 } 61 62 static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset, 63 int value) 64 { 65 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 66 67 bcm6345_gpio_set_value(dev, offset, value); 68 69 return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0); 70 } 71 72 static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset) 73 { 74 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 75 76 if (readl_be(priv->reg_dirout) & BIT(offset)) 77 return GPIOF_OUTPUT; 78 else 79 return GPIOF_INPUT; 80 } 81 82 static const struct dm_gpio_ops bcm6345_gpio_ops = { 83 .direction_input = bcm6345_gpio_direction_input, 84 .direction_output = bcm6345_gpio_direction_output, 85 .get_value = bcm6345_gpio_get_value, 86 .set_value = bcm6345_gpio_set_value, 87 .get_function = bcm6345_gpio_get_function, 88 }; 89 90 static int bcm6345_gpio_probe(struct udevice *dev) 91 { 92 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 93 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 94 fdt_addr_t data_addr, dirout_addr; 95 fdt_size_t data_size, dirout_size; 96 97 dirout_addr = devfdt_get_addr_size_index(dev, 0, &dirout_size); 98 if (dirout_addr == FDT_ADDR_T_NONE) 99 return -EINVAL; 100 101 data_addr = devfdt_get_addr_size_index(dev, 1, &data_size); 102 if (data_addr == FDT_ADDR_T_NONE) 103 return -EINVAL; 104 105 priv->reg_data = ioremap(data_addr, data_size); 106 priv->reg_dirout = ioremap(dirout_addr, dirout_size); 107 108 uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), 109 "ngpios", 32); 110 uc_priv->bank_name = dev->name; 111 112 return 0; 113 } 114 115 static const struct udevice_id bcm6345_gpio_ids[] = { 116 { .compatible = "brcm,bcm6345-gpio" }, 117 { /* sentinel */ } 118 }; 119 120 U_BOOT_DRIVER(bcm6345_gpio) = { 121 .name = "bcm6345-gpio", 122 .id = UCLASS_GPIO, 123 .of_match = bcm6345_gpio_ids, 124 .ops = &bcm6345_gpio_ops, 125 .priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv), 126 .probe = bcm6345_gpio_probe, 127 }; 128