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 <errno.h> 13 #include <asm/gpio.h> 14 #include <asm/io.h> 15 #include <dm/device.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 return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0); 68 } 69 70 static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset) 71 { 72 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 73 74 if (readl_be(priv->reg_dirout) & BIT(offset)) 75 return GPIOF_OUTPUT; 76 else 77 return GPIOF_INPUT; 78 } 79 80 static const struct dm_gpio_ops bcm6345_gpio_ops = { 81 .direction_input = bcm6345_gpio_direction_input, 82 .direction_output = bcm6345_gpio_direction_output, 83 .get_value = bcm6345_gpio_get_value, 84 .set_value = bcm6345_gpio_set_value, 85 .get_function = bcm6345_gpio_get_function, 86 }; 87 88 static int bcm6345_gpio_probe(struct udevice *dev) 89 { 90 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 91 struct bcm6345_gpio_priv *priv = dev_get_priv(dev); 92 fdt_addr_t data_addr, dirout_addr; 93 fdt_size_t data_size, dirout_size; 94 95 dirout_addr = dev_get_addr_size_index(dev, 0, &dirout_size); 96 if (dirout_addr == FDT_ADDR_T_NONE) 97 return -EINVAL; 98 99 data_addr = dev_get_addr_size_index(dev, 1, &data_size); 100 if (data_addr == FDT_ADDR_T_NONE) 101 return -EINVAL; 102 103 priv->reg_data = ioremap(data_addr, data_size); 104 priv->reg_dirout = ioremap(dirout_addr, dirout_size); 105 106 uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), 107 "ngpios", 32); 108 uc_priv->bank_name = dev->name; 109 110 return 0; 111 } 112 113 static const struct udevice_id bcm6345_gpio_ids[] = { 114 { .compatible = "brcm,bcm6345-gpio" }, 115 { /* sentinel */ } 116 }; 117 118 U_BOOT_DRIVER(bcm6345_gpio) = { 119 .name = "bcm6345-gpio", 120 .id = UCLASS_GPIO, 121 .of_match = bcm6345_gpio_ids, 122 .ops = &bcm6345_gpio_ops, 123 .priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv), 124 .probe = bcm6345_gpio_probe, 125 }; 126