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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index d5ca760..24ac27f 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 24ac27f..e07d84a 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 94762a5..ee40db1 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index e07d84a..e499c2b 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index e499c2b..4036454 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 4036454..f772127 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 ee40db1..686ba32 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index f772127..9373d99 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 v0.10.2 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 diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index 44cfc44..71ace69 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 b3774e5..c3f6736 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 9373d99..6d0ec29 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 686ba32..39c1e15 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 6d0ec29..15e332a 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 39c1e15..18a6df5 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 15e332a..6138c14 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 18a6df5..f66e2fb 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 6138c14..3eb3091 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 f66e2fb..7833eae 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 3eb3091..153f312 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 7833eae..f2078aec 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 v0.10.2 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 diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index f2078aec..3f36258 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 v0.10.2