]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
WIP:pwrseq: Convert in to proper platform device
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Thu, 17 Sep 2015 09:17:05 +0000 (10:17 +0100)
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Mon, 11 Jan 2016 09:53:57 +0000 (09:53 +0000)
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
drivers/mmc/Kconfig
drivers/mmc/core/Kconfig
drivers/mmc/core/Makefile
drivers/mmc/core/pwrseq.c
drivers/mmc/core/pwrseq.h
drivers/mmc/core/pwrseq_emmc.c
drivers/mmc/core/pwrseq_simple.c

index f2eeb38efa653387b42cb8bf9ccc0ba4e0f17969..bc08c3b1335c45c926bf39d626e5cf730a7243ee 100644 (file)
@@ -5,6 +5,8 @@
 menuconfig MMC
        tristate "MMC/SD/SDIO card support"
        depends on HAS_IOMEM
+       select PWRSEQ_SIMPLE
+       select PWRSEQ_EMMC
        help
          This selects MultiMediaCard, Secure Digital and Secure
          Digital I/O support.
index 4c33d7690f2f66c4f8eb244480d06bce58acd3f1..b26f7560144669fc44b5697e4ed7933dd5c871f5 100644 (file)
@@ -1,3 +1,10 @@
 #
 # MMC core configuration
 #
+config PWRSEQ_EMMC
+       tristate "PwrSeq EMMC"
+       depends on OF
+
+config PWRSEQ_SIMPLE
+       tristate "PwrSeq Simple"
+       depends on OF
index 2c25138f28b73d2de48b50b73ffb8d07cce26b85..b281675edb928237660622ceea1ee04e05cd5ea7 100644 (file)
@@ -8,5 +8,7 @@ mmc_core-y                      := core.o bus.o host.o \
                                   sdio.o sdio_ops.o sdio_bus.o \
                                   sdio_cis.o sdio_io.o sdio_irq.o \
                                   quirks.o slot-gpio.o
-mmc_core-$(CONFIG_OF)          += pwrseq.o pwrseq_simple.o pwrseq_emmc.o
+mmc_core-$(CONFIG_OF)          += pwrseq.o
 mmc_core-$(CONFIG_DEBUG_FS)    += debugfs.o
+obj-$(CONFIG_PWRSEQ_SIMPLE)    += pwrseq_simple.o
+obj-$(CONFIG_PWRSEQ_EMMC)      += pwrseq_emmc.o
index 4c1d1757dbf977f2dbe3a653cfcadbcc02e30cb6..c728714e8d9f05562fd18ff1eb983014e2914787 100644 (file)
@@ -8,50 +8,28 @@
  *  MMC power sequence management
  */
 #include <linux/kernel.h>
-#include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/of.h>
-#include <linux/of_platform.h>
-
 #include <linux/mmc/host.h>
-
 #include "pwrseq.h"
 
-struct mmc_pwrseq_match {
-       const char *compatible;
-       struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev);
-};
-
-static struct mmc_pwrseq_match pwrseq_match[] = {
-       {
-               .compatible = "mmc-pwrseq-simple",
-               .alloc = mmc_pwrseq_simple_alloc,
-       }, {
-               .compatible = "mmc-pwrseq-emmc",
-               .alloc = mmc_pwrseq_emmc_alloc,
-       },
-};
-
-static struct mmc_pwrseq_match *mmc_pwrseq_find(struct device_node *np)
+static DEFINE_MUTEX(pwrseq_list_mutex);
+static LIST_HEAD(pwrseq_list);
+
+static struct mmc_pwrseq *of_find_mmc_pwrseq(struct device_node *np)
 {
-       struct mmc_pwrseq_match *match = ERR_PTR(-ENODEV);
-       int i;
+       struct mmc_pwrseq *p;
 
-       for (i = 0; i < ARRAY_SIZE(pwrseq_match); i++) {
-               if (of_device_is_compatible(np, pwrseq_match[i].compatible)) {
-                       match = &pwrseq_match[i];
-                       break;
-               }
-       }
+       list_for_each_entry(p, &pwrseq_list, list)
+               if (p->dev->of_node == np)
+                       return p;
 
-       return match;
+       return NULL;
 }
 
 int mmc_pwrseq_alloc(struct mmc_host *host)
 {
-       struct platform_device *pdev;
        struct device_node *np;
-       struct mmc_pwrseq_match *match;
        struct mmc_pwrseq *pwrseq;
        int ret = 0;
 
@@ -59,25 +37,18 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
        if (!np)
                return 0;
 
-       pdev = of_find_device_by_node(np);
-       if (!pdev) {
-               ret = -ENODEV;
-               goto err;
-       }
-
-       match = mmc_pwrseq_find(np);
-       if (IS_ERR(match)) {
-               ret = PTR_ERR(match);
-               goto err;
-       }
+       pwrseq = of_find_mmc_pwrseq(np);
 
-       pwrseq = match->alloc(host, &pdev->dev);
-       if (IS_ERR(pwrseq)) {
-               ret = PTR_ERR(pwrseq);
-               goto err;
+       if (pwrseq && pwrseq->ops && pwrseq->ops->alloc) {
+               host->pwrseq = pwrseq;
+               ret = pwrseq->ops->alloc(host);
+               if (IS_ERR_VALUE(ret)) {
+                       host->pwrseq = NULL;
+                       goto err;
+               }
        }
+       pwrseq->users++;
 
-       host->pwrseq = pwrseq;
        dev_info(host->parent, "allocated mmc-pwrseq\n");
 
 err:
@@ -113,8 +84,37 @@ void mmc_pwrseq_free(struct mmc_host *host)
 {
        struct mmc_pwrseq *pwrseq = host->pwrseq;
 
+       printk("DEBUG::::::::::: %p %p \n", host, pwrseq);
        if (pwrseq && pwrseq->ops && pwrseq->ops->free)
                pwrseq->ops->free(host);
 
+       if (pwrseq)
+               pwrseq->users--;
        host->pwrseq = NULL;
 }
+
+int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
+{
+       if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
+               return -EINVAL;
+
+       mutex_lock(&pwrseq_list_mutex);
+       list_add(&pwrseq->list, &pwrseq_list);
+       mutex_unlock(&pwrseq_list_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
+
+int mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
+{
+       if (!pwrseq->users) {
+               mutex_lock(&pwrseq_list_mutex);
+               list_del(&pwrseq->list);
+               mutex_unlock(&pwrseq_list_mutex);
+               return 0;
+       }
+
+       return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);
index 096da48c6a7ecbb0ba294e6fd1bf9513b02bca36..462c0abfb651da30e117960cbf506a147202ccf7 100644 (file)
@@ -8,7 +8,10 @@
 #ifndef _MMC_CORE_PWRSEQ_H
 #define _MMC_CORE_PWRSEQ_H
 
+#include <linux/mmc/host.h>
+
 struct mmc_pwrseq_ops {
+       int (*alloc)(struct mmc_host *host);
        void (*pre_power_on)(struct mmc_host *host);
        void (*post_power_on)(struct mmc_host *host);
        void (*power_off)(struct mmc_host *host);
@@ -17,23 +20,35 @@ struct mmc_pwrseq_ops {
 
 struct mmc_pwrseq {
        struct mmc_pwrseq_ops *ops;
+       struct device *dev;
+       struct list_head list;
+       int users;
+       
 };
 
 #ifdef CONFIG_OF
 
+int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq);
+int mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq);
+
 int mmc_pwrseq_alloc(struct mmc_host *host);
 void mmc_pwrseq_pre_power_on(struct mmc_host *host);
 void mmc_pwrseq_post_power_on(struct mmc_host *host);
 void mmc_pwrseq_power_off(struct mmc_host *host);
 void mmc_pwrseq_free(struct mmc_host *host);
 
-struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
-                                          struct device *dev);
-struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
-                                        struct device *dev);
-
 #else
 
+static inline int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
+{
+       return -ENOSYS;
+}
+
+static inline int mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
+{
+       return -ENOSYS;
+}
+
 static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
 static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {}
 static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
index ad4f94ec7e8d465a4e4e45ba9388fb7d97231f4a..ccecf30043971273fe68d8419a899a6529eb4256 100644 (file)
@@ -9,6 +9,8 @@
  */
 #include <linux/delay.h>
 #include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -16,7 +18,6 @@
 #include <linux/reboot.h>
 
 #include <linux/mmc/host.h>
-
 #include "pwrseq.h"
 
 struct mmc_pwrseq_emmc {
@@ -25,6 +26,8 @@ struct mmc_pwrseq_emmc {
        struct gpio_desc *reset_gpio;
 };
 
+#define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq)
+
 static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
 {
        gpiod_set_value(pwrseq->reset_gpio, 1);
@@ -35,52 +38,37 @@ static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
 
 static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
 {
-       struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
-                                       struct mmc_pwrseq_emmc, pwrseq);
+       struct mmc_pwrseq_emmc *pwrseq =  to_pwrseq_emmc(host->pwrseq);
 
        __mmc_pwrseq_emmc_reset(pwrseq);
 }
 
 static void mmc_pwrseq_emmc_free(struct mmc_host *host)
 {
-       struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
-                                       struct mmc_pwrseq_emmc, pwrseq);
+       struct mmc_pwrseq_emmc *pwrseq =  to_pwrseq_emmc(host->pwrseq);
 
        unregister_restart_handler(&pwrseq->reset_nb);
        gpiod_put(pwrseq->reset_gpio);
-       kfree(pwrseq);
 }
 
-static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
-       .post_power_on = mmc_pwrseq_emmc_reset,
-       .free = mmc_pwrseq_emmc_free,
-};
-
 static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
                                    unsigned long mode, void *cmd)
 {
        struct mmc_pwrseq_emmc *pwrseq = container_of(this,
-                                       struct mmc_pwrseq_emmc, reset_nb);
+                               struct mmc_pwrseq_emmc, reset_nb);
 
        __mmc_pwrseq_emmc_reset(pwrseq);
        return NOTIFY_DONE;
 }
 
-struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
-                                        struct device *dev)
+static int mmc_pwrseq_emmc_alloc(struct mmc_host *host)
 {
-       struct mmc_pwrseq_emmc *pwrseq;
-       int ret = 0;
-
-       pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);
-       if (!pwrseq)
-               return ERR_PTR(-ENOMEM);
-
-       pwrseq->reset_gpio = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
-       if (IS_ERR(pwrseq->reset_gpio)) {
-               ret = PTR_ERR(pwrseq->reset_gpio);
-               goto free;
-       }
+       struct mmc_pwrseq_emmc *pwrseq =  to_pwrseq_emmc(host->pwrseq);
+       
+       pwrseq->reset_gpio = gpiod_get(host->pwrseq->dev,
+                                       "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(pwrseq->reset_gpio))
+               return PTR_ERR(pwrseq->reset_gpio);
 
        /*
         * register reset handler to ensure emmc reset also from
@@ -91,10 +79,53 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
        pwrseq->reset_nb.priority = 255;
        register_restart_handler(&pwrseq->reset_nb);
 
+       return 0;
+}
+
+static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
+       .alloc = mmc_pwrseq_emmc_alloc,
+       .post_power_on = mmc_pwrseq_emmc_reset,
+       .free = mmc_pwrseq_emmc_free,
+};
+
+static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
+{
+       struct mmc_pwrseq_emmc *pwrseq;
+       struct device *dev = &pdev->dev;
+
+       pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
+       if (!pwrseq)
+               return -ENOMEM;
+
        pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
+       pwrseq->pwrseq.dev = dev;
+
+       platform_set_drvdata(pdev, pwrseq);
 
-       return &pwrseq->pwrseq;
-free:
-       kfree(pwrseq);
-       return ERR_PTR(ret);
+       return mmc_pwrseq_register(&pwrseq->pwrseq);
 }
+
+static int mmc_pwrseq_emmc_remove(struct platform_device *pdev)
+{
+       struct mmc_pwrseq_emmc *spwrseq = platform_get_drvdata(pdev);
+
+       return mmc_pwrseq_unregister(&spwrseq->pwrseq);
+}
+
+static const struct of_device_id mmc_pwrseq_emmc_of_match[] = {
+       { .compatible = "mmc-pwrseq-emmc",},
+       {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match);
+
+static struct platform_driver mmc_pwrseq_emmc_driver = {
+       .probe = mmc_pwrseq_emmc_probe,
+       .remove = mmc_pwrseq_emmc_remove,
+       .driver = {
+               .name = "pwrseq_emmc",
+               .of_match_table = mmc_pwrseq_emmc_of_match,
+       },
+};
+
+module_platform_driver(mmc_pwrseq_emmc_driver);
+MODULE_LICENSE("GPL v2");
index d10538bb5e07ac298fcadad3003bd84c02fa00d5..8fb4ed9e7e014fd70ef4223d4e9b6ca402fcd3c2 100644 (file)
@@ -9,6 +9,7 @@
  */
 #include <linux/clk.h>
 #include <linux/kernel.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -26,6 +27,8 @@ struct mmc_pwrseq_simple {
        struct gpio_descs *reset_gpios;
 };
 
+#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
+
 static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
                                              int value)
 {
@@ -42,8 +45,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
 
 static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
 {
-       struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
-                                       struct mmc_pwrseq_simple, pwrseq);
+       struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
 
        if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
                clk_prepare_enable(pwrseq->ext_clk);
@@ -55,16 +57,14 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
 
 static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
 {
-       struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
-                                       struct mmc_pwrseq_simple, pwrseq);
+       struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
 
        mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
 }
 
 static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
 {
-       struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
-                                       struct mmc_pwrseq_simple, pwrseq);
+       struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
 
        mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
 
@@ -76,54 +76,90 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
 
 static void mmc_pwrseq_simple_free(struct mmc_host *host)
 {
-       struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
-                                       struct mmc_pwrseq_simple, pwrseq);
+       struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
 
        gpiod_put_array(pwrseq->reset_gpios);
 
        if (!IS_ERR(pwrseq->ext_clk))
                clk_put(pwrseq->ext_clk);
 
-       kfree(pwrseq);
 }
 
-static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
-       .pre_power_on = mmc_pwrseq_simple_pre_power_on,
-       .post_power_on = mmc_pwrseq_simple_post_power_on,
-       .power_off = mmc_pwrseq_simple_power_off,
-       .free = mmc_pwrseq_simple_free,
-};
-
-struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
-                                          struct device *dev)
+int mmc_pwrseq_simple_alloc(struct mmc_host *host)
 {
-       struct mmc_pwrseq_simple *pwrseq;
-       int ret = 0;
-
-       pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
-       if (!pwrseq)
-               return ERR_PTR(-ENOMEM);
+       struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
+       struct device *dev = host->pwrseq->dev;
+       int i, ret = 0;
 
        pwrseq->ext_clk = clk_get(dev, "ext_clock");
        if (IS_ERR(pwrseq->ext_clk) &&
            PTR_ERR(pwrseq->ext_clk) != -ENOENT) {
-               ret = PTR_ERR(pwrseq->ext_clk);
-               goto free;
+               return PTR_ERR(pwrseq->ext_clk);
+       
        }
 
        pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
        if (IS_ERR(pwrseq->reset_gpios)) {
                ret = PTR_ERR(pwrseq->reset_gpios);
-               goto clk_put;
+               clk_put(pwrseq->ext_clk);
+               return ret;
        }
 
-       pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
+       return 0;
+}
 
-       return &pwrseq->pwrseq;
-clk_put:
-       if (!IS_ERR(pwrseq->ext_clk))
-               clk_put(pwrseq->ext_clk);
-free:
-       kfree(pwrseq);
-       return ERR_PTR(ret);
+static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
+       .alloc = mmc_pwrseq_simple_alloc,
+       .pre_power_on = mmc_pwrseq_simple_pre_power_on,
+       .post_power_on = mmc_pwrseq_simple_post_power_on,
+       .power_off = mmc_pwrseq_simple_power_off,
+       .free = mmc_pwrseq_simple_free,
+};
+
+static const struct of_device_id mmc_pwrseq_simple_of_match[] = {
+       { .compatible = "mmc-pwrseq-simple",},
+       {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, mmc_pwrseq_simple_of_match);
+
+static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
+{
+       struct mmc_pwrseq_simple *spwrseq;
+       struct device *dev = &pdev->dev;
+       int nr_gpios;
+
+       nr_gpios = of_gpio_named_count(dev->of_node, "reset-gpios");
+       if (nr_gpios < 0)
+               nr_gpios = 0;
+
+       spwrseq = devm_kzalloc(dev, sizeof(struct mmc_pwrseq_simple) + nr_gpios *
+                        sizeof(struct gpio_desc *), GFP_KERNEL);
+       if (!spwrseq)
+               return -ENOMEM;
+
+       spwrseq->pwrseq.dev = dev;
+       spwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
+
+       platform_set_drvdata(pdev, spwrseq);
+
+       return mmc_pwrseq_register(&spwrseq->pwrseq);
+}
+
+static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
+{
+       struct mmc_pwrseq_simple *spwrseq = platform_get_drvdata(pdev);
+
+       return mmc_pwrseq_unregister(&spwrseq->pwrseq);
 }
+
+static struct platform_driver mmc_pwrseq_simple_driver = {
+       .probe = mmc_pwrseq_simple_probe,
+       .remove = mmc_pwrseq_simple_remove,
+       .driver = {
+               .name = "pwrseq_simple",
+               .of_match_table = mmc_pwrseq_simple_of_match,
+       },
+};
+
+module_platform_driver(mmc_pwrseq_simple_driver);
+MODULE_LICENSE("GPL v2");