Merge branch 'pcmcia' of git://git.armlinux.org.uk/~rmk/linux-arm
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Oct 2016 18:34:28 +0000 (11:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Oct 2016 18:34:28 +0000 (11:34 -0700)
Pull ARM pcmcia updates from Russell King:
 "These updates lay the foundations for more generic soc_common PCMCIA
  support, which will result in several of the board specific drivers
  being elimated.

  As the dependencies for this are complex, the preliminary work is
  being submitted now, with the remainder scheduled for the next merge
  window"

* 'pcmcia' of git://git.armlinux.org.uk/~rmk/linux-arm:
  pcmcia: soc_common: add driver-data pointer
  pcmcia: soc_common: add support for voltage sense GPIOs
  pcmcia: soc_common: constify pcmcia_low_level ops pointer
  pcmcia: soc_common: switch to a per-socket cpufreq notifier
  pcmcia: soc_common: add support for Vcc and Vpp regulators
  pcmcia: soc_common: add CF socket state helper
  pcmcia: soc_common: restore previous socket state on error
  pcmcia: soc_common: add support for reset and bus enable GPIOs
  pcmcia: soc_common: request legacy detect GPIO with active low
  pcmcia: soc_common: ignore invalid interrupts
  pcmcia: soc_common: switch to using gpio_descs
  pcmcia: soc_common: use devm_gpio_request_one()

drivers/pcmcia/sa1100_assabet.c
drivers/pcmcia/sa1100_cerf.c
drivers/pcmcia/soc_common.c
drivers/pcmcia/soc_common.h

index 44cfc44..71ace69 100644 (file)
@@ -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,
 };
index b3774e5..c3f6736 100644 (file)
@@ -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,
 };
 
index d5ca760..153f312 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <linux/cpufreq.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -42,6 +43,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
 #include <linux/spinlock.h>
 #include <linux/timer.h>
 
@@ -79,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)
 {
@@ -111,12 +148,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);
@@ -129,6 +163,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;
@@ -143,21 +201,32 @@ 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;
+                       unsigned long flags = GPIOF_IN;
 
-                       ret = gpio_request_one(skt->stat[i].gpio, GPIOF_IN,
-                                              skt->stat[i].name);
+                       /* 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, flags,
+                                                   skt->stat[i].name);
                        if (ret) {
                                __soc_pcmcia_hw_shutdown(skt, i);
                                return ret;
                        }
 
-                       irq = gpio_to_irq(skt->stat[i].gpio);
+                       skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
+               }
+
+               if (i < SOC_STAT_VS1 && 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) {
@@ -166,8 +235,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;
                        }
@@ -197,6 +264,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;
@@ -208,17 +287,18 @@ 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 (gpio_is_valid(skt->stat[SOC_STAT_CD].gpio))
-               state.detect = !gpio_get_value(skt->stat[SOC_STAT_CD].gpio);
-
-       /* 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_CD].desc)
+               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)
+               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);
 
@@ -257,7 +337,30 @@ 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;
+
+               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.
@@ -274,10 +377,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;
 }
 
@@ -637,54 +736,19 @@ 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;
+       return skt->ops->frequency_change(skt, val, freqs);
 }
-fs_initcall(soc_pcmcia_cpufreq_register);
-
-static void soc_pcmcia_cpufreq_unregister(void)
-{
-       cpufreq_unregister_notifier(&soc_pcmcia_notifier_block,
-               CPUFREQ_TRANSITION_NOTIFIER);
-}
-module_exit(soc_pcmcia_cpufreq_unregister);
-
 #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;
 
@@ -700,19 +764,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);
@@ -726,6 +792,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;
@@ -752,10 +820,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
@@ -776,14 +840,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;
@@ -791,15 +864,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);
index 94762a5..3f36258 100644 (file)
 
 
 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
@@ -52,18 +59,30 @@ struct soc_pcmcia_socket {
 
        struct {
                int             gpio;
+               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;
+       struct soc_pcmcia_regulator vcc;
+       struct soc_pcmcia_regulator vpp;
 
        unsigned int            irq_state;
 
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block   cpufreq_nb;
+#endif
        struct timer_list       poll_timer;
        struct list_head        node;
+       void *driver_data;
 };
 
 struct skt_dev_info {
@@ -133,10 +152,16 @@ 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);
+
+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