From 59ecfefad53ce39f880a9c8b503fe99235f4b94d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 4 Sep 2016 21:50:47 +0100 Subject: pcmcia: soc_common: use devm_gpio_request_one() Use devm_gpio_request_one() to request the GPIOs so we can avoid manual clean up these gpio resources. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index d5ca760c4eb2..24ac27f9a119 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -111,12 +111,9 @@ static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt, { unsigned int i; - for (i = 0; i < nr; i++) { + for (i = 0; i < nr; i++) if (skt->stat[i].irq) free_irq(skt->stat[i].irq, skt); - if (gpio_is_valid(skt->stat[i].gpio)) - gpio_free(skt->stat[i].gpio); - } if (skt->ops->hw_shutdown) skt->ops->hw_shutdown(skt); @@ -145,8 +142,9 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) if (gpio_is_valid(skt->stat[i].gpio)) { int irq; - ret = gpio_request_one(skt->stat[i].gpio, GPIOF_IN, - skt->stat[i].name); + ret = devm_gpio_request_one(skt->socket.dev.parent, + skt->stat[i].gpio, GPIOF_IN, + skt->stat[i].name); if (ret) { __soc_pcmcia_hw_shutdown(skt, i); return ret; @@ -166,8 +164,6 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) IRQF_TRIGGER_NONE, skt->stat[i].name, skt); if (ret) { - if (gpio_is_valid(skt->stat[i].gpio)) - gpio_free(skt->stat[i].gpio); __soc_pcmcia_hw_shutdown(skt, i); return ret; } -- cgit v1.2.1 From 45ca7536d4f9e803c27be113b17c4cdaa12cc960 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:45 +0100 Subject: pcmcia: soc_common: switch to using gpio_descs Switch to using the gpiod_* consumer API rather than the legacy API. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 49 +++++++++++++++++++++++++++++++++++---------- drivers/pcmcia/soc_common.h | 3 +++ 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 24ac27f9a119..e07d84a69fcc 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -126,6 +127,30 @@ static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) __soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat)); } +int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt) +{ + struct device *dev = skt->socket.dev.parent; + struct gpio_desc *desc; + int i; + + for (i = 0; i < ARRAY_SIZE(skt->stat); i++) { + if (!skt->stat[i].name) + continue; + + desc = devm_gpiod_get(dev, skt->stat[i].name, GPIOD_IN); + if (IS_ERR(desc)) { + dev_err(dev, "Failed to get GPIO for %s: %ld\n", + skt->stat[i].name, PTR_ERR(desc)); + return PTR_ERR(desc); + } + + skt->stat[i].desc = desc; + } + + return 0; +} +EXPORT_SYMBOL_GPL(soc_pcmcia_request_gpiods); + static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret = 0, i; @@ -140,8 +165,6 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) for (i = 0; i < ARRAY_SIZE(skt->stat); i++) { if (gpio_is_valid(skt->stat[i].gpio)) { - int irq; - ret = devm_gpio_request_one(skt->socket.dev.parent, skt->stat[i].gpio, GPIOF_IN, skt->stat[i].name); @@ -150,7 +173,11 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) return ret; } - irq = gpio_to_irq(skt->stat[i].gpio); + skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio); + } + + if (skt->stat[i].desc) { + int irq = gpiod_to_irq(skt->stat[i].desc); if (i == SOC_STAT_RDY) skt->socket.pci_irq = irq; @@ -205,16 +232,16 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) state.bvd2 = 1; /* CD is active low by default */ - if (gpio_is_valid(skt->stat[SOC_STAT_CD].gpio)) - state.detect = !gpio_get_value(skt->stat[SOC_STAT_CD].gpio); + if (skt->stat[SOC_STAT_CD].desc) + state.detect = !gpiod_get_raw_value(skt->stat[SOC_STAT_CD].desc); /* RDY and BVD are active high by default */ - if (gpio_is_valid(skt->stat[SOC_STAT_RDY].gpio)) - state.ready = !!gpio_get_value(skt->stat[SOC_STAT_RDY].gpio); - if (gpio_is_valid(skt->stat[SOC_STAT_BVD1].gpio)) - state.bvd1 = !!gpio_get_value(skt->stat[SOC_STAT_BVD1].gpio); - if (gpio_is_valid(skt->stat[SOC_STAT_BVD2].gpio)) - state.bvd2 = !!gpio_get_value(skt->stat[SOC_STAT_BVD2].gpio); + if (skt->stat[SOC_STAT_RDY].desc) + state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc); + if (skt->stat[SOC_STAT_BVD1].desc) + state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc); + if (skt->stat[SOC_STAT_BVD2].desc) + state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc); skt->ops->socket_state(skt, &state); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 94762a54d731..ee40db16dc40 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -17,6 +17,7 @@ struct device; +struct gpio_desc; struct pcmcia_low_level; /* @@ -52,6 +53,7 @@ struct soc_pcmcia_socket { struct { int gpio; + struct gpio_desc *desc; unsigned int irq; const char *name; } stat[4]; @@ -136,6 +138,7 @@ void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt, struct pcmcia_low_level *ops, struct device *dev); void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt); int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt); +int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt); #ifdef CONFIG_PCMCIA_DEBUG -- cgit v1.2.1 From a4941191235e0fee2dd8bad3b7c61478f229c962 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 11:17:50 +0100 Subject: pcmcia: soc_common: ignore invalid interrupts If gpiod_to_irq() returns an invalid interrupt, we should not try to use it as an interrupt number. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index e07d84a69fcc..e499c2b8d7df 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -179,10 +179,12 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) if (skt->stat[i].desc) { int irq = gpiod_to_irq(skt->stat[i].desc); - if (i == SOC_STAT_RDY) - skt->socket.pci_irq = irq; - else - skt->stat[i].irq = irq; + if (irq > 0) { + if (i == SOC_STAT_RDY) + skt->socket.pci_irq = irq; + else + skt->stat[i].irq = irq; + } } if (skt->stat[i].irq) { -- cgit v1.2.1 From 7bfe49785b28931297d9e6e811f88732914f8ff3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:45 +0100 Subject: pcmcia: soc_common: request legacy detect GPIO with active low Request the legacy card detect signal with the active low property and remove our own negation of the detection value. This allows us to use the firmware-defined polarities rather than hard-coding it into the driver. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index e499c2b8d7df..4036454b2785 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -165,8 +165,14 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) for (i = 0; i < ARRAY_SIZE(skt->stat); i++) { if (gpio_is_valid(skt->stat[i].gpio)) { + unsigned long flags = GPIOF_IN; + + /* CD is active low by default */ + if (i == SOC_STAT_CD) + flags |= GPIOF_ACTIVE_LOW; + ret = devm_gpio_request_one(skt->socket.dev.parent, - skt->stat[i].gpio, GPIOF_IN, + skt->stat[i].gpio, flags, skt->stat[i].name); if (ret) { __soc_pcmcia_hw_shutdown(skt, i); @@ -233,11 +239,8 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) state.bvd1 = 1; state.bvd2 = 1; - /* CD is active low by default */ if (skt->stat[SOC_STAT_CD].desc) - state.detect = !gpiod_get_raw_value(skt->stat[SOC_STAT_CD].desc); - - /* RDY and BVD are active high by default */ + state.detect = !!gpiod_get_value(skt->stat[SOC_STAT_CD].desc); if (skt->stat[SOC_STAT_RDY].desc) state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc); if (skt->stat[SOC_STAT_BVD1].desc) -- cgit v1.2.1 From 535e0abc0534b139b067d496bb93663acffb72ce Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:45 +0100 Subject: pcmcia: soc_common: add support for reset and bus enable GPIOs Add support to soc_common for controlling reset and bus enable GPIOs from within the generic soc_common layer, rather than having individual drivers having to perform this themselves. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 16 ++++++++++++++++ drivers/pcmcia/soc_common.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 4036454b2785..f7721274cfba 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -119,6 +119,7 @@ static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt, if (skt->ops->hw_shutdown) skt->ops->hw_shutdown(skt); + clk_disable_unprepare(skt->clk); } @@ -286,6 +287,21 @@ static int soc_common_pcmcia_config_skt( ret = skt->ops->configure_socket(skt, state); if (ret == 0) { + struct gpio_desc *descs[2]; + int values[2], n = 0; + + if (skt->gpio_reset) { + descs[n] = skt->gpio_reset; + values[n++] = !!(state->flags & SS_RESET); + } + if (skt->gpio_bus_enable) { + descs[n] = skt->gpio_bus_enable; + values[n++] = !!(state->flags & SS_OUTPUT_ENA); + } + + if (n) + gpiod_set_array_value_cansleep(n, descs, values); + /* * This really needs a better solution. The IRQ * may or may not be claimed by the driver. diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index ee40db16dc40..686ba3238c76 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -62,6 +62,9 @@ struct soc_pcmcia_socket { #define SOC_STAT_BVD2 2 /* BATWARN / IOSPKR */ #define SOC_STAT_RDY 3 /* Ready / Interrupt */ + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_bus_enable; + unsigned int irq_state; struct timer_list poll_timer; -- cgit v1.2.1 From 6ac95d821216f3baab16821a893d52ab385824be Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:46 +0100 Subject: pcmcia: soc_common: restore previous socket state on error If an attempt to set a socket state returns an error, restore the previous socket state. If restoring the previous socket state fails, warn about this. This allows us to have simple error handling in the socket state configuration handlers - there is no need for every handler implementation to manually undo the updates, which can be complex when regulators are involved. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index f7721274cfba..9373d997d0cf 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -286,6 +286,14 @@ static int soc_common_pcmcia_config_skt( int ret; ret = skt->ops->configure_socket(skt, state); + if (ret < 0) { + pr_err("soc_common_pcmcia: unable to configure socket %d\n", + skt->nr); + /* restore the previous state */ + WARN_ON(skt->ops->configure_socket(skt, &skt->cs_state)); + return ret; + } + if (ret == 0) { struct gpio_desc *descs[2]; int values[2], n = 0; @@ -318,10 +326,6 @@ static int soc_common_pcmcia_config_skt( skt->cs_state = *state; } - if (ret < 0) - printk(KERN_ERR "soc_common_pcmcia: unable to configure " - "socket %d\n", skt->nr); - return ret; } @@ -770,6 +774,8 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) { int ret; + skt->cs_state = dead_socket; + setup_timer(&skt->poll_timer, soc_common_pcmcia_poll_event, (unsigned long)skt); skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD; -- cgit v1.2.1 From a1d0500261e788f9b1d068e3167b2a77ad0abfc4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:46 +0100 Subject: pcmcia: soc_common: add CF socket state helper Add a helper to get the voltage state of CF sockets, where the voltage sense pins are not wired up. Switch assabet and cerf to use this helper. Signed-off-by: Russell King --- drivers/pcmcia/sa1100_assabet.c | 9 +-------- drivers/pcmcia/sa1100_cerf.c | 9 +-------- drivers/pcmcia/soc_common.c | 12 ++++++++++++ drivers/pcmcia/soc_common.h | 2 ++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index 44cfc4416e54..71ace6910d7e 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -31,13 +31,6 @@ static int assabet_pcmcia_hw_init(struct soc_pcmcia_socket *skt) return 0; } -static void -assabet_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) -{ - state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ - state->vs_Xv = 0; -} - static int assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { @@ -90,7 +83,7 @@ static void assabet_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) static struct pcmcia_low_level assabet_pcmcia_ops = { .owner = THIS_MODULE, .hw_init = assabet_pcmcia_hw_init, - .socket_state = assabet_pcmcia_socket_state, + .socket_state = soc_common_cf_socket_state, .configure_socket = assabet_pcmcia_configure_socket, .socket_suspend = assabet_pcmcia_socket_suspend, }; diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index b3774e5d0396..c3f67363f6a1 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -45,13 +45,6 @@ static void cerf_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) gpio_free(CERF_GPIO_CF_RESET); } -static void -cerf_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) -{ - state->vs_3v = 1; - state->vs_Xv = 0; -} - static int cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) @@ -77,7 +70,7 @@ static struct pcmcia_low_level cerf_pcmcia_ops = { .owner = THIS_MODULE, .hw_init = cerf_pcmcia_hw_init, .hw_shutdown = cerf_pcmcia_hw_shutdown, - .socket_state = cerf_pcmcia_socket_state, + .socket_state = soc_common_cf_socket_state, .configure_socket = cerf_pcmcia_configure_socket, }; diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 9373d997d0cf..6d0ec291f475 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -229,6 +229,18 @@ static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt) irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE); } +/* + * The CF 3.0 specification says that cards tie VS1 to ground and leave + * VS2 open. Many implementations do not wire up the VS signals, so we + * provide hard-coded values as per the CF 3.0 spec. + */ +void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->vs_3v = 1; +} +EXPORT_SYMBOL_GPL(soc_common_cf_socket_state); + static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) { struct pcmcia_state state; diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 686ba3238c76..39c1e15167f3 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -143,6 +143,8 @@ void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt); int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt); int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt); +void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state); #ifdef CONFIG_PCMCIA_DEBUG -- cgit v1.2.1 From ac61b6001a636ab9aa954b5f9a996056cd8519f4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:46 +0100 Subject: pcmcia: soc_common: add support for Vcc and Vpp regulators Add support for handling supply regulators in the soc_common code. This allows us to separate out the board specifics for setting voltages from the PCMCIA code. We detect when setting a voltage fails, and report this fact - some platforms have fixed-voltage supplies (eg, for CF sockets at 3.3V) and we need to ignore attempts to configure for 5V, as per the existing board specific drivers. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 37 ++++++++++++++++++++++++++++++++++++- drivers/pcmcia/soc_common.h | 11 +++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 6d0ec291f475..15e332aca0f3 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,41 @@ EXPORT_SYMBOL(soc_pcmcia_debug); #define to_soc_pcmcia_socket(x) \ container_of(x, struct soc_pcmcia_socket, socket) +int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt, + struct soc_pcmcia_regulator *r, int v) +{ + bool on; + int ret; + + if (!r->reg) + return 0; + + on = v != 0; + if (r->on == on) + return 0; + + if (on) { + ret = regulator_set_voltage(r->reg, v * 100000, v * 100000); + if (ret) { + int vout = regulator_get_voltage(r->reg) / 100000; + + dev_warn(&skt->socket.dev, + "CS requested %s=%u.%uV, applying %u.%uV\n", + r == &skt->vcc ? "Vcc" : "Vpp", + v / 10, v % 10, vout / 10, vout % 10); + } + + ret = regulator_enable(r->reg); + } else { + regulator_disable(r->reg); + } + if (ret == 0) + r->on = on; + + return ret; +} +EXPORT_SYMBOL_GPL(soc_pcmcia_regulator_set); + static unsigned short calc_speed(unsigned short *spds, int num, unsigned short dflt) { @@ -119,7 +155,6 @@ static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt, if (skt->ops->hw_shutdown) skt->ops->hw_shutdown(skt); - clk_disable_unprepare(skt->clk); } diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 39c1e15167f3..18a6df5ca374 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -19,6 +19,12 @@ struct device; struct gpio_desc; struct pcmcia_low_level; +struct regulator; + +struct soc_pcmcia_regulator { + struct regulator *reg; + bool on; +}; /* * This structure encapsulates per-socket state which we might need to @@ -64,6 +70,8 @@ struct soc_pcmcia_socket { struct gpio_desc *gpio_reset; struct gpio_desc *gpio_bus_enable; + struct soc_pcmcia_regulator vcc; + struct soc_pcmcia_regulator vpp; unsigned int irq_state; @@ -146,6 +154,9 @@ int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt); void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state); +int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt, + struct soc_pcmcia_regulator *r, int v); + #ifdef CONFIG_PCMCIA_DEBUG extern void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func, -- cgit v1.2.1 From fb8c9959a3e2e4a28f58d9a9d056d633a3386524 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:46 +0100 Subject: pcmcia: soc_common: switch to a per-socket cpufreq notifier Switch to a per-socket cpufreq notifier rather than a global notifier. This allows each socket to be self-contained. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 77 ++++++++++++++------------------------------- drivers/pcmcia/soc_common.h | 3 ++ 2 files changed, 26 insertions(+), 54 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 15e332aca0f3..6138c14a5566 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -732,50 +732,15 @@ static struct pccard_operations soc_common_pcmcia_operations = { }; -static LIST_HEAD(soc_pcmcia_sockets); -static DEFINE_MUTEX(soc_pcmcia_sockets_lock); - #ifdef CONFIG_CPU_FREQ -static int -soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) +static int soc_common_pcmcia_cpufreq_nb(struct notifier_block *nb, + unsigned long val, void *data) { - struct soc_pcmcia_socket *skt; + struct soc_pcmcia_socket *skt = container_of(nb, struct soc_pcmcia_socket, cpufreq_nb); struct cpufreq_freqs *freqs = data; - int ret = 0; - - mutex_lock(&soc_pcmcia_sockets_lock); - list_for_each_entry(skt, &soc_pcmcia_sockets, node) - if (skt->ops->frequency_change) - ret += skt->ops->frequency_change(skt, val, freqs); - mutex_unlock(&soc_pcmcia_sockets_lock); - - return ret; -} - -static struct notifier_block soc_pcmcia_notifier_block = { - .notifier_call = soc_pcmcia_notifier -}; - -static int soc_pcmcia_cpufreq_register(void) -{ - int ret; - - ret = cpufreq_register_notifier(&soc_pcmcia_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (ret < 0) - printk(KERN_ERR "Unable to register CPU frequency change " - "notifier for PCMCIA (%d)\n", ret); - return ret; -} -fs_initcall(soc_pcmcia_cpufreq_register); -static void soc_pcmcia_cpufreq_unregister(void) -{ - cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); + return skt->ops->frequency_change(skt, val, freqs); } -module_exit(soc_pcmcia_cpufreq_unregister); - #endif void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt, @@ -795,19 +760,21 @@ EXPORT_SYMBOL(soc_pcmcia_init_one); void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt) { - mutex_lock(&soc_pcmcia_sockets_lock); del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); +#ifdef CONFIG_CPU_FREQ + if (skt->ops->frequency_change) + cpufreq_unregister_notifier(&skt->cpufreq_nb, + CPUFREQ_TRANSITION_NOTIFIER); +#endif + soc_pcmcia_hw_shutdown(skt); /* should not be required; violates some lowlevel drivers */ soc_common_pcmcia_config_skt(skt, &dead_socket); - list_del(&skt->node); - mutex_unlock(&soc_pcmcia_sockets_lock); - iounmap(skt->virt_io); skt->virt_io = NULL; release_resource(&skt->res_attr); @@ -849,10 +816,6 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) goto out_err_5; } - mutex_lock(&soc_pcmcia_sockets_lock); - - list_add(&skt->node, &soc_pcmcia_sockets); - /* * We initialize default socket timing here, because * we are not guaranteed to see a SetIOMap operation at @@ -873,14 +836,23 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) skt->status = soc_common_pcmcia_skt_state(skt); +#ifdef CONFIG_CPU_FREQ + if (skt->ops->frequency_change) { + skt->cpufreq_nb.notifier_call = soc_common_pcmcia_cpufreq_nb; + + ret = cpufreq_register_notifier(&skt->cpufreq_nb, + CPUFREQ_TRANSITION_NOTIFIER); + if (ret < 0) + dev_err(skt->socket.dev.parent, + "unable to register CPU frequency change notifier for PCMCIA (%d)\n", + ret); + } +#endif + ret = pcmcia_register_socket(&skt->socket); if (ret) goto out_err_7; - add_timer(&skt->poll_timer); - - mutex_unlock(&soc_pcmcia_sockets_lock); - ret = device_create_file(&skt->socket.dev, &dev_attr_status); if (ret) goto out_err_8; @@ -888,15 +860,12 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) return ret; out_err_8: - mutex_lock(&soc_pcmcia_sockets_lock); del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); out_err_7: soc_pcmcia_hw_shutdown(skt); out_err_6: - list_del(&skt->node); - mutex_unlock(&soc_pcmcia_sockets_lock); iounmap(skt->virt_io); out_err_5: release_resource(&skt->res_attr); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 18a6df5ca374..f66e2fb1f33f 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -75,6 +75,9 @@ struct soc_pcmcia_socket { unsigned int irq_state; +#ifdef CONFIG_CPU_FREQ + struct notifier_block cpufreq_nb; +#endif struct timer_list poll_timer; struct list_head node; }; -- cgit v1.2.1 From c8f9ce556ba2fca6b9abdfac508afb9905aac6b8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:46 +0100 Subject: pcmcia: soc_common: constify pcmcia_low_level ops pointer Constify the pcmcia_low_level operation pointer to soc_pcmcia_init_one() which has no need to modify it. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 2 +- drivers/pcmcia/soc_common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 6138c14a5566..3eb30916be26 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -744,7 +744,7 @@ static int soc_common_pcmcia_cpufreq_nb(struct notifier_block *nb, #endif void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt, - struct pcmcia_low_level *ops, struct device *dev) + const struct pcmcia_low_level *ops, struct device *dev) { int i; diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index f66e2fb1f33f..7833eae86960 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -149,7 +149,7 @@ struct soc_pcmcia_timing { extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *); void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt, - struct pcmcia_low_level *ops, struct device *dev); + const struct pcmcia_low_level *ops, struct device *dev); void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt); int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt); int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt); -- cgit v1.2.1 From 5805271d908aa34912265dba41bcb902588e0ff7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 11:28:19 +0100 Subject: pcmcia: soc_common: add support for voltage sense GPIOs Add support for the voltage sense GPIOs which are wired up on some platforms. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.c | 6 +++++- drivers/pcmcia/soc_common.h | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 3eb30916be26..153f3122283d 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -218,7 +218,7 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio); } - if (skt->stat[i].desc) { + if (i < SOC_STAT_VS1 && skt->stat[i].desc) { int irq = gpiod_to_irq(skt->stat[i].desc); if (irq > 0) { @@ -295,6 +295,10 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc); if (skt->stat[SOC_STAT_BVD2].desc) state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc); + if (skt->stat[SOC_STAT_VS1].desc) + state.vs_3v = !!gpiod_get_value(skt->stat[SOC_STAT_VS1].desc); + if (skt->stat[SOC_STAT_VS2].desc) + state.vs_Xv = !!gpiod_get_value(skt->stat[SOC_STAT_VS2].desc); skt->ops->socket_state(skt, &state); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 7833eae86960..f2078aecb914 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -62,11 +62,13 @@ struct soc_pcmcia_socket { struct gpio_desc *desc; unsigned int irq; const char *name; - } stat[4]; + } stat[6]; #define SOC_STAT_CD 0 /* Card detect */ #define SOC_STAT_BVD1 1 /* BATDEAD / IOSTSCHG */ #define SOC_STAT_BVD2 2 /* BATWARN / IOSPKR */ #define SOC_STAT_RDY 3 /* Ready / Interrupt */ +#define SOC_STAT_VS1 4 /* Voltage sense 1 */ +#define SOC_STAT_VS2 5 /* Voltage sense 2 */ struct gpio_desc *gpio_reset; struct gpio_desc *gpio_bus_enable; -- cgit v1.2.1 From 4a5d67d7346619f4a45b5d6f7a496db2e0e8545d Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2016 08:49:47 +0100 Subject: pcmcia: soc_common: add driver-data pointer Add a driver-data pointer so that low level drivers can add additional data to the soc_common pcmcia socket structure. Signed-off-by: Russell King --- drivers/pcmcia/soc_common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index f2078aecb914..3f3625805353 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -82,6 +82,7 @@ struct soc_pcmcia_socket { #endif struct timer_list poll_timer; struct list_head node; + void *driver_data; }; struct skt_dev_info { -- cgit v1.2.1