lkml.org 
[lkml]   [2012]   [Feb]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 2/7] mfd: split off mc13xxx SPI specifica from core
    mc13xxx-core.c includes handling SPI directly.
    To be able to alternatively use mc13xxx with I2C,
    split off SPI specific functionality into separate
    file mc13xxx-spi.c, leaving mc13xxx-core.c independent
    of the chosen wiring.

    Signed-off-by: Oskar Schirmer <oskar@scara.com>
    ---
    drivers/mfd/Kconfig | 12 ++-
    drivers/mfd/Makefile | 1 +
    drivers/mfd/mc13xxx-core.c | 165 ++++++-----------------------------------
    drivers/mfd/mc13xxx-spi.c | 172 +++++++++++++++++++++++++++++++++++++++++++
    include/linux/mfd/mc13xxx.h | 13 +++-
    5 files changed, 218 insertions(+), 145 deletions(-)
    create mode 100644 drivers/mfd/mc13xxx-spi.c

    diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
    index f147395..750b50c 100644
    --- a/drivers/mfd/Kconfig
    +++ b/drivers/mfd/Kconfig
    @@ -572,14 +572,18 @@ config MFD_MC13783
    tristate

    config MFD_MC13XXX
    - tristate "Support Freescale MC13783 and MC13892"
    - depends on SPI_MASTER
    + tristate
    select MFD_CORE
    select MFD_MC13783
    +
    +config MFD_MC13XXX_SPI
    + tristate "Support Freescale MC13783 and MC13892 with SPI"
    + select MFD_MC13XXX
    + depends on SPI_MASTER
    help
    Support for the Freescale (Atlas) PMIC and audio CODECs
    - MC13783 and MC13892.
    - This driver provides common support for accessing the device,
    + MC13783 and MC13892, wired for SPI use.
    + This driver provides common support for accessing the device,
    additional drivers must be enabled in order to use the
    functionality of the device.

    diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
    index b953bab..2dc66ed 100644
    --- a/drivers/mfd/Makefile
    +++ b/drivers/mfd/Makefile
    @@ -53,6 +53,7 @@ obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
    obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o

    obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
    +obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o

    obj-$(CONFIG_MFD_CORE) += mfd-core.o

    diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
    index 94840c1..1102b77 100644
    --- a/drivers/mfd/mc13xxx-core.c
    +++ b/drivers/mfd/mc13xxx-core.c
    @@ -15,7 +15,6 @@
    #include <linux/platform_device.h>
    #include <linux/mutex.h>
    #include <linux/interrupt.h>
    -#include <linux/spi/spi.h>
    #include <linux/mfd/core.h>
    #include <linux/mfd/mc13xxx.h>
    #include <linux/of.h>
    @@ -132,29 +131,26 @@
    void mc13xxx_lock(struct mc13xxx *mc13xxx)
    {
    if (!mutex_trylock(&mc13xxx->lock)) {
    - dev_dbg(&mc13xxx->spidev->dev, "wait for %s from %pf\n",
    + dev_dbg(mc13xxx->dev, "wait for %s from %pf\n",
    __func__, __builtin_return_address(0));

    mutex_lock(&mc13xxx->lock);
    }
    - dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n",
    + dev_dbg(mc13xxx->dev, "%s from %pf\n",
    __func__, __builtin_return_address(0));
    }
    EXPORT_SYMBOL(mc13xxx_lock);

    void mc13xxx_unlock(struct mc13xxx *mc13xxx)
    {
    - dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n",
    + dev_dbg(mc13xxx->dev, "%s from %pf\n",
    __func__, __builtin_return_address(0));
    mutex_unlock(&mc13xxx->lock);
    }
    EXPORT_SYMBOL(mc13xxx_unlock);

    -#define MC13XXX_REGOFFSET_SHIFT 25
    int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
    {
    - struct spi_transfer t;
    - struct spi_message m;
    int ret;

    BUG_ON(!mutex_is_locked(&mc13xxx->lock));
    @@ -162,66 +158,24 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
    if (offset > MC13XXX_NUMREGS)
    return -EINVAL;

    - *val = offset << MC13XXX_REGOFFSET_SHIFT;
    + ret = mc13xxx->read(mc13xxx, offset, val);

    - memset(&t, 0, sizeof(t));
    -
    - t.tx_buf = val;
    - t.rx_buf = val;
    - t.len = sizeof(u32);
    -
    - spi_message_init(&m);
    - spi_message_add_tail(&t, &m);
    -
    - ret = spi_sync(mc13xxx->spidev, &m);
    -
    - /* error in message.status implies error return from spi_sync */
    - BUG_ON(!ret && m.status);
    -
    - if (ret)
    - return ret;
    -
    - *val &= 0xffffff;
    -
    - dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
    -
    - return 0;
    + return ret;
    }
    EXPORT_SYMBOL(mc13xxx_reg_read);

    int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
    {
    - u32 buf;
    - struct spi_transfer t;
    - struct spi_message m;
    int ret;

    BUG_ON(!mutex_is_locked(&mc13xxx->lock));

    - dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val);
    -
    if (offset > MC13XXX_NUMREGS || val > 0xffffff)
    return -EINVAL;

    - buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val;
    -
    - memset(&t, 0, sizeof(t));
    -
    - t.tx_buf = &buf;
    - t.rx_buf = &buf;
    - t.len = sizeof(u32);
    -
    - spi_message_init(&m);
    - spi_message_add_tail(&t, &m);
    -
    - ret = spi_sync(mc13xxx->spidev, &m);
    -
    - BUG_ON(!ret && m.status);
    + ret = mc13xxx->write(mc13xxx, offset, val);

    - if (ret)
    - return ret;
    -
    - return 0;
    + return ret;
    }
    EXPORT_SYMBOL(mc13xxx_reg_write);

    @@ -427,7 +381,7 @@ static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx,
    if (handled == IRQ_HANDLED)
    num_handled++;
    } else {
    - dev_err(&mc13xxx->spidev->dev,
    + dev_err(mc13xxx->dev,
    "BUG: irq %u but no handler\n",
    baseirq + irq);

    @@ -501,7 +455,7 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
    if (ret)
    return ret;

    - dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, "
    + dev_info(mc13xxx->dev, "%s: rev: %d.%d, "
    "fin: %d, fab: %d, icid: %d/%d\n",
    mc13xxx_chipname[*id],
    maskval(revision, MC13XXX_REVISION_REVFULL),
    @@ -513,10 +467,8 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
    }

    if (*id != MC13XXX_ID_INVALID) {
    - const struct spi_device_id *devid =
    - spi_get_device_id(mc13xxx->spidev);
    - if (!devid || devid->driver_data != *id)
    - dev_warn(&mc13xxx->spidev->dev, "device id doesn't "
    + if (!mc13xxx->driver_data || *mc13xxx->driver_data != *id)
    + dev_warn(mc13xxx->dev, "device id doesn't "
    "match auto detection!\n");
    }

    @@ -525,13 +477,10 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)

    static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
    {
    - const struct spi_device_id *devid =
    - spi_get_device_id(mc13xxx->spidev);
    -
    - if (!devid)
    + if (!mc13xxx->driver_data)
    return NULL;

    - return mc13xxx_chipname[devid->driver_data];
    + return mc13xxx_chipname[*mc13xxx->driver_data];
    }

    int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
    @@ -571,7 +520,7 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
    };
    init_completion(&adcdone_data.done);

    - dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__);
    + dev_dbg(mc13xxx->dev, "%s\n", __func__);

    mc13xxx_lock(mc13xxx);

    @@ -613,7 +562,7 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
    return -EINVAL;
    }

    - dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
    + dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__);
    mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
    mc13xxx_handler_adcdone, __func__, &adcdone_data);
    mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_ADCDONE);
    @@ -671,7 +620,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
    if (!cell.name)
    return -ENOMEM;

    - return mfd_add_devices(&mc13xxx->spidev->dev, -1, &cell, 1, NULL, 0);
    + return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0);
    }

    static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
    @@ -682,7 +631,7 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
    #ifdef CONFIG_OF
    static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
    {
    - struct device_node *np = mc13xxx->spidev->dev.of_node;
    + struct device_node *np = mc13xxx->dev.of_node;

    if (!np)
    return -ENODEV;
    @@ -708,49 +657,13 @@ static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
    }
    #endif

    -static const struct spi_device_id mc13xxx_device_id[] = {
    - {
    - .name = "mc13783",
    - .driver_data = MC13XXX_ID_MC13783,
    - }, {
    - .name = "mc13892",
    - .driver_data = MC13XXX_ID_MC13892,
    - }, {
    - /* sentinel */
    - }
    -};
    -MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
    -
    -static const struct of_device_id mc13xxx_dt_ids[] = {
    - { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
    - { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
    - { /* sentinel */ }
    -};
    -MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
    -
    -static int mc13xxx_probe(struct spi_device *spi)
    +int mc13xxx_device_init(struct mc13xxx *mc13xxx)
    {
    - const struct of_device_id *of_id;
    - struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
    - struct mc13xxx *mc13xxx;
    - struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
    + struct mc13xxx_platform_data *pdata = dev_get_platdata(mc13xxx->dev);
    enum mc13xxx_id id;
    int ret;

    - of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
    - if (of_id)
    - sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
    -
    - mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
    - if (!mc13xxx)
    - return -ENOMEM;
    -
    - dev_set_drvdata(&spi->dev, mc13xxx);
    - spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
    - spi->bits_per_word = 32;
    - spi_setup(spi);
    -
    - mc13xxx->spidev = spi;
    + dev_set_drvdata(mc13xxx->dev, mc13xxx);

    mutex_init(&mc13xxx->lock);
    mc13xxx_lock(mc13xxx);
    @@ -768,14 +681,14 @@ static int mc13xxx_probe(struct spi_device *spi)
    if (ret)
    goto err_mask;

    - ret = request_threaded_irq(spi->irq, NULL, mc13xxx_irq_thread,
    + ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread,
    IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);

    if (ret) {
    err_mask:
    err_revision:
    mc13xxx_unlock(mc13xxx);
    - dev_set_drvdata(&spi->dev, NULL);
    + dev_set_drvdata(mc13xxx->dev, NULL);
    kfree(mc13xxx);
    return ret;
    }
    @@ -813,41 +726,13 @@ err_revision:
    return 0;
    }

    -static int __devexit mc13xxx_remove(struct spi_device *spi)
    +void mc13xxx_device_exit(struct mc13xxx *mc13xxx)
    {
    - struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev);
    -
    - free_irq(mc13xxx->spidev->irq, mc13xxx);
    -
    - mfd_remove_devices(&spi->dev);
    + free_irq(mc13xxx->irq, mc13xxx);

    + mfd_remove_devices(mc13xxx->dev);
    kfree(mc13xxx);
    -
    - return 0;
    -}
    -
    -static struct spi_driver mc13xxx_driver = {
    - .id_table = mc13xxx_device_id,
    - .driver = {
    - .name = "mc13xxx",
    - .owner = THIS_MODULE,
    - .of_match_table = mc13xxx_dt_ids,
    - },
    - .probe = mc13xxx_probe,
    - .remove = __devexit_p(mc13xxx_remove),
    -};
    -
    -static int __init mc13xxx_init(void)
    -{
    - return spi_register_driver(&mc13xxx_driver);
    -}
    -subsys_initcall(mc13xxx_init);
    -
    -static void __exit mc13xxx_exit(void)
    -{
    - spi_unregister_driver(&mc13xxx_driver);
    }
    -module_exit(mc13xxx_exit);

    MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC");
    MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
    diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c
    new file mode 100644
    index 0000000..37277c1
    --- /dev/null
    +++ b/drivers/mfd/mc13xxx-spi.c
    @@ -0,0 +1,172 @@
    +/*
    + * Copyright 2009-2010 Pengutronix
    + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
    + *
    + * loosely based on an earlier driver that has
    + * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
    + *
    + * This program is free software; you can redistribute it and/or modify it under
    + * the terms of the GNU General Public License version 2 as published by the
    + * Free Software Foundation.
    + */
    +
    +#include <linux/slab.h>
    +#include <linux/module.h>
    +#include <linux/platform_device.h>
    +#include <linux/mutex.h>
    +#include <linux/interrupt.h>
    +#include <linux/spi/spi.h>
    +#include <linux/mfd/core.h>
    +#include <linux/mfd/mc13xxx.h>
    +#include <linux/of.h>
    +#include <linux/of_device.h>
    +
    +#define MC13XXX_REGOFFSET_SHIFT 25
    +static int mc13xxx_spi_read(struct mc13xxx *mc13xxx,
    + unsigned int offset, u32 *val)
    +{
    + struct spi_transfer t;
    + struct spi_message m;
    + int ret;
    +
    + *val = offset << MC13XXX_REGOFFSET_SHIFT;
    +
    + memset(&t, 0, sizeof(t));
    +
    + t.tx_buf = val;
    + t.rx_buf = val;
    + t.len = sizeof(u32);
    +
    + spi_message_init(&m);
    + spi_message_add_tail(&t, &m);
    +
    + ret = spi_sync(mc13xxx->control.spidev, &m);
    +
    + /* error in message.status implies error return from spi_sync */
    + BUG_ON(!ret && m.status);
    +
    + if (ret)
    + return ret;
    +
    + *val &= 0xffffff;
    +
    + dev_vdbg(mc13xxx->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
    +
    + return 0;
    +}
    +
    +static int mc13xxx_spi_write(struct mc13xxx *mc13xxx,
    + unsigned int offset, u32 val)
    +{
    + u32 buf;
    + struct spi_transfer t;
    + struct spi_message m;
    + int ret;
    +
    + dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val);
    +
    + buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val;
    +
    + memset(&t, 0, sizeof(t));
    +
    + t.tx_buf = &buf;
    + t.rx_buf = &buf;
    + t.len = sizeof(u32);
    +
    + spi_message_init(&m);
    + spi_message_add_tail(&t, &m);
    +
    + ret = spi_sync(mc13xxx->control.spidev, &m);
    +
    + BUG_ON(!ret && m.status);
    +
    + return ret;
    +}
    +
    +static const struct spi_device_id mc13xxx_spi_device_id[] = {
    + {
    + .name = "mc13783",
    + .driver_data = MC13XXX_ID_MC13783,
    + }, {
    + .name = "mc13892",
    + .driver_data = MC13XXX_ID_MC13892,
    + }, {
    + /* sentinel */
    + }
    +};
    +MODULE_DEVICE_TABLE(spi, mc13xxx_spi_device_id);
    +
    +static const struct of_device_id mc13xxx_dt_ids[] = {
    + { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
    + { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
    + { /* sentinel */ }
    +};
    +MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
    +
    +static int mc13xxx_spi_probe(struct spi_device *spi)
    +{
    + const struct of_device_id *of_id;
    + struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
    + struct mc13xxx *mc13xxx;
    + const struct spi_device_id *devid;
    +
    + of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
    + if (of_id)
    + sdrv->id_table =
    + &mc13xxx_spi_device_id[(enum mc13xxx_id) of_id->data];
    +
    + mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
    + if (!mc13xxx)
    + return -ENOMEM;
    +
    + mc13xxx->dev = &spi->dev;
    + mc13xxx->control.spidev = spi;
    + mc13xxx->read = mc13xxx_spi_read;
    + mc13xxx->write = mc13xxx_spi_write;
    + mc13xxx->irq = spi->irq;
    +
    + spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
    + spi->bits_per_word = 32;
    + spi_setup(spi);
    +
    + devid = spi_get_device_id(spi);
    + mc13xxx->driver_data = devid ? &devid->driver_data : NULL;
    +
    + return mc13xxx_device_init(mc13xxx);
    +}
    +
    +static int __devexit mc13xxx_spi_remove(struct spi_device *spi)
    +{
    + struct mc13xxx *mc13xxx = spi_get_drvdata(spi);
    +
    + mc13xxx_device_exit(mc13xxx);
    +
    + return 0;
    +}
    +
    +static struct spi_driver mc13xxx_spi_driver = {
    + .id_table = mc13xxx_spi_device_id,
    + .driver = {
    + .name = "mc13xxx",
    + .owner = THIS_MODULE,
    + .of_match_table = mc13xxx_dt_ids,
    + },
    + .probe = mc13xxx_spi_probe,
    + .remove = __devexit_p(mc13xxx_spi_remove),
    +};
    +
    +static int __init mc13xxx_spi_init(void)
    +{
    + return spi_register_driver(&mc13xxx_spi_driver);
    +}
    +subsys_initcall(mc13xxx_spi_init);
    +
    +static void __exit mc13xxx_spi_exit(void)
    +{
    + spi_unregister_driver(&mc13xxx_spi_driver);
    +}
    +module_exit(mc13xxx_spi_exit);
    +
    +MODULE_DESCRIPTION("SPI support for Freescale MC13XXX PMIC");
    +MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
    +MODULE_LICENSE("GPL v2");
    diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h
    index df6654a..9929a8e 100644
    --- a/include/linux/mfd/mc13xxx.h
    +++ b/include/linux/mfd/mc13xxx.h
    @@ -10,6 +10,7 @@
    #define __LINUX_MFD_MC13XXX_H

    #include <linux/interrupt.h>
    +#include <linux/spi/spi.h>

    #define MC13XXX_IRQ_ADCDONE 0
    #define MC13XXX_IRQ_ADCBISDONE 1
    @@ -42,15 +43,22 @@ enum mc13xxx_id {
    };

    struct mc13xxx {
    - struct spi_device *spidev;
    + struct device *dev;
    + union {
    + struct spi_device *spidev;
    + } control;
    struct mutex lock;
    int irq;
    int flags;

    + int (*read)(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val);
    + int (*write)(struct mc13xxx *mc13xxx, unsigned int offset, u32 val);
    +
    irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
    void *irqdata[MC13XXX_NUM_IRQ];

    int adcflags;
    + const kernel_ulong_t *driver_data;
    };

    void mc13xxx_lock(struct mc13xxx *mc13xxx);
    @@ -80,6 +88,9 @@ int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
    int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,
    unsigned int mode, unsigned int channel, unsigned int *sample);

    +int mc13xxx_device_init(struct mc13xxx *mc13xxx);
    +void mc13xxx_device_exit(struct mc13xxx *mc13xxx);
    +
    struct regulator_init_data;

    struct mc13xxx_regulator_init_data {
    --
    1.7.5.4


    \
     
     \ /
      Last update: 2012-02-14 12:07    [W:2.802 / U:0.132 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site