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