1/* 2 * Broadcom specific AMBA 3 * GPIO driver 4 * 5 * Copyright 2011, Broadcom Corporation 6 * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de> 7 * 8 * Licensed under the GNU/GPL. See COPYING for details. 9 */ 10 11#include <linux/gpio.h> 12#include <linux/irq.h> 13#include <linux/interrupt.h> 14#include <linux/irqdomain.h> 15#include <linux/export.h> 16#include <linux/bcma/bcma.h> 17 18#include "bcma_private.h" 19 20#define BCMA_GPIO_MAX_PINS 32 21 22static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip) 23{ 24 return container_of(chip, struct bcma_drv_cc, gpio); 25} 26 27static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 28{ 29 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); 30 31 return !!bcma_chipco_gpio_in(cc, 1 << gpio); 32} 33 34static void bcma_gpio_set_value(struct gpio_chip *chip, unsigned gpio, 35 int value) 36{ 37 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); 38 39 bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0); 40} 41 42static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 43{ 44 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); 45 46 bcma_chipco_gpio_outen(cc, 1 << gpio, 0); 47 return 0; 48} 49 50static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, 51 int value) 52{ 53 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); 54 55 bcma_chipco_gpio_outen(cc, 1 << gpio, 1 << gpio); 56 bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0); 57 return 0; 58} 59 60static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio) 61{ 62 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); 63 64 bcma_chipco_gpio_control(cc, 1 << gpio, 0); 65 /* clear pulldown */ 66 bcma_chipco_gpio_pulldown(cc, 1 << gpio, 0); 67 /* Set pullup */ 68 bcma_chipco_gpio_pullup(cc, 1 << gpio, 1 << gpio); 69 70 return 0; 71} 72 73static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio) 74{ 75 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); 76 77 /* clear pullup */ 78 bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); 79} 80 81#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X) 82static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) 83{ 84 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); 85 86 if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) 87 return irq_find_mapping(cc->irq_domain, gpio); 88 else 89 return -EINVAL; 90} 91 92static void bcma_gpio_irq_unmask(struct irq_data *d) 93{ 94 struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d); 95 int gpio = irqd_to_hwirq(d); 96 u32 val = bcma_chipco_gpio_in(cc, BIT(gpio)); 97 98 bcma_chipco_gpio_polarity(cc, BIT(gpio), val); 99 bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio)); 100} 101 102static void bcma_gpio_irq_mask(struct irq_data *d) 103{ 104 struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d); 105 int gpio = irqd_to_hwirq(d); 106 107 bcma_chipco_gpio_intmask(cc, BIT(gpio), 0); 108} 109 110static struct irq_chip bcma_gpio_irq_chip = { 111 .name = "BCMA-GPIO", 112 .irq_mask = bcma_gpio_irq_mask, 113 .irq_unmask = bcma_gpio_irq_unmask, 114}; 115 116static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id) 117{ 118 struct bcma_drv_cc *cc = dev_id; 119 u32 val = bcma_cc_read32(cc, BCMA_CC_GPIOIN); 120 u32 mask = bcma_cc_read32(cc, BCMA_CC_GPIOIRQ); 121 u32 pol = bcma_cc_read32(cc, BCMA_CC_GPIOPOL); 122 unsigned long irqs = (val ^ pol) & mask; 123 int gpio; 124 125 if (!irqs) 126 return IRQ_NONE; 127 128 for_each_set_bit(gpio, &irqs, cc->gpio.ngpio) 129 generic_handle_irq(bcma_gpio_to_irq(&cc->gpio, gpio)); 130 bcma_chipco_gpio_polarity(cc, irqs, val & irqs); 131 132 return IRQ_HANDLED; 133} 134 135static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc) 136{ 137 struct gpio_chip *chip = &cc->gpio; 138 int gpio, hwirq, err; 139 140 if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC) 141 return 0; 142 143 cc->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, 144 &irq_domain_simple_ops, cc); 145 if (!cc->irq_domain) { 146 err = -ENODEV; 147 goto err_irq_domain; 148 } 149 for (gpio = 0; gpio < chip->ngpio; gpio++) { 150 int irq = irq_create_mapping(cc->irq_domain, gpio); 151 152 irq_set_chip_data(irq, cc); 153 irq_set_chip_and_handler(irq, &bcma_gpio_irq_chip, 154 handle_simple_irq); 155 } 156 157 hwirq = bcma_core_irq(cc->core, 0); 158 err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio", 159 cc); 160 if (err) 161 goto err_req_irq; 162 163 bcma_chipco_gpio_intmask(cc, ~0, 0); 164 bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO); 165 166 return 0; 167 168err_req_irq: 169 for (gpio = 0; gpio < chip->ngpio; gpio++) { 170 int irq = irq_find_mapping(cc->irq_domain, gpio); 171 172 irq_dispose_mapping(irq); 173 } 174 irq_domain_remove(cc->irq_domain); 175err_irq_domain: 176 return err; 177} 178 179static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) 180{ 181 struct gpio_chip *chip = &cc->gpio; 182 int gpio; 183 184 if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC) 185 return; 186 187 bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO); 188 free_irq(bcma_core_irq(cc->core, 0), cc); 189 for (gpio = 0; gpio < chip->ngpio; gpio++) { 190 int irq = irq_find_mapping(cc->irq_domain, gpio); 191 192 irq_dispose_mapping(irq); 193 } 194 irq_domain_remove(cc->irq_domain); 195} 196#else 197static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc) 198{ 199 return 0; 200} 201 202static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) 203{ 204} 205#endif 206 207int bcma_gpio_init(struct bcma_drv_cc *cc) 208{ 209 struct bcma_bus *bus = cc->core->bus; 210 struct gpio_chip *chip = &cc->gpio; 211 int err; 212 213 chip->label = "bcma_gpio"; 214 chip->owner = THIS_MODULE; 215 chip->request = bcma_gpio_request; 216 chip->free = bcma_gpio_free; 217 chip->get = bcma_gpio_get_value; 218 chip->set = bcma_gpio_set_value; 219 chip->direction_input = bcma_gpio_direction_input; 220 chip->direction_output = bcma_gpio_direction_output; 221#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X) 222 chip->to_irq = bcma_gpio_to_irq; 223#endif 224#if IS_BUILTIN(CONFIG_OF) 225 if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) 226 chip->of_node = cc->core->dev.of_node; 227#endif 228 switch (bus->chipinfo.id) { 229 case BCMA_CHIP_ID_BCM5357: 230 case BCMA_CHIP_ID_BCM53572: 231 chip->ngpio = 32; 232 break; 233 default: 234 chip->ngpio = 16; 235 } 236 237 /* 238 * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO 239 * pin numbers. We don't have Device Tree there and we can't really use 240 * relative (per chip) numbers. 241 * So let's use predictable base for BCM47XX and "random" for all other. 242 */ 243#if IS_BUILTIN(CONFIG_BCM47XX) 244 chip->base = bus->num * BCMA_GPIO_MAX_PINS; 245#else 246 chip->base = -1; 247#endif 248 249 err = bcma_gpio_irq_domain_init(cc); 250 if (err) 251 return err; 252 253 err = gpiochip_add(chip); 254 if (err) { 255 bcma_gpio_irq_domain_exit(cc); 256 return err; 257 } 258 259 return 0; 260} 261 262int bcma_gpio_unregister(struct bcma_drv_cc *cc) 263{ 264 bcma_gpio_irq_domain_exit(cc); 265 gpiochip_remove(&cc->gpio); 266 return 0; 267} 268