1/* 2 * Atheros AR71XX/AR724X/AR913X GPIO API support 3 * 4 * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> 5 * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> 6 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 7 * 8 * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 as published 12 * by the Free Software Foundation. 13 */ 14 15#include <linux/gpio/driver.h> 16#include <linux/platform_data/gpio-ath79.h> 17#include <linux/of_device.h> 18 19#include <asm/mach-ath79/ar71xx_regs.h> 20 21struct ath79_gpio_ctrl { 22 struct gpio_chip chip; 23 void __iomem *base; 24 spinlock_t lock; 25}; 26 27#define to_ath79_gpio_ctrl(c) container_of(c, struct ath79_gpio_ctrl, chip) 28 29static void ath79_gpio_set_value(struct gpio_chip *chip, 30 unsigned gpio, int value) 31{ 32 struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); 33 34 if (value) 35 __raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET); 36 else 37 __raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_CLEAR); 38} 39 40static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 41{ 42 struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); 43 44 return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1; 45} 46 47static int ath79_gpio_direction_input(struct gpio_chip *chip, 48 unsigned offset) 49{ 50 struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); 51 unsigned long flags; 52 53 spin_lock_irqsave(&ctrl->lock, flags); 54 55 __raw_writel( 56 __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset), 57 ctrl->base + AR71XX_GPIO_REG_OE); 58 59 spin_unlock_irqrestore(&ctrl->lock, flags); 60 61 return 0; 62} 63 64static int ath79_gpio_direction_output(struct gpio_chip *chip, 65 unsigned offset, int value) 66{ 67 struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); 68 unsigned long flags; 69 70 spin_lock_irqsave(&ctrl->lock, flags); 71 72 if (value) 73 __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET); 74 else 75 __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR); 76 77 __raw_writel( 78 __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset), 79 ctrl->base + AR71XX_GPIO_REG_OE); 80 81 spin_unlock_irqrestore(&ctrl->lock, flags); 82 83 return 0; 84} 85 86static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 87{ 88 struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); 89 unsigned long flags; 90 91 spin_lock_irqsave(&ctrl->lock, flags); 92 93 __raw_writel( 94 __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset), 95 ctrl->base + AR71XX_GPIO_REG_OE); 96 97 spin_unlock_irqrestore(&ctrl->lock, flags); 98 99 return 0; 100} 101 102static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 103 int value) 104{ 105 struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); 106 unsigned long flags; 107 108 spin_lock_irqsave(&ctrl->lock, flags); 109 110 if (value) 111 __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET); 112 else 113 __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR); 114 115 __raw_writel( 116 __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset), 117 ctrl->base + AR71XX_GPIO_REG_OE); 118 119 spin_unlock_irqrestore(&ctrl->lock, flags); 120 121 return 0; 122} 123 124static const struct gpio_chip ath79_gpio_chip = { 125 .label = "ath79", 126 .get = ath79_gpio_get_value, 127 .set = ath79_gpio_set_value, 128 .direction_input = ath79_gpio_direction_input, 129 .direction_output = ath79_gpio_direction_output, 130 .base = 0, 131}; 132 133static const struct of_device_id ath79_gpio_of_match[] = { 134 { .compatible = "qca,ar7100-gpio" }, 135 { .compatible = "qca,ar9340-gpio" }, 136 {}, 137}; 138 139static int ath79_gpio_probe(struct platform_device *pdev) 140{ 141 struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data; 142 struct device_node *np = pdev->dev.of_node; 143 struct ath79_gpio_ctrl *ctrl; 144 struct resource *res; 145 u32 ath79_gpio_count; 146 bool oe_inverted; 147 int err; 148 149 ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 150 if (!ctrl) 151 return -ENOMEM; 152 153 if (np) { 154 err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); 155 if (err) { 156 dev_err(&pdev->dev, "ngpios property is not valid\n"); 157 return err; 158 } 159 if (ath79_gpio_count >= 32) { 160 dev_err(&pdev->dev, "ngpios must be less than 32\n"); 161 return -EINVAL; 162 } 163 oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); 164 } else if (pdata) { 165 ath79_gpio_count = pdata->ngpios; 166 oe_inverted = pdata->oe_inverted; 167 } else { 168 dev_err(&pdev->dev, "No DT node or platform data found\n"); 169 return -EINVAL; 170 } 171 172 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 173 ctrl->base = devm_ioremap_nocache( 174 &pdev->dev, res->start, resource_size(res)); 175 if (!ctrl->base) 176 return -ENOMEM; 177 178 spin_lock_init(&ctrl->lock); 179 memcpy(&ctrl->chip, &ath79_gpio_chip, sizeof(ctrl->chip)); 180 ctrl->chip.dev = &pdev->dev; 181 ctrl->chip.ngpio = ath79_gpio_count; 182 if (oe_inverted) { 183 ctrl->chip.direction_input = ar934x_gpio_direction_input; 184 ctrl->chip.direction_output = ar934x_gpio_direction_output; 185 } 186 187 err = gpiochip_add(&ctrl->chip); 188 if (err) { 189 dev_err(&pdev->dev, 190 "cannot add AR71xx GPIO chip, error=%d", err); 191 return err; 192 } 193 194 return 0; 195} 196 197static struct platform_driver ath79_gpio_driver = { 198 .driver = { 199 .name = "ath79-gpio", 200 .of_match_table = ath79_gpio_of_match, 201 }, 202 .probe = ath79_gpio_probe, 203}; 204 205module_platform_driver(ath79_gpio_driver); 206