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 #define AR71XX_GPIO_REG_OE 0x00 20 #define AR71XX_GPIO_REG_IN 0x04 21 #define AR71XX_GPIO_REG_SET 0x0c 22 #define AR71XX_GPIO_REG_CLEAR 0x10 23 24 struct ath79_gpio_ctrl { 25 struct gpio_chip gc; 26 void __iomem *base; 27 spinlock_t lock; 28 }; 29 30 static const struct of_device_id ath79_gpio_of_match[] = { 31 { .compatible = "qca,ar7100-gpio" }, 32 { .compatible = "qca,ar9340-gpio" }, 33 {}, 34 }; 35 36 static int ath79_gpio_probe(struct platform_device *pdev) 37 { 38 struct ath79_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); 39 struct device_node *np = pdev->dev.of_node; 40 struct ath79_gpio_ctrl *ctrl; 41 struct resource *res; 42 u32 ath79_gpio_count; 43 bool oe_inverted; 44 int err; 45 46 ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 47 if (!ctrl) 48 return -ENOMEM; 49 platform_set_drvdata(pdev, ctrl); 50 51 if (np) { 52 err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); 53 if (err) { 54 dev_err(&pdev->dev, "ngpios property is not valid\n"); 55 return err; 56 } 57 if (ath79_gpio_count >= 32) { 58 dev_err(&pdev->dev, "ngpios must be less than 32\n"); 59 return -EINVAL; 60 } 61 oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); 62 } else if (pdata) { 63 ath79_gpio_count = pdata->ngpios; 64 oe_inverted = pdata->oe_inverted; 65 } else { 66 dev_err(&pdev->dev, "No DT node or platform data found\n"); 67 return -EINVAL; 68 } 69 70 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 71 ctrl->base = devm_ioremap_nocache( 72 &pdev->dev, res->start, resource_size(res)); 73 if (!ctrl->base) 74 return -ENOMEM; 75 76 spin_lock_init(&ctrl->lock); 77 err = bgpio_init(&ctrl->gc, &pdev->dev, 4, 78 ctrl->base + AR71XX_GPIO_REG_IN, 79 ctrl->base + AR71XX_GPIO_REG_SET, 80 ctrl->base + AR71XX_GPIO_REG_CLEAR, 81 oe_inverted ? NULL : ctrl->base + AR71XX_GPIO_REG_OE, 82 oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL, 83 0); 84 if (err) { 85 dev_err(&pdev->dev, "bgpio_init failed\n"); 86 return err; 87 } 88 /* Use base 0 to stay compatible with legacy platforms */ 89 ctrl->gc.base = 0; 90 91 err = gpiochip_add_data(&ctrl->gc, ctrl); 92 if (err) { 93 dev_err(&pdev->dev, 94 "cannot add AR71xx GPIO chip, error=%d", err); 95 return err; 96 } 97 98 return 0; 99 } 100 101 static int ath79_gpio_remove(struct platform_device *pdev) 102 { 103 struct ath79_gpio_ctrl *ctrl = platform_get_drvdata(pdev); 104 105 gpiochip_remove(&ctrl->gc); 106 return 0; 107 } 108 109 static struct platform_driver ath79_gpio_driver = { 110 .driver = { 111 .name = "ath79-gpio", 112 .of_match_table = ath79_gpio_of_match, 113 }, 114 .probe = ath79_gpio_probe, 115 .remove = ath79_gpio_remove, 116 }; 117 118 module_platform_driver(ath79_gpio_driver); 119