@@ -8,6 +8,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+
+#define DRV_NAME "sh-pfc"
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/errno.h>
@@ -20,11 +22,10 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/pinctrl/machine.h>
+#include <linux/platform_device.h>
#include "core.h"
-static struct sh_pfc sh_pfc __read_mostly;
-
static void pfc_iounmap(struct sh_pfc *pfc)
{
int k;
@@ -494,8 +495,10 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
return -1;
}
-int register_sh_pfc(struct sh_pfc_platform_data *pdata)
+static int sh_pfc_probe(struct platform_device *pdev)
{
+ struct sh_pfc_platform_data *pdata = pdev->dev.platform_data;
+ struct sh_pfc *pfc;
int ret;
/*
@@ -503,26 +506,29 @@ int register_sh_pfc(struct sh_pfc_platform_data *pdata)
*/
BUILD_BUG_ON(PINMUX_FLAG_TYPE > ((1 << PINMUX_FLAG_DBIT_SHIFT) - 1));
- if (sh_pfc.pdata)
- return -EBUSY;
+ if (pdata == NULL)
+ return -ENODEV;
- sh_pfc.pdata = pdata;
+ pfc = devm_kzalloc(&pdev->dev, sizeof(pfc), GFP_KERNEL);
+ if (pfc == NULL)
+ return -ENOMEM;
- ret = pfc_ioremap(&sh_pfc);
- if (unlikely(ret < 0)) {
- sh_pfc.pdata = NULL;
+ pfc->pdata = pdata;
+ pfc->dev = &pdev->dev;
+
+ ret = pfc_ioremap(pfc);
+ if (unlikely(ret < 0))
return ret;
- }
- spin_lock_init(&sh_pfc.lock);
+ spin_lock_init(&pfc->lock);
pinctrl_provide_dummies();
- setup_data_regs(&sh_pfc);
+ setup_data_regs(pfc);
/*
* Initialize pinctrl bindings first
*/
- ret = sh_pfc_register_pinctrl(&sh_pfc);
+ ret = sh_pfc_register_pinctrl(pfc);
if (unlikely(ret != 0))
goto err;
@@ -530,7 +536,7 @@ int register_sh_pfc(struct sh_pfc_platform_data *pdata)
/*
* Then the GPIO chip
*/
- ret = sh_pfc_register_gpiochip(&sh_pfc);
+ ret = sh_pfc_register_gpiochip(pfc);
if (unlikely(ret != 0)) {
/*
* If the GPIO chip fails to come up we still leave the
@@ -541,17 +547,76 @@ int register_sh_pfc(struct sh_pfc_platform_data *pdata)
}
#endif
- pr_info("%s support registered\n", sh_pfc.pdata->name);
+ platform_set_drvdata(pdev, pfc);
+
+ pr_info("%s support registered\n", pdata->name);
return 0;
err:
- pfc_iounmap(&sh_pfc);
- sh_pfc.pdata = NULL;
-
+ pfc_iounmap(pfc);
return ret;
}
+static int __devexit sh_pfc_remove(struct platform_device *pdev)
+{
+ struct sh_pfc *pfc = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_GPIO_SH_PFC
+ sh_pfc_unregister_gpiochip(pfc);
+#endif
+ sh_pfc_unregister_pinctrl(pfc);
+
+ pfc_iounmap(pfc);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct platform_device_id sh_pfc_id_table[] = {
+ { "sh-pfc", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, sh_pfc_id_table);
+
+static struct platform_driver sh_pfc_driver = {
+ .probe = sh_pfc_probe,
+ .remove = __devexit_p(sh_pfc_remove),
+ .id_table = sh_pfc_id_table,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct platform_device sh_pfc_device = {
+ .name = DRV_NAME,
+ .id = -1,
+};
+
+int __init register_sh_pfc(struct sh_pfc_platform_data *pdata)
+{
+ int rc;
+
+ sh_pfc_device.dev.platform_data = pdata;
+
+ rc = platform_driver_register(&sh_pfc_driver);
+ if (likely(!rc)) {
+ rc = platform_device_register(&sh_pfc_device);
+ if (unlikely(rc))
+ platform_driver_unregister(&sh_pfc_driver);
+ }
+
+ return rc;
+}
+
+static void __exit sh_pfc_exit(void)
+{
+ platform_driver_unregister(&sh_pfc_driver);
+}
+module_exit(sh_pfc_exit);
+
MODULE_AUTHOR("Magnus Damm, Paul Mundt");
MODULE_DESCRIPTION("Pin Control and GPIO driver for SuperH pin function controller");
MODULE_LICENSE("GPL v2");
@@ -21,19 +21,23 @@ struct pfc_window {
};
struct sh_pfc_chip;
+struct sh_pfc_pinctrl;
struct sh_pfc {
+ struct device *dev;
struct sh_pfc_platform_data *pdata;
spinlock_t lock;
struct pfc_window *window;
struct sh_pfc_chip *gpio;
+ struct sh_pfc_pinctrl *pinctrl;
};
int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc);
int sh_pfc_register_pinctrl(struct sh_pfc *pfc);
+int sh_pfc_unregister_pinctrl(struct sh_pfc *pfc);
int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos);
void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
@@ -8,7 +8,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#define pr_fmt(fmt) "sh_pfc " KBUILD_MODNAME ": " fmt
+
+#define pr_fmt(fmt) KBUILD_MODNAME " gpio: " fmt
#include <linux/init.h>
#include <linux/gpio.h>
@@ -7,8 +7,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#define DRV_NAME "pinctrl-sh_pfc"
+#define DRV_NAME "sh-pfc"
#define pr_fmt(fmt) KBUILD_MODNAME " pinctrl: " fmt
#include <linux/init.h>
@@ -17,7 +17,6 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
@@ -39,8 +38,6 @@ struct sh_pfc_pinctrl {
spinlock_t lock;
};
-static struct sh_pfc_pinctrl *sh_pfc_pmx;
-
static int sh_pfc_get_groups_count(struct pinctrl_dev *pctldev)
{
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
@@ -423,28 +420,31 @@ static int __devinit sh_pfc_map_functions(struct sh_pfc *pfc,
return 0;
}
-static int __devinit sh_pfc_pinctrl_probe(struct platform_device *pdev)
+int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
{
- struct sh_pfc *pfc;
+ struct sh_pfc_pinctrl *pmx;
int ret;
- if (unlikely(!sh_pfc_pmx))
- return -ENODEV;
+ pmx = kzalloc(sizeof(struct sh_pfc_pinctrl), GFP_KERNEL);
+ if (unlikely(!pmx))
+ return -ENOMEM;
+
+ spin_lock_init(&pmx->lock);
- pfc = sh_pfc_pmx->pfc;
+ pmx->pfc = pfc;
+ pfc->pinctrl = pmx;
- ret = sh_pfc_map_gpios(pfc, sh_pfc_pmx);
+ ret = sh_pfc_map_gpios(pfc, pmx);
if (unlikely(ret != 0))
return ret;
- ret = sh_pfc_map_functions(pfc, sh_pfc_pmx);
+ ret = sh_pfc_map_functions(pfc, pmx);
if (unlikely(ret != 0))
goto free_pads;
- sh_pfc_pmx->pctl = pinctrl_register(&sh_pfc_pinctrl_desc, &pdev->dev,
- sh_pfc_pmx);
- if (IS_ERR(sh_pfc_pmx->pctl)) {
- ret = PTR_ERR(sh_pfc_pmx->pctl);
+ pmx->pctl = pinctrl_register(&sh_pfc_pinctrl_desc, pfc->dev, pmx);
+ if (IS_ERR(pmx->pctl)) {
+ ret = PTR_ERR(pmx->pctl);
goto free_functions;
}
@@ -453,79 +453,29 @@ static int __devinit sh_pfc_pinctrl_probe(struct platform_device *pdev)
sh_pfc_gpio_range.base = pfc->pdata->first_gpio;
sh_pfc_gpio_range.pin_base = pfc->pdata->first_gpio;
- pinctrl_add_gpio_range(sh_pfc_pmx->pctl, &sh_pfc_gpio_range);
-
- platform_set_drvdata(pdev, sh_pfc_pmx);
+ pinctrl_add_gpio_range(pmx->pctl, &sh_pfc_gpio_range);
return 0;
free_functions:
- kfree(sh_pfc_pmx->functions);
+ kfree(pmx->functions);
free_pads:
- kfree(sh_pfc_pmx->pads);
- kfree(sh_pfc_pmx);
+ kfree(pmx->pads);
+ kfree(pmx);
return ret;
}
-static int __devexit sh_pfc_pinctrl_remove(struct platform_device *pdev)
+int __devexit sh_pfc_unregister_pinctrl(struct sh_pfc *pfc)
{
- struct sh_pfc_pinctrl *pmx = platform_get_drvdata(pdev);
+ struct sh_pfc_pinctrl *pmx = pfc->pinctrl;
pinctrl_unregister(pmx->pctl);
- platform_set_drvdata(pdev, NULL);
-
- kfree(sh_pfc_pmx->functions);
- kfree(sh_pfc_pmx->pads);
- kfree(sh_pfc_pmx);
+ kfree(pmx->functions);
+ kfree(pmx->pads);
+ kfree(pmx);
+ pfc->pinctrl = NULL;
return 0;
}
-
-static struct platform_driver sh_pfc_pinctrl_driver = {
- .probe = sh_pfc_pinctrl_probe,
- .remove = __devexit_p(sh_pfc_pinctrl_remove),
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_device sh_pfc_pinctrl_device = {
- .name = DRV_NAME,
- .id = -1,
-};
-
-static int sh_pfc_pinctrl_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&sh_pfc_pinctrl_driver);
- if (likely(!rc)) {
- rc = platform_device_register(&sh_pfc_pinctrl_device);
- if (unlikely(rc))
- platform_driver_unregister(&sh_pfc_pinctrl_driver);
- }
-
- return rc;
-}
-
-int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
-{
- sh_pfc_pmx = kzalloc(sizeof(struct sh_pfc_pinctrl), GFP_KERNEL);
- if (unlikely(!sh_pfc_pmx))
- return -ENOMEM;
-
- spin_lock_init(&sh_pfc_pmx->lock);
-
- sh_pfc_pmx->pfc = pfc;
-
- return sh_pfc_pinctrl_init();
-}
-
-static void __exit sh_pfc_pinctrl_exit(void)
-{
- platform_driver_unregister(&sh_pfc_pinctrl_driver);
-}
-module_exit(sh_pfc_pinctrl_exit);