diff options
author | Hauke Mehrtens <hauke@hauke-m.de> | 2014-02-04 22:54:29 +0000 |
---|---|---|
committer | Hauke Mehrtens <hauke@hauke-m.de> | 2014-02-04 22:54:29 +0000 |
commit | 7ae5ff92aeac2ed17f0d5fc9d1554f8eaa3a4d27 (patch) | |
tree | 57161ac178428e8082038d6371f54d650d0b523c /target/linux/generic | |
parent | e0d4a548fb099ec45ccb566c9bf5a90c224a121b (diff) | |
download | upstream-7ae5ff92aeac2ed17f0d5fc9d1554f8eaa3a4d27.tar.gz upstream-7ae5ff92aeac2ed17f0d5fc9d1554f8eaa3a4d27.tar.bz2 upstream-7ae5ff92aeac2ed17f0d5fc9d1554f8eaa3a4d27.zip |
kernel: ssb: update ssb to a version from kernel 3.14-rc1
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
SVN-Revision: 39464
Diffstat (limited to 'target/linux/generic')
-rw-r--r-- | target/linux/generic/patches-3.10/020-ssb_update.patch | 489 | ||||
-rw-r--r-- | target/linux/generic/patches-3.12/020-ssb_update.patch | 543 | ||||
-rw-r--r-- | target/linux/generic/patches-3.13/020-ssb_update.patch | 467 |
3 files changed, 1495 insertions, 4 deletions
diff --git a/target/linux/generic/patches-3.10/020-ssb_update.patch b/target/linux/generic/patches-3.10/020-ssb_update.patch index 1605705251..4b0caa806a 100644 --- a/target/linux/generic/patches-3.10/020-ssb_update.patch +++ b/target/linux/generic/patches-3.10/020-ssb_update.patch @@ -16,6 +16,14 @@ default y config SSB_DRIVER_EXTIF +@@ -168,6 +168,7 @@ config SSB_DRIVER_GIGE + config SSB_DRIVER_GPIO + bool "SSB GPIO driver" + depends on SSB && GPIOLIB ++ select IRQ_DOMAIN if SSB_EMBEDDED + help + Driver to provide access to the GPIO pins on the bus. + --- a/drivers/ssb/driver_chipcommon_sflash.c +++ b/drivers/ssb/driver_chipcommon_sflash.c @@ -9,6 +9,19 @@ @@ -47,8 +55,12 @@ { "M25P20", 0x11, 0x10000, 4, }, { "M25P40", 0x12, 0x10000, 8, }, -@@ -27,7 +40,7 @@ static struct ssb_sflash_tbl_e ssb_sflas - { 0 }, +@@ -24,10 +37,10 @@ static struct ssb_sflash_tbl_e ssb_sflas + { "M25P32", 0x15, 0x10000, 64, }, + { "M25P64", 0x16, 0x10000, 128, }, + { "M25FL128", 0x17, 0x10000, 256, }, +- { 0 }, ++ { NULL }, }; -static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { @@ -56,8 +68,12 @@ { "SST25WF512", 1, 0x1000, 16, }, { "SST25VF512", 0x48, 0x1000, 16, }, { "SST25WF010", 2, 0x1000, 32, }, -@@ -45,7 +58,7 @@ static struct ssb_sflash_tbl_e ssb_sflas - { 0 }, +@@ -42,10 +55,10 @@ static struct ssb_sflash_tbl_e ssb_sflas + { "SST25VF016", 0x41, 0x1000, 512, }, + { "SST25VF032", 0x4a, 0x1000, 1024, }, + { "SST25VF064", 0x4b, 0x1000, 2048, }, +- { 0 }, ++ { NULL }, }; -static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { @@ -65,6 +81,15 @@ { "AT45DB011", 0xc, 256, 512, }, { "AT45DB021", 0x14, 256, 1024, }, { "AT45DB041", 0x1c, 256, 2048, }, +@@ -53,7 +66,7 @@ static struct ssb_sflash_tbl_e ssb_sflas + { "AT45DB161", 0x2c, 512, 4096, }, + { "AT45DB321", 0x34, 512, 8192, }, + { "AT45DB642", 0x3c, 1024, 8192, }, +- { 0 }, ++ { NULL }, + }; + + static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) @@ -73,7 +86,8 @@ static void ssb_sflash_cmd(struct ssb_ch /* Initialize serial flash access */ int ssb_sflash_init(struct ssb_chipcommon *cc) @@ -101,6 +126,396 @@ - return -ENOTSUPP; + return 0; } +--- a/drivers/ssb/driver_gpio.c ++++ b/drivers/ssb/driver_gpio.c +@@ -9,16 +9,40 @@ + */ + + #include <linux/gpio.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/irqdomain.h> + #include <linux/export.h> + #include <linux/ssb/ssb.h> + + #include "ssb_private.h" + ++ ++/************************************************** ++ * Shared ++ **************************************************/ ++ + static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) + { + return container_of(chip, struct ssb_bus, gpio); + } + ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) ++{ ++ struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ ++ if (bus->bustype == SSB_BUSTYPE_SSB) ++ return irq_find_mapping(bus->irq_domain, gpio); ++ else ++ return -EINVAL; ++} ++#endif ++ ++/************************************************** ++ * ChipCommon ++ **************************************************/ ++ + static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) + { + struct ssb_bus *bus = ssb_gpio_get_bus(chip); +@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct + ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); + } + +-static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_chipco_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->chipco.dev) + 2; +- else +- return -EINVAL; ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); ++ ++ ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_chipco_chip = { ++ .name = "SSB-GPIO-CC", ++ .irq_mask = ssb_gpio_irq_chipco_mask, ++ .irq_unmask = ssb_gpio_irq_chipco_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); ++ u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); ++ u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, chipco); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->chipco.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); ++ chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); ++ free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ + } ++#endif + + static int ssb_gpio_chipco_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_chipco_gpio"; + chip->owner = THIS_MODULE; +@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct s + chip->set = ssb_gpio_chipco_set_value; + chip->direction_input = ssb_gpio_chipco_direction_input; + chip->direction_output = ssb_gpio_chipco_direction_output; +- chip->to_irq = ssb_gpio_chipco_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 16; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct s + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_chipco_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_chipco_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + ++/************************************************** ++ * EXTIF ++ **************************************************/ ++ + #ifdef CONFIG_SSB_DRIVER_EXTIF + + static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) +@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_outp + return 0; + } + +-static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_extif_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->extif.dev) + 2; +- else +- return -EINVAL; ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_extif_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); ++ ++ ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_extif_chip = { ++ .name = "SSB-GPIO-EXTIF", ++ .irq_mask = ssb_gpio_irq_extif_mask, ++ .irq_unmask = ssb_gpio_irq_extif_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_extif *extif = &bus->extif; ++ u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); ++ u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); ++ u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_extif_gpio_polarity(extif, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, extif); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->extif.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_extif_gpio_intmask(&bus->extif, ~0, 0); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; + } + ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++} ++#endif ++ + static int ssb_gpio_extif_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_extif_gpio"; + chip->owner = THIS_MODULE; +@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ss + chip->set = ssb_gpio_extif_set_value; + chip->direction_input = ssb_gpio_extif_direction_input; + chip->direction_output = ssb_gpio_extif_direction_output; +- chip->to_irq = ssb_gpio_extif_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 5; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ss + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_extif_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_extif_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + + #else +@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ss + } + #endif + ++/************************************************** ++ * Init ++ **************************************************/ ++ + int ssb_gpio_init(struct ssb_bus *bus) + { + if (ssb_chipco_available(&bus->chipco)) --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -553,6 +553,14 @@ static int ssb_devices_register(struct s @@ -118,6 +533,32 @@ return 0; error: /* Unwind the already registered devices. */ +@@ -582,6 +590,13 @@ static int ssb_attach_queued_buses(void) + ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ++ ++ err = ssb_gpio_init(bus); ++ if (err == -ENOTSUPP) ++ ssb_dbg("GPIO driver not activated\n"); ++ else if (err) ++ ssb_dbg("Error registering GPIO driver: %i\n", err); ++ + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +@@ -819,11 +834,6 @@ static int ssb_bus_register(struct ssb_b + ssb_chipcommon_init(&bus->chipco); + ssb_extif_init(&bus->extif); + ssb_mipscore_init(&bus->mipscore); +- err = ssb_gpio_init(bus); +- if (err == -ENOTSUPP) +- ssb_dbg("GPIO driver not activated\n"); +- else if (err) +- ssb_dbg("Error registering GPIO driver: %i\n", err); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -38,7 +38,7 @@ static int ssb_pcihost_resume(struct pci @@ -153,6 +594,46 @@ #ifdef CONFIG_SSB_DRIVER_EXTIF extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -486,6 +486,7 @@ struct ssb_bus { + #endif /* EMBEDDED */ + #ifdef CONFIG_SSB_DRIVER_GPIO + struct gpio_chip gpio; ++ struct irq_domain *irq_domain; + #endif /* DRIVER_GPIO */ + + /* Internal-only stuff follows. Do not touch. */ +--- a/include/linux/ssb/ssb_driver_gige.h ++++ b/include/linux/ssb/ssb_driver_gige.h +@@ -108,6 +108,16 @@ static inline int ssb_gige_get_macaddr(s + return 0; + } + ++/* Get the device phy address */ ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ if (!dev) ++ return -ENODEV; ++ ++ return dev->dev->bus->sprom.et0phyaddr; ++} ++ + extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev); + extern int ssb_gige_map_irq(struct ssb_device *sdev, +@@ -174,6 +184,10 @@ static inline int ssb_gige_get_macaddr(s + { + return -ENODEV; + } ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ return -ENODEV; ++} + + #endif /* CONFIG_SSB_DRIVER_GIGE */ + #endif /* LINUX_SSB_DRIVER_GIGE_H_ */ --- a/include/linux/ssb/ssb_driver_mips.h +++ b/include/linux/ssb/ssb_driver_mips.h @@ -20,6 +20,18 @@ struct ssb_pflash { diff --git a/target/linux/generic/patches-3.12/020-ssb_update.patch b/target/linux/generic/patches-3.12/020-ssb_update.patch new file mode 100644 index 0000000000..a6c6d8f46c --- /dev/null +++ b/target/linux/generic/patches-3.12/020-ssb_update.patch @@ -0,0 +1,543 @@ +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -168,6 +168,7 @@ config SSB_DRIVER_GIGE + config SSB_DRIVER_GPIO + bool "SSB GPIO driver" + depends on SSB && GPIOLIB ++ select IRQ_DOMAIN if SSB_EMBEDDED + help + Driver to provide access to the GPIO pins on the bus. + +--- a/drivers/ssb/driver_chipcommon_sflash.c ++++ b/drivers/ssb/driver_chipcommon_sflash.c +@@ -37,7 +37,7 @@ static const struct ssb_sflash_tbl_e ssb + { "M25P32", 0x15, 0x10000, 64, }, + { "M25P64", 0x16, 0x10000, 128, }, + { "M25FL128", 0x17, 0x10000, 256, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { +@@ -55,7 +55,7 @@ static const struct ssb_sflash_tbl_e ssb + { "SST25VF016", 0x41, 0x1000, 512, }, + { "SST25VF032", 0x4a, 0x1000, 1024, }, + { "SST25VF064", 0x4b, 0x1000, 2048, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { +@@ -66,7 +66,7 @@ static const struct ssb_sflash_tbl_e ssb + { "AT45DB161", 0x2c, 512, 4096, }, + { "AT45DB321", 0x34, 512, 8192, }, + { "AT45DB642", 0x3c, 1024, 8192, }, +- { 0 }, ++ { NULL }, + }; + + static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) +--- a/drivers/ssb/driver_gpio.c ++++ b/drivers/ssb/driver_gpio.c +@@ -9,16 +9,40 @@ + */ + + #include <linux/gpio.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/irqdomain.h> + #include <linux/export.h> + #include <linux/ssb/ssb.h> + + #include "ssb_private.h" + ++ ++/************************************************** ++ * Shared ++ **************************************************/ ++ + static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) + { + return container_of(chip, struct ssb_bus, gpio); + } + ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) ++{ ++ struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ ++ if (bus->bustype == SSB_BUSTYPE_SSB) ++ return irq_find_mapping(bus->irq_domain, gpio); ++ else ++ return -EINVAL; ++} ++#endif ++ ++/************************************************** ++ * ChipCommon ++ **************************************************/ ++ + static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) + { + struct ssb_bus *bus = ssb_gpio_get_bus(chip); +@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct + ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); + } + +-static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_chipco_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->chipco.dev) + 2; +- else +- return -EINVAL; ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); ++ ++ ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_chipco_chip = { ++ .name = "SSB-GPIO-CC", ++ .irq_mask = ssb_gpio_irq_chipco_mask, ++ .irq_unmask = ssb_gpio_irq_chipco_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); ++ u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); ++ u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, chipco); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->chipco.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); ++ chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); ++ free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ + } ++#endif + + static int ssb_gpio_chipco_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_chipco_gpio"; + chip->owner = THIS_MODULE; +@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct s + chip->set = ssb_gpio_chipco_set_value; + chip->direction_input = ssb_gpio_chipco_direction_input; + chip->direction_output = ssb_gpio_chipco_direction_output; +- chip->to_irq = ssb_gpio_chipco_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 16; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct s + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_chipco_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_chipco_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + ++/************************************************** ++ * EXTIF ++ **************************************************/ ++ + #ifdef CONFIG_SSB_DRIVER_EXTIF + + static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) +@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_outp + return 0; + } + +-static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_extif_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->extif.dev) + 2; +- else +- return -EINVAL; ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_extif_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); ++ ++ ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_extif_chip = { ++ .name = "SSB-GPIO-EXTIF", ++ .irq_mask = ssb_gpio_irq_extif_mask, ++ .irq_unmask = ssb_gpio_irq_extif_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_extif *extif = &bus->extif; ++ u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); ++ u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); ++ u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_extif_gpio_polarity(extif, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, extif); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->extif.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_extif_gpio_intmask(&bus->extif, ~0, 0); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; + } + ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++} ++#endif ++ + static int ssb_gpio_extif_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_extif_gpio"; + chip->owner = THIS_MODULE; +@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ss + chip->set = ssb_gpio_extif_set_value; + chip->direction_input = ssb_gpio_extif_direction_input; + chip->direction_output = ssb_gpio_extif_direction_output; +- chip->to_irq = ssb_gpio_extif_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 5; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ss + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_extif_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_extif_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + + #else +@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ss + } + #endif + ++/************************************************** ++ * Init ++ **************************************************/ ++ + int ssb_gpio_init(struct ssb_bus *bus) + { + if (ssb_chipco_available(&bus->chipco)) +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -374,7 +374,8 @@ static ssize_t \ + attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \ + { \ + return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \ +-} ++} \ ++static DEVICE_ATTR_RO(attrib); + + ssb_config_attr(core_num, core_index, "%u\n") + ssb_config_attr(coreid, id.coreid, "0x%04x\n") +@@ -387,16 +388,18 @@ name_show(struct device *dev, struct dev + return sprintf(buf, "%s\n", + ssb_core_name(dev_to_ssb_dev(dev)->id.coreid)); + } ++static DEVICE_ATTR_RO(name); + +-static struct device_attribute ssb_device_attrs[] = { +- __ATTR_RO(name), +- __ATTR_RO(core_num), +- __ATTR_RO(coreid), +- __ATTR_RO(vendor), +- __ATTR_RO(revision), +- __ATTR_RO(irq), +- __ATTR_NULL, ++static struct attribute *ssb_device_attrs[] = { ++ &dev_attr_name.attr, ++ &dev_attr_core_num.attr, ++ &dev_attr_coreid.attr, ++ &dev_attr_vendor.attr, ++ &dev_attr_revision.attr, ++ &dev_attr_irq.attr, ++ NULL, + }; ++ATTRIBUTE_GROUPS(ssb_device); + + static struct bus_type ssb_bustype = { + .name = "ssb", +@@ -407,7 +410,7 @@ static struct bus_type ssb_bustype = { + .suspend = ssb_device_suspend, + .resume = ssb_device_resume, + .uevent = ssb_device_uevent, +- .dev_attrs = ssb_device_attrs, ++ .dev_groups = ssb_device_groups, + }; + + static void ssb_buses_lock(void) +@@ -590,6 +593,13 @@ static int ssb_attach_queued_buses(void) + ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ++ ++ err = ssb_gpio_init(bus); ++ if (err == -ENOTSUPP) ++ ssb_dbg("GPIO driver not activated\n"); ++ else if (err) ++ ssb_dbg("Error registering GPIO driver: %i\n", err); ++ + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +@@ -827,11 +837,6 @@ static int ssb_bus_register(struct ssb_b + ssb_chipcommon_init(&bus->chipco); + ssb_extif_init(&bus->extif); + ssb_mipscore_init(&bus->mipscore); +- err = ssb_gpio_init(bus); +- if (err == -ENOTSUPP) +- ssb_dbg("GPIO driver not activated\n"); +- else if (err) +- ssb_dbg("Error registering GPIO driver: %i\n", err); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -486,6 +486,7 @@ struct ssb_bus { + #endif /* EMBEDDED */ + #ifdef CONFIG_SSB_DRIVER_GPIO + struct gpio_chip gpio; ++ struct irq_domain *irq_domain; + #endif /* DRIVER_GPIO */ + + /* Internal-only stuff follows. Do not touch. */ +--- a/include/linux/ssb/ssb_driver_gige.h ++++ b/include/linux/ssb/ssb_driver_gige.h +@@ -108,6 +108,16 @@ static inline int ssb_gige_get_macaddr(s + return 0; + } + ++/* Get the device phy address */ ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ if (!dev) ++ return -ENODEV; ++ ++ return dev->dev->bus->sprom.et0phyaddr; ++} ++ + extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev); + extern int ssb_gige_map_irq(struct ssb_device *sdev, +@@ -174,6 +184,10 @@ static inline int ssb_gige_get_macaddr(s + { + return -ENODEV; + } ++static inline int ssb_gige_get_phyaddr(struct pci_dev *pdev) ++{ ++ return -ENODEV; ++} + + #endif /* CONFIG_SSB_DRIVER_GIGE */ + #endif /* LINUX_SSB_DRIVER_GIGE_H_ */ diff --git a/target/linux/generic/patches-3.13/020-ssb_update.patch b/target/linux/generic/patches-3.13/020-ssb_update.patch new file mode 100644 index 0000000000..4452644680 --- /dev/null +++ b/target/linux/generic/patches-3.13/020-ssb_update.patch @@ -0,0 +1,467 @@ +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -168,6 +168,7 @@ config SSB_DRIVER_GIGE + config SSB_DRIVER_GPIO + bool "SSB GPIO driver" + depends on SSB && GPIOLIB ++ select IRQ_DOMAIN if SSB_EMBEDDED + help + Driver to provide access to the GPIO pins on the bus. + +--- a/drivers/ssb/driver_chipcommon_sflash.c ++++ b/drivers/ssb/driver_chipcommon_sflash.c +@@ -37,7 +37,7 @@ static const struct ssb_sflash_tbl_e ssb + { "M25P32", 0x15, 0x10000, 64, }, + { "M25P64", 0x16, 0x10000, 128, }, + { "M25FL128", 0x17, 0x10000, 256, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { +@@ -55,7 +55,7 @@ static const struct ssb_sflash_tbl_e ssb + { "SST25VF016", 0x41, 0x1000, 512, }, + { "SST25VF032", 0x4a, 0x1000, 1024, }, + { "SST25VF064", 0x4b, 0x1000, 2048, }, +- { 0 }, ++ { NULL }, + }; + + static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { +@@ -66,7 +66,7 @@ static const struct ssb_sflash_tbl_e ssb + { "AT45DB161", 0x2c, 512, 4096, }, + { "AT45DB321", 0x34, 512, 8192, }, + { "AT45DB642", 0x3c, 1024, 8192, }, +- { 0 }, ++ { NULL }, + }; + + static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) +--- a/drivers/ssb/driver_gpio.c ++++ b/drivers/ssb/driver_gpio.c +@@ -9,16 +9,40 @@ + */ + + #include <linux/gpio.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/irqdomain.h> + #include <linux/export.h> + #include <linux/ssb/ssb.h> + + #include "ssb_private.h" + ++ ++/************************************************** ++ * Shared ++ **************************************************/ ++ + static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) + { + return container_of(chip, struct ssb_bus, gpio); + } + ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) ++{ ++ struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ ++ if (bus->bustype == SSB_BUSTYPE_SSB) ++ return irq_find_mapping(bus->irq_domain, gpio); ++ else ++ return -EINVAL; ++} ++#endif ++ ++/************************************************** ++ * ChipCommon ++ **************************************************/ ++ + static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) + { + struct ssb_bus *bus = ssb_gpio_get_bus(chip); +@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct + ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); + } + +-static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_chipco_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->chipco.dev) + 2; +- else +- return -EINVAL; ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); ++ ++ ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); ++ ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_chipco_chip = { ++ .name = "SSB-GPIO-CC", ++ .irq_mask = ssb_gpio_irq_chipco_mask, ++ .irq_unmask = ssb_gpio_irq_chipco_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); ++ u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); ++ u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, chipco); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->chipco.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); ++ chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_chipcommon *chipco = &bus->chipco; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); ++ free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) ++{ + } ++#endif + + static int ssb_gpio_chipco_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_chipco_gpio"; + chip->owner = THIS_MODULE; +@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct s + chip->set = ssb_gpio_chipco_set_value; + chip->direction_input = ssb_gpio_chipco_direction_input; + chip->direction_output = ssb_gpio_chipco_direction_output; +- chip->to_irq = ssb_gpio_chipco_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 16; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct s + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_chipco_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_chipco_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + ++/************************************************** ++ * EXTIF ++ **************************************************/ ++ + #ifdef CONFIG_SSB_DRIVER_EXTIF + + static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) +@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_outp + return 0; + } + +-static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++static void ssb_gpio_irq_extif_mask(struct irq_data *d) + { +- struct ssb_bus *bus = ssb_gpio_get_bus(chip); ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); + +- if (bus->bustype == SSB_BUSTYPE_SSB) +- return ssb_mips_irq(bus->extif.dev) + 2; +- else +- return -EINVAL; ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); ++} ++ ++static void ssb_gpio_irq_extif_unmask(struct irq_data *d) ++{ ++ struct ssb_bus *bus = irq_data_get_irq_chip_data(d); ++ int gpio = irqd_to_hwirq(d); ++ u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); ++ ++ ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); ++ ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); ++} ++ ++static struct irq_chip ssb_gpio_irq_extif_chip = { ++ .name = "SSB-GPIO-EXTIF", ++ .irq_mask = ssb_gpio_irq_extif_mask, ++ .irq_unmask = ssb_gpio_irq_extif_unmask, ++}; ++ ++static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) ++{ ++ struct ssb_bus *bus = dev_id; ++ struct ssb_extif *extif = &bus->extif; ++ u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); ++ u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); ++ u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); ++ unsigned long irqs = (val ^ pol) & mask; ++ int gpio; ++ ++ if (!irqs) ++ return IRQ_NONE; ++ ++ for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) ++ generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); ++ ssb_extif_gpio_polarity(extif, irqs, val & irqs); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio, hwirq, err; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return 0; ++ ++ bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, ++ &irq_domain_simple_ops, extif); ++ if (!bus->irq_domain) { ++ err = -ENODEV; ++ goto err_irq_domain; ++ } ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_create_mapping(bus->irq_domain, gpio); ++ ++ irq_set_chip_data(irq, bus); ++ irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, ++ handle_simple_irq); ++ } ++ ++ hwirq = ssb_mips_irq(bus->extif.dev) + 2; ++ err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, ++ "gpio", bus); ++ if (err) ++ goto err_req_irq; ++ ++ ssb_extif_gpio_intmask(&bus->extif, ~0, 0); ++ ++ return 0; ++ ++err_req_irq: ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++err_irq_domain: ++ return err; + } + ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++ struct ssb_extif *extif = &bus->extif; ++ struct gpio_chip *chip = &bus->gpio; ++ int gpio; ++ ++ if (bus->bustype != SSB_BUSTYPE_SSB) ++ return; ++ ++ free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); ++ for (gpio = 0; gpio < chip->ngpio; gpio++) { ++ int irq = irq_find_mapping(bus->irq_domain, gpio); ++ ++ irq_dispose_mapping(irq); ++ } ++ irq_domain_remove(bus->irq_domain); ++} ++#else ++static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) ++{ ++ return 0; ++} ++ ++static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) ++{ ++} ++#endif ++ + static int ssb_gpio_extif_init(struct ssb_bus *bus) + { + struct gpio_chip *chip = &bus->gpio; ++ int err; + + chip->label = "ssb_extif_gpio"; + chip->owner = THIS_MODULE; +@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ss + chip->set = ssb_gpio_extif_set_value; + chip->direction_input = ssb_gpio_extif_direction_input; + chip->direction_output = ssb_gpio_extif_direction_output; +- chip->to_irq = ssb_gpio_extif_to_irq; ++#if IS_ENABLED(CONFIG_SSB_EMBEDDED) ++ chip->to_irq = ssb_gpio_to_irq; ++#endif + chip->ngpio = 5; + /* There is just one SoC in one device and its GPIO addresses should be + * deterministic to address them more easily. The other buses could get +@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ss + else + chip->base = -1; + +- return gpiochip_add(chip); ++ err = ssb_gpio_irq_extif_domain_init(bus); ++ if (err) ++ return err; ++ ++ err = gpiochip_add(chip); ++ if (err) { ++ ssb_gpio_irq_extif_domain_exit(bus); ++ return err; ++ } ++ ++ return 0; + } + + #else +@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ss + } + #endif + ++/************************************************** ++ * Init ++ **************************************************/ ++ + int ssb_gpio_init(struct ssb_bus *bus) + { + if (ssb_chipco_available(&bus->chipco)) +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -593,6 +593,13 @@ static int ssb_attach_queued_buses(void) + ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ++ ++ err = ssb_gpio_init(bus); ++ if (err == -ENOTSUPP) ++ ssb_dbg("GPIO driver not activated\n"); ++ else if (err) ++ ssb_dbg("Error registering GPIO driver: %i\n", err); ++ + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +@@ -830,11 +837,6 @@ static int ssb_bus_register(struct ssb_b + ssb_chipcommon_init(&bus->chipco); + ssb_extif_init(&bus->extif); + ssb_mipscore_init(&bus->mipscore); +- err = ssb_gpio_init(bus); +- if (err == -ENOTSUPP) +- ssb_dbg("GPIO driver not activated\n"); +- else if (err) +- ssb_dbg("Error registering GPIO driver: %i\n", err); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -486,6 +486,7 @@ struct ssb_bus { + #endif /* EMBEDDED */ + #ifdef CONFIG_SSB_DRIVER_GPIO + struct gpio_chip gpio; ++ struct irq_domain *irq_domain; + #endif /* DRIVER_GPIO */ + + /* Internal-only stuff follows. Do not touch. */ |