linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* mc13xxx: add I2C support (now with regmap), V3
@ 2012-03-14 20:43 Marc Reilly
  2012-03-14 20:43 ` [PATCH v3 1/6] regmap: add support for 7_25 format Marc Reilly
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Marc Reilly @ 2012-03-14 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This series (against mfd-2.6/for-next) changes the mc13xxx driver to use 
regmap and adds I2C support. It generally goes about this the same way as 
the previous 2 versions, but now uses regmap.

I am unable to test SPI functionality, but the I2C stuff works. It would be
great if someone could test the SPI side again.

The first 2 patches add required support to regmap for the mc13xxx register
format(s), I've included them here for convenience.
@Mark B: I also have some versions of these that apply against regmap/for-next.

Cheers,
Marc

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/6] regmap: add support for 7_25 format
  2012-03-14 20:43 mc13xxx: add I2C support (now with regmap), V3 Marc Reilly
@ 2012-03-14 20:43 ` Marc Reilly
  2012-03-15 10:44   ` Mark Brown
  2012-03-14 20:43 ` [PATCH v3 2/6] regmap: Add support for device with 24 data bits Marc Reilly
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Marc Reilly @ 2012-03-14 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

This adds support for devices with 7 address bits and 25 data bits.
The initial intended user for this are the mc13xxx mfds in spi mode.
(The 25th data bit is actually a dummy bit)

Signed-off-by: Marc Reilly <marc@cpdesign.com.au>
---
 drivers/base/regmap/regmap.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index be10a4f..62ef0df 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -100,6 +100,14 @@ static void regmap_format_10_14_write(struct regmap *map,
 	out[0] = reg >> 2;
 }
 
+static void regmap_format_7_25_write(struct regmap *map,
+				    unsigned int reg, unsigned int val)
+{
+	__be32 *out = map->work_buf;
+
+	*out = (reg << 25) | val;
+}
+
 static void regmap_format_8(void *buf, unsigned int val)
 {
 	u8 *b = buf;
@@ -193,6 +201,9 @@ struct regmap *regmap_init(struct device *dev,
 		case 9:
 			map->format.format_write = regmap_format_7_9_write;
 			break;
+		case 25:
+			map->format.format_write = regmap_format_7_25_write;
+			break;
 		default:
 			goto err_map;
 		}
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/6] regmap: Add support for device with 24 data bits.
  2012-03-14 20:43 mc13xxx: add I2C support (now with regmap), V3 Marc Reilly
  2012-03-14 20:43 ` [PATCH v3 1/6] regmap: add support for 7_25 format Marc Reilly
@ 2012-03-14 20:43 ` Marc Reilly
  2012-03-15 10:46   ` Mark Brown
  2012-03-14 20:43 ` [PATCH v3 3/6] mfd: mc13xxx-core: Prepare for separate spi and i2c backends Marc Reilly
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Marc Reilly @ 2012-03-14 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for devices with 24 data bits.

Signed-off-by: Marc Reilly <marc@cpdesign.com.au>
---
 drivers/base/regmap/regmap.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 62ef0df..880e3a0 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -122,6 +122,15 @@ static void regmap_format_16(void *buf, unsigned int val)
 	b[0] = cpu_to_be16(val);
 }
 
+static void regmap_format_24(void *buf, unsigned int val)
+{
+	u8 *b = buf;
+
+	b[0] = val >> 16;
+	b[1] = val >> 8;
+	b[2] = val;
+}
+
 static unsigned int regmap_parse_8(void *buf)
 {
 	u8 *b = buf;
@@ -138,6 +147,16 @@ static unsigned int regmap_parse_16(void *buf)
 	return b[0];
 }
 
+static unsigned int regmap_parse_24(void *buf)
+{
+	u8 *b = buf;
+	unsigned int ret = b[2];
+	ret |= ((unsigned int)b[1]) << 8;
+	ret |= ((unsigned int)b[0]) << 16;
+
+	return ret;
+}
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -240,6 +259,10 @@ struct regmap *regmap_init(struct device *dev,
 		map->format.format_val = regmap_format_16;
 		map->format.parse_val = regmap_parse_16;
 		break;
+	case 24:
+		map->format.format_val = regmap_format_24;
+		map->format.parse_val = regmap_parse_24;
+		break;
 	}
 
 	if (!map->format.format_write &&
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/6] mfd: mc13xxx-core: Prepare for separate spi and i2c backends.
  2012-03-14 20:43 mc13xxx: add I2C support (now with regmap), V3 Marc Reilly
  2012-03-14 20:43 ` [PATCH v3 1/6] regmap: add support for 7_25 format Marc Reilly
  2012-03-14 20:43 ` [PATCH v3 2/6] regmap: Add support for device with 24 data bits Marc Reilly
@ 2012-03-14 20:43 ` Marc Reilly
  2012-03-14 20:43 ` [PATCH v3 4/6] mfd: mc13xxx-core: use regmap for register access Marc Reilly
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Marc Reilly @ 2012-03-14 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

This patch abstracts the bus specific operations from the driver core.
Generic init and cleanup is consolidated into mc13xxx_common_*.
spi specific functions are renamed to reflect such.
(The irq member of the mc13xxx struct is no longer redundant, it's used
to store the irq for cleanup time).

Signed-off-by: Marc Reilly <marc@cpdesign.com.au>
---
 drivers/mfd/mc13xxx-core.c |  187 ++++++++++++++++++++++++++------------------
 1 files changed, 112 insertions(+), 75 deletions(-)

diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 7122386..0753402 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -22,8 +22,18 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 
+enum mc13xxx_id {
+	MC13XXX_ID_MC13783,
+	MC13XXX_ID_MC13892,
+	MC13XXX_ID_INVALID,
+};
+
 struct mc13xxx {
 	struct spi_device *spidev;
+
+	struct device *dev;
+	enum mc13xxx_id ictype;
+
 	struct mutex lock;
 	int irq;
 	int flags;
@@ -144,36 +154,32 @@ struct mc13xxx {
 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)
+static int mc13xxx_spi_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));
-
-	if (offset > MC13XXX_NUMREGS)
-		return -EINVAL;
-
 	*val = offset << MC13XXX_REGOFFSET_SHIFT;
 
 	memset(&t, 0, sizeof(t));
@@ -195,26 +201,17 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
 
 	*val &= 0xffffff;
 
-	dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
-
 	return 0;
 }
-EXPORT_SYMBOL(mc13xxx_reg_read);
 
-int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
+static int mc13xxx_spi_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));
@@ -235,6 +232,34 @@ int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
 
 	return 0;
 }
+
+int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
+{
+	int ret;
+
+	BUG_ON(!mutex_is_locked(&mc13xxx->lock));
+
+	if (offset > MC13XXX_NUMREGS)
+		return -EINVAL;
+
+	ret = mc13xxx_spi_reg_read(mc13xxx, offset, val);
+	dev_vdbg(mc13xxx->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
+
+	return ret;
+}
+EXPORT_SYMBOL(mc13xxx_reg_read);
+
+int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
+{
+	BUG_ON(!mutex_is_locked(&mc13xxx->lock));
+
+	dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val);
+
+	if (offset > MC13XXX_NUMREGS || val > 0xffffff)
+		return -EINVAL;
+
+	return mc13xxx_spi_reg_write(mc13xxx, offset, val);
+}
 EXPORT_SYMBOL(mc13xxx_reg_write);
 
 int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
@@ -439,7 +464,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);
 
@@ -475,25 +500,23 @@ static irqreturn_t mc13xxx_irq_thread(int irq, void *data)
 	return IRQ_RETVAL(handled);
 }
 
-enum mc13xxx_id {
-	MC13XXX_ID_MC13783,
-	MC13XXX_ID_MC13892,
-	MC13XXX_ID_INVALID,
-};
-
 static const char *mc13xxx_chipname[] = {
 	[MC13XXX_ID_MC13783] = "mc13783",
 	[MC13XXX_ID_MC13892] = "mc13892",
 };
 
 #define maskval(reg, mask)	(((reg) & (mask)) >> __ffs(mask))
-static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
+static int mc13xxx_identify(struct mc13xxx *mc13xxx)
 {
 	u32 icid;
 	u32 revision;
-	const char *name;
 	int ret;
 
+	/*
+	 * Get the generation ID from register 46, as apparently some older
+	 * IC revisions only have this info at this location. Newer ICs seem to
+	 * have both.
+	 */
 	ret = mc13xxx_reg_read(mc13xxx, 46, &icid);
 	if (ret)
 		return ret;
@@ -502,26 +525,23 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
 
 	switch (icid) {
 	case 2:
-		*id = MC13XXX_ID_MC13783;
-		name = "mc13783";
+		mc13xxx->ictype = MC13XXX_ID_MC13783;
 		break;
 	case 7:
-		*id = MC13XXX_ID_MC13892;
-		name = "mc13892";
+		mc13xxx->ictype = MC13XXX_ID_MC13892;
 		break;
 	default:
-		*id = MC13XXX_ID_INVALID;
+		mc13xxx->ictype = MC13XXX_ID_INVALID;
 		break;
 	}
 
-	if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) {
+	if (mc13xxx->ictype == MC13XXX_ID_MC13783 ||
+			mc13xxx->ictype == MC13XXX_ID_MC13892) {
 		ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
-		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],
+				mc13xxx_chipname[mc13xxx->ictype],
 				maskval(revision, MC13XXX_REVISION_REVFULL),
 				maskval(revision, MC13XXX_REVISION_REVMETAL),
 				maskval(revision, MC13XXX_REVISION_FIN),
@@ -530,26 +550,12 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
 				maskval(revision, MC13XXX_REVISION_ICIDCODE));
 	}
 
-	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 "
-					"match auto detection!\n");
-	}
-
-	return 0;
+	return (mc13xxx->ictype == MC13XXX_ID_INVALID) ? -ENODEV : 0;
 }
 
 static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
 {
-	const struct spi_device_id *devid =
-		spi_get_device_id(mc13xxx->spidev);
-
-	if (!devid)
-		return NULL;
-
-	return mc13xxx_chipname[devid->driver_data];
+	return mc13xxx_chipname[mc13xxx->ictype];
 }
 
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
@@ -589,7 +595,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);
 
@@ -631,7 +637,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);
@@ -689,7 +695,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)
@@ -700,7 +706,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;
@@ -746,13 +752,17 @@ static const struct of_device_id mc13xxx_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
 
-static int mc13xxx_probe(struct spi_device *spi)
+static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
+		struct mc13xxx_platform_data *pdata, int irq);
+
+static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx);
+
+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;
 	struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
-	enum mc13xxx_id id;
 	int ret;
 
 	of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
@@ -768,13 +778,34 @@ static int mc13xxx_probe(struct spi_device *spi)
 	spi->bits_per_word = 32;
 	spi_setup(spi);
 
+	mc13xxx->dev = &spi->dev;
 	mc13xxx->spidev = spi;
 
+	ret = mc13xxx_common_init(mc13xxx, pdata, spi->irq);
+
+	if (ret) {
+		dev_set_drvdata(&spi->dev, NULL);
+	} else {
+		const struct spi_device_id *devid =
+			spi_get_device_id(mc13xxx->spidev);
+		if (!devid || devid->driver_data != mc13xxx->ictype)
+			dev_warn(mc13xxx->dev,
+				"device id doesn't match auto detection!\n");
+	}
+
+	return ret;
+}
+
+static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
+		struct mc13xxx_platform_data *pdata, int irq)
+{
+	int ret;
+
 	mutex_init(&mc13xxx->lock);
 	mc13xxx_lock(mc13xxx);
 
-	ret = mc13xxx_identify(mc13xxx, &id);
-	if (ret || id == MC13XXX_ID_INVALID)
+	ret = mc13xxx_identify(mc13xxx);
+	if (ret)
 		goto err_revision;
 
 	/* mask all irqs */
@@ -786,18 +817,19 @@ 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(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);
 		kfree(mc13xxx);
 		return ret;
 	}
 
+	mc13xxx->irq = irq;
+
 	mc13xxx_unlock(mc13xxx);
 
 	if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
@@ -831,39 +863,44 @@ err_revision:
 	return 0;
 }
 
-static int __devexit mc13xxx_remove(struct spi_device *spi)
+static int __devexit mc13xxx_spi_remove(struct spi_device *spi)
 {
 	struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev);
 
-	free_irq(mc13xxx->spidev->irq, mc13xxx);
+	mc13xxx_common_cleanup(mc13xxx);
 
-	mfd_remove_devices(&spi->dev);
+	return 0;
+}
 
-	kfree(mc13xxx);
+static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx)
+{
+	free_irq(mc13xxx->irq, mc13xxx);
 
-	return 0;
+	mfd_remove_devices(mc13xxx->dev);
+
+	kfree(mc13xxx);
 }
 
-static struct spi_driver mc13xxx_driver = {
+static struct spi_driver mc13xxx_spi_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),
+	.probe = mc13xxx_spi_probe,
+	.remove = __devexit_p(mc13xxx_spi_remove),
 };
 
 static int __init mc13xxx_init(void)
 {
-	return spi_register_driver(&mc13xxx_driver);
+	return spi_register_driver(&mc13xxx_spi_driver);
 }
 subsys_initcall(mc13xxx_init);
 
 static void __exit mc13xxx_exit(void)
 {
-	spi_unregister_driver(&mc13xxx_driver);
+	spi_unregister_driver(&mc13xxx_spi_driver);
 }
 module_exit(mc13xxx_exit);
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/6] mfd: mc13xxx-core: use regmap for register access
  2012-03-14 20:43 mc13xxx: add I2C support (now with regmap), V3 Marc Reilly
                   ` (2 preceding siblings ...)
  2012-03-14 20:43 ` [PATCH v3 3/6] mfd: mc13xxx-core: Prepare for separate spi and i2c backends Marc Reilly
@ 2012-03-14 20:43 ` Marc Reilly
  2012-03-15 17:43   ` Mark Brown
  2012-03-14 20:43 ` [PATCH v3 5/6] mfd: mc13xxx-core: Move spi specific code into separate module Marc Reilly
  2012-03-14 20:43 ` [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver Marc Reilly
  5 siblings, 1 reply; 12+ messages in thread
From: Marc Reilly @ 2012-03-14 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

This change converts the mc13xxx core to use regmap rather than direct
spi r/w.
The spidev member of mc13xxx struct becomes redundant and is removed.
Extra debugging aids are added to mc13xxx_reg_rmw.
Mutex init is moved to before regmap init.

Signed-off-by: Marc Reilly <marc@cpdesign.com.au>
---
 drivers/mfd/mc13xxx-core.c |  109 ++++++++++++-------------------------------
 1 files changed, 31 insertions(+), 78 deletions(-)

diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 0753402..9804572 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -21,6 +21,8 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
 
 enum mc13xxx_id {
 	MC13XXX_ID_MC13783,
@@ -29,7 +31,7 @@ enum mc13xxx_id {
 };
 
 struct mc13xxx {
-	struct spi_device *spidev;
+	struct regmap *regmap;
 
 	struct device *dev;
 	enum mc13xxx_id ictype;
@@ -172,67 +174,6 @@ void mc13xxx_unlock(struct mc13xxx *mc13xxx)
 }
 EXPORT_SYMBOL(mc13xxx_unlock);
 
-#define MC13XXX_REGOFFSET_SHIFT 25
-static int mc13xxx_spi_reg_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->spidev, &m);
-
-	/* error in message.status implies error return from spi_sync */
-	BUG_ON(!ret && m.status);
-
-	if (ret)
-		return ret;
-
-	*val &= 0xffffff;
-
-	return 0;
-}
-
-static int mc13xxx_spi_reg_write(struct mc13xxx *mc13xxx, unsigned int offset,
-		u32 val)
-{
-	u32 buf;
-	struct spi_transfer t;
-	struct spi_message m;
-	int ret;
-
-	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);
-
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
 int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
 {
 	int ret;
@@ -242,7 +183,7 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
 	if (offset > MC13XXX_NUMREGS)
 		return -EINVAL;
 
-	ret = mc13xxx_spi_reg_read(mc13xxx, offset, val);
+	ret = regmap_read(mc13xxx->regmap, offset, val);
 	dev_vdbg(mc13xxx->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
 
 	return ret;
@@ -258,25 +199,19 @@ int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
 	if (offset > MC13XXX_NUMREGS || val > 0xffffff)
 		return -EINVAL;
 
-	return mc13xxx_spi_reg_write(mc13xxx, offset, val);
+	return regmap_write(mc13xxx->regmap, offset, val);
 }
 EXPORT_SYMBOL(mc13xxx_reg_write);
 
 int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
 		u32 mask, u32 val)
 {
-	int ret;
-	u32 valread;
-
+	BUG_ON(!mutex_is_locked(&mc13xxx->lock));
 	BUG_ON(val & ~mask);
+	dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n",
+			offset, val, mask);
 
-	ret = mc13xxx_reg_read(mc13xxx, offset, &valread);
-	if (ret)
-		return ret;
-
-	valread = (valread & ~mask) | val;
-
-	return mc13xxx_reg_write(mc13xxx, offset, valread);
+	return regmap_update_bits(mc13xxx->regmap, offset, mask, val);
 }
 EXPORT_SYMBOL(mc13xxx_reg_rmw);
 
@@ -752,6 +687,15 @@ static const struct of_device_id mc13xxx_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
 
+static struct regmap_config mc13xxx_regmap_spi_config = {
+	.reg_bits = 7,
+	.val_bits = 25,
+
+	.max_register = MC13XXX_NUMREGS,
+
+	.cache_type = REGCACHE_NONE,
+};
+
 static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
 		struct mc13xxx_platform_data *pdata, int irq);
 
@@ -776,10 +720,18 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
 	dev_set_drvdata(&spi->dev, mc13xxx);
 	spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
 	spi->bits_per_word = 32;
-	spi_setup(spi);
 
 	mc13xxx->dev = &spi->dev;
-	mc13xxx->spidev = spi;
+	mutex_init(&mc13xxx->lock);
+
+	mc13xxx->regmap = regmap_init_spi(spi, &mc13xxx_regmap_spi_config);
+	if (IS_ERR(mc13xxx->regmap)) {
+		ret = PTR_ERR(mc13xxx->regmap);
+		dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
+				ret);
+		dev_set_drvdata(&spi->dev, NULL);
+		return ret;
+	}
 
 	ret = mc13xxx_common_init(mc13xxx, pdata, spi->irq);
 
@@ -787,7 +739,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
 		dev_set_drvdata(&spi->dev, NULL);
 	} else {
 		const struct spi_device_id *devid =
-			spi_get_device_id(mc13xxx->spidev);
+			spi_get_device_id(spi);
 		if (!devid || devid->driver_data != mc13xxx->ictype)
 			dev_warn(mc13xxx->dev,
 				"device id doesn't match auto detection!\n");
@@ -801,7 +753,6 @@ static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
 {
 	int ret;
 
-	mutex_init(&mc13xxx->lock);
 	mc13xxx_lock(mc13xxx);
 
 	ret = mc13xxx_identify(mc13xxx);
@@ -878,6 +829,8 @@ static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx)
 
 	mfd_remove_devices(mc13xxx->dev);
 
+	regmap_exit(mc13xxx->regmap);
+
 	kfree(mc13xxx);
 }
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 5/6] mfd: mc13xxx-core: Move spi specific code into separate module.
  2012-03-14 20:43 mc13xxx: add I2C support (now with regmap), V3 Marc Reilly
                   ` (3 preceding siblings ...)
  2012-03-14 20:43 ` [PATCH v3 4/6] mfd: mc13xxx-core: use regmap for register access Marc Reilly
@ 2012-03-14 20:43 ` Marc Reilly
  2012-03-14 20:43 ` [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver Marc Reilly
  5 siblings, 0 replies; 12+ messages in thread
From: Marc Reilly @ 2012-03-14 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

All spi specific code is moved into a new module. The mc13xxx struct
moves to a new local include file by necessity.

A new config choice selects the SPI bus type support and by default is
value of SPI_MASTER to remain compatible with existing configs.

Signed-off-by: Marc Reilly <marc@cpdesign.com.au>
---
 drivers/mfd/Kconfig        |   15 ++++-
 drivers/mfd/Makefile       |    1 +
 drivers/mfd/mc13xxx-core.c |  146 ++------------------------------------------
 drivers/mfd/mc13xxx-spi.c  |  138 +++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/mc13xxx.h      |   45 ++++++++++++++
 5 files changed, 201 insertions(+), 144 deletions(-)
 create mode 100644 drivers/mfd/mc13xxx-spi.c
 create mode 100644 drivers/mfd/mc13xxx.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index cd13e9f..501fee5 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -577,12 +577,21 @@ config MFD_MC13XXX
 	select MFD_CORE
 	select MFD_MC13783
 	help
-	  Support for the Freescale (Atlas) PMIC and audio CODECs
-	  MC13783 and MC13892.
-	  This driver provides common support for accessing  the device,
+	  Enable support for the Freescale MC13783 and MC13892 PMICs.
+	  This driver provides common support for accessing the device,
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+if MFD_MC13XXX
+
+config MFD_MC13XXX_SPI
+	tristate "MC13xxx SPI interface" if SPI_MASTER
+	default SPI_MASTER
+	help
+	  Select this if your MC13xxx is connected via an SPI bus.
+
+endif
+
 config ABX500_CORE
 	bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
 	default y if ARCH_U300 || ARCH_U8500
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 9804572..31dbf91 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -15,36 +15,13 @@
 #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>
 #include <linux/of_gpio.h>
-#include <linux/regmap.h>
-#include <linux/err.h>
 
-enum mc13xxx_id {
-	MC13XXX_ID_MC13783,
-	MC13XXX_ID_MC13892,
-	MC13XXX_ID_INVALID,
-};
-
-struct mc13xxx {
-	struct regmap *regmap;
-
-	struct device *dev;
-	enum mc13xxx_id ictype;
-
-	struct mutex lock;
-	int irq;
-	int flags;
-
-	irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
-	void *irqdata[MC13XXX_NUM_IRQ];
-
-	int adcflags;
-};
+#include "mc13xxx.h"
 
 #define MC13XXX_IRQSTAT0	0
 #define MC13XXX_IRQSTAT0_ADCDONEI	(1 << 0)
@@ -151,8 +128,6 @@ struct mc13xxx {
 
 #define MC13XXX_ADC2		45
 
-#define MC13XXX_NUMREGS 0x3f
-
 void mc13xxx_lock(struct mc13xxx *mc13xxx)
 {
 	if (!mutex_trylock(&mc13xxx->lock)) {
@@ -667,88 +642,7 @@ 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 struct regmap_config mc13xxx_regmap_spi_config = {
-	.reg_bits = 7,
-	.val_bits = 25,
-
-	.max_register = MC13XXX_NUMREGS,
-
-	.cache_type = REGCACHE_NONE,
-};
-
-static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
-		struct mc13xxx_platform_data *pdata, int irq);
-
-static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx);
-
-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;
-	struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
-	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;
-
-	mc13xxx->dev = &spi->dev;
-	mutex_init(&mc13xxx->lock);
-
-	mc13xxx->regmap = regmap_init_spi(spi, &mc13xxx_regmap_spi_config);
-	if (IS_ERR(mc13xxx->regmap)) {
-		ret = PTR_ERR(mc13xxx->regmap);
-		dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
-				ret);
-		dev_set_drvdata(&spi->dev, NULL);
-		return ret;
-	}
-
-	ret = mc13xxx_common_init(mc13xxx, pdata, spi->irq);
-
-	if (ret) {
-		dev_set_drvdata(&spi->dev, NULL);
-	} else {
-		const struct spi_device_id *devid =
-			spi_get_device_id(spi);
-		if (!devid || devid->driver_data != mc13xxx->ictype)
-			dev_warn(mc13xxx->dev,
-				"device id doesn't match auto detection!\n");
-	}
-
-	return ret;
-}
-
-static int mc13xxx_common_init(struct mc13xxx *mc13xxx,
+int mc13xxx_common_init(struct mc13xxx *mc13xxx,
 		struct mc13xxx_platform_data *pdata, int irq)
 {
 	int ret;
@@ -813,17 +707,9 @@ err_revision:
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(mc13xxx_common_init);
 
-static int __devexit mc13xxx_spi_remove(struct spi_device *spi)
-{
-	struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev);
-
-	mc13xxx_common_cleanup(mc13xxx);
-
-	return 0;
-}
-
-static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx)
+void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx)
 {
 	free_irq(mc13xxx->irq, mc13xxx);
 
@@ -833,29 +719,7 @@ static void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx)
 
 	kfree(mc13xxx);
 }
-
-static struct spi_driver mc13xxx_spi_driver = {
-	.id_table = mc13xxx_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_init(void)
-{
-	return spi_register_driver(&mc13xxx_spi_driver);
-}
-subsys_initcall(mc13xxx_init);
-
-static void __exit mc13xxx_exit(void)
-{
-	spi_unregister_driver(&mc13xxx_spi_driver);
-}
-module_exit(mc13xxx_exit);
+EXPORT_SYMBOL_GPL(mc13xxx_common_cleanup);
 
 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..3e71df4
--- /dev/null
+++ b/drivers/mfd/mc13xxx-spi.c
@@ -0,0 +1,138 @@
+/*
+ * 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/mfd/core.h>
+#include <linux/mfd/mc13xxx.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+
+#include "mc13xxx.h"
+
+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 struct regmap_config mc13xxx_regmap_spi_config = {
+	.reg_bits = 7,
+	.val_bits = 25,
+
+	.max_register = MC13XXX_NUMREGS,
+
+	.cache_type = REGCACHE_NONE,
+};
+
+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;
+	struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
+	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;
+
+	mc13xxx->dev = &spi->dev;
+	mutex_init(&mc13xxx->lock);
+
+	mc13xxx->regmap = regmap_init_spi(spi, &mc13xxx_regmap_spi_config);
+	if (IS_ERR(mc13xxx->regmap)) {
+		ret = PTR_ERR(mc13xxx->regmap);
+		dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
+				ret);
+		dev_set_drvdata(&spi->dev, NULL);
+		return ret;
+	}
+
+	ret = mc13xxx_common_init(mc13xxx, pdata, spi->irq);
+
+	if (ret) {
+		dev_set_drvdata(&spi->dev, NULL);
+	} else {
+		const struct spi_device_id *devid =
+			spi_get_device_id(spi);
+		if (!devid || devid->driver_data != mc13xxx->ictype)
+			dev_warn(mc13xxx->dev,
+				"device id doesn't match auto detection!\n");
+	}
+
+	return ret;
+}
+
+static int __devexit mc13xxx_spi_remove(struct spi_device *spi)
+{
+	struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev);
+
+	mc13xxx_common_cleanup(mc13xxx);
+
+	return 0;
+}
+
+static struct spi_driver mc13xxx_spi_driver = {
+	.id_table = mc13xxx_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_init(void)
+{
+	return spi_register_driver(&mc13xxx_spi_driver);
+}
+subsys_initcall(mc13xxx_init);
+
+static void __exit mc13xxx_exit(void)
+{
+	spi_unregister_driver(&mc13xxx_spi_driver);
+}
+module_exit(mc13xxx_exit);
+
+MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC");
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/mc13xxx.h b/drivers/mfd/mc13xxx.h
new file mode 100644
index 0000000..bbba06f
--- /dev/null
+++ b/drivers/mfd/mc13xxx.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Creative Product Design
+ * Marc Reilly <marc@cpdesign.com.au>
+ *
+ * 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.
+ */
+#ifndef __DRIVERS_MFD_MC13XXX_H
+#define __DRIVERS_MFD_MC13XXX_H
+
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mc13xxx.h>
+
+enum mc13xxx_id {
+	MC13XXX_ID_MC13783,
+	MC13XXX_ID_MC13892,
+	MC13XXX_ID_INVALID,
+};
+
+#define MC13XXX_NUMREGS 0x3f
+
+struct mc13xxx {
+	struct regmap *regmap;
+
+	struct device *dev;
+	enum mc13xxx_id ictype;
+
+	struct mutex lock;
+	int irq;
+	int flags;
+
+	irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
+	void *irqdata[MC13XXX_NUM_IRQ];
+
+	int adcflags;
+};
+
+int mc13xxx_common_init(struct mc13xxx *mc13xxx,
+		struct mc13xxx_platform_data *pdata, int irq);
+
+void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx);
+
+#endif /* __DRIVERS_MFD_MC13XXX_H */
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver
  2012-03-14 20:43 mc13xxx: add I2C support (now with regmap), V3 Marc Reilly
                   ` (4 preceding siblings ...)
  2012-03-14 20:43 ` [PATCH v3 5/6] mfd: mc13xxx-core: Move spi specific code into separate module Marc Reilly
@ 2012-03-14 20:43 ` Marc Reilly
  2012-03-14 22:15   ` Fabio Estevam
  2012-03-15 13:40   ` Shubhrajyoti Datta
  5 siblings, 2 replies; 12+ messages in thread
From: Marc Reilly @ 2012-03-14 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

Adds support for mc13xxx family ICs connected via i2c.

Signed-off-by: Marc Reilly <marc@cpdesign.com.au>
---
 drivers/mfd/Kconfig       |    8 +++-
 drivers/mfd/Makefile      |    1 +
 drivers/mfd/mc13xxx-i2c.c |  128 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 136 insertions(+), 1 deletions(-)
 create mode 100644 drivers/mfd/mc13xxx-i2c.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 501fee5..3a039ff 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -573,7 +573,7 @@ config MFD_MC13783
 
 config MFD_MC13XXX
 	tristate "Support Freescale MC13783 and MC13892"
-	depends on SPI_MASTER
+	depends on SPI_MASTER || I2C
 	select MFD_CORE
 	select MFD_MC13783
 	help
@@ -590,6 +590,12 @@ config MFD_MC13XXX_SPI
 	help
 	  Select this if your MC13xxx is connected via an SPI bus.
 
+config MFD_MC13XXX_I2C
+	tristate "MC13xxx I2C interface" if I2C
+	default I2C
+	help
+	  Select this if your MC13xxx is connected via an I2C bus.
+
 endif
 
 config ABX500_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2dc66ed..6d4566f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -54,6 +54,7 @@ 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_MC13XXX_I2C)	+= mc13xxx-i2c.o
 
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c
new file mode 100644
index 0000000..1fb89af
--- /dev/null
+++ b/drivers/mfd/mc13xxx-i2c.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2009-2010 Creative Product Design
+ * Marc Reilly marc at cpdesign.com.au
+ *
+ * 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/mfd/core.h>
+#include <linux/mfd/mc13xxx.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include "mc13xxx.h"
+
+static const struct i2c_device_id mc13xxx_i2c_device_id[] = {
+	{
+		.name = "mc13783",
+		.driver_data = MC13XXX_ID_MC13783
+	}, {
+		.name = "mc13892",
+		.driver_data = MC13XXX_ID_MC13892,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(i2c, mc13xxx_i2c_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 struct regmap_config mc13xxx_regmap_i2c_config = {
+	.reg_bits = 8,
+	.val_bits = 24,
+
+	.max_register = MC13XXX_NUMREGS,
+
+	.cache_type = REGCACHE_NONE,
+};
+
+static int mc13xxx_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	const struct of_device_id *of_id;
+	struct i2c_driver *idrv = to_i2c_driver(client->dev.driver);
+	struct mc13xxx *mc13xxx;
+	struct mc13xxx_platform_data *pdata = dev_get_platdata(&client->dev);
+	int ret;
+
+	of_id = of_match_device(mc13xxx_dt_ids, &client->dev);
+	if (of_id)
+		idrv->id_table =
+			&mc13xxx_i2c_device_id[(enum mc13xxx_id) of_id->data];
+
+	mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
+	if (!mc13xxx)
+		return -ENOMEM;
+
+	dev_set_drvdata(&client->dev, mc13xxx);
+
+	mc13xxx->dev = &client->dev;
+	mutex_init(&mc13xxx->lock);
+
+	mc13xxx->regmap = regmap_init_i2c(client, &mc13xxx_regmap_i2c_config);
+	if (IS_ERR(mc13xxx->regmap)) {
+		ret = PTR_ERR(mc13xxx->regmap);
+		dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
+				ret);
+		dev_set_drvdata(&client->dev, NULL);
+		return ret;
+	}
+
+	ret = mc13xxx_common_init(mc13xxx, pdata, client->irq);
+
+	if (ret == 0 && (id->driver_data != mc13xxx->ictype))
+		dev_warn(mc13xxx->dev,
+				"device id doesn't match auto detection!\n");
+
+	return ret;
+}
+
+static int __devexit mc13xxx_i2c_remove(struct i2c_client *client)
+{
+	struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev);
+
+	mc13xxx_common_cleanup(mc13xxx);
+
+	return 0;
+}
+
+static struct i2c_driver mc13xxx_i2c_driver = {
+	.id_table = mc13xxx_i2c_device_id,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "mc13xxx",
+		.of_match_table = mc13xxx_dt_ids,
+	},
+	.probe = mc13xxx_i2c_probe,
+	.remove = __devexit_p(mc13xxx_i2c_remove),
+};
+
+static int __init mc13xxx_i2c_init(void)
+{
+	return i2c_add_driver(&mc13xxx_i2c_driver);
+}
+subsys_initcall(mc13xxx_i2c_init);
+
+static void __exit mc13xxx_i2c_exit(void)
+{
+	i2c_del_driver(&mc13xxx_i2c_driver);
+}
+module_exit(mc13xxx_i2c_exit);
+
+MODULE_DESCRIPTION("i2c driver for Freescale MC13XXX PMIC");
+MODULE_AUTHOR("Marc Reilly <marc@cpdesign.com.au");
+MODULE_LICENSE("GPL v2");
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver
  2012-03-14 20:43 ` [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver Marc Reilly
@ 2012-03-14 22:15   ` Fabio Estevam
  2012-03-15 13:40   ` Shubhrajyoti Datta
  1 sibling, 0 replies; 12+ messages in thread
From: Fabio Estevam @ 2012-03-14 22:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On Wed, Mar 14, 2012 at 5:43 PM, Marc Reilly <marc@cpdesign.com.au> wrote:

> +
> +static const struct i2c_device_id mc13xxx_i2c_device_id[] = {
> + ? ? ? {
> + ? ? ? ? ? ? ? .name = "mc13783",
> + ? ? ? ? ? ? ? .driver_data = MC13XXX_ID_MC13783

mc13783 does not have i2c interface.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/6] regmap: add support for 7_25 format
  2012-03-14 20:43 ` [PATCH v3 1/6] regmap: add support for 7_25 format Marc Reilly
@ 2012-03-15 10:44   ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2012-03-15 10:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 15, 2012 at 07:43:05AM +1100, Marc Reilly wrote:
> This adds support for devices with 7 address bits and 25 data bits.
> The initial intended user for this are the mc13xxx mfds in spi mode.
> (The 25th data bit is actually a dummy bit)
> 
> Signed-off-by: Marc Reilly <marc@cpdesign.com.au>

It looks like this should be using the pad_bits parameter, though
currently we only actually support pad bytes and integer sized register
values.  Ugh.  We also have some entertainment because this device
contains a touchscreen so I imagine you want readback but devices using
odd register sizes don't do readback right now.

What I think we want to do here is use pad_bits then internally to the
API notice that reg_bits + pad_bits is a byte and therefore set up for 8
bit registers and set a new value reg_shift in the map which shifts the
register address left, either teaching the register format functions
about it or just making a new one.  This should work better from a
framework point of view.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120315/5fbd7597/attachment.sig>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 2/6] regmap: Add support for device with 24 data bits.
  2012-03-14 20:43 ` [PATCH v3 2/6] regmap: Add support for device with 24 data bits Marc Reilly
@ 2012-03-15 10:46   ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2012-03-15 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 15, 2012 at 07:43:06AM +1100, Marc Reilly wrote:
> Add support for devices with 24 data bits.

Not sure what you generated this patch against but it doesn't apply to
my topic/core or against -next.  Please regenerate it against
topic/core, it looks good.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120315/1524d0cd/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver
  2012-03-14 20:43 ` [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver Marc Reilly
  2012-03-14 22:15   ` Fabio Estevam
@ 2012-03-15 13:40   ` Shubhrajyoti Datta
  1 sibling, 0 replies; 12+ messages in thread
From: Shubhrajyoti Datta @ 2012-03-15 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On Thu, Mar 15, 2012 at 2:13 AM, Marc Reilly <marc@cpdesign.com.au> wrote:
> Adds support for mc13xxx family ICs connected via i2c.
>
> Signed-off-by: Marc Reilly <marc@cpdesign.com.au>
> ---
<snip>

> +static int mc13xxx_i2c_probe(struct i2c_client *client,
> + ? ? ? ? ? ? ? const struct i2c_device_id *id)
> +{
> + ? ? ? const struct of_device_id *of_id;
> + ? ? ? struct i2c_driver *idrv = to_i2c_driver(client->dev.driver);
> + ? ? ? struct mc13xxx *mc13xxx;
> + ? ? ? struct mc13xxx_platform_data *pdata = dev_get_platdata(&client->dev);
> + ? ? ? int ret;
> +
> + ? ? ? of_id = of_match_device(mc13xxx_dt_ids, &client->dev);
> + ? ? ? if (of_id)
> + ? ? ? ? ? ? ? idrv->id_table =
> + ? ? ? ? ? ? ? ? ? ? ? &mc13xxx_i2c_device_id[(enum mc13xxx_id) of_id->data];
> +
> + ? ? ? mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
> + ? ? ? if (!mc13xxx)
> + ? ? ? ? ? ? ? return -ENOMEM;
> +
> + ? ? ? dev_set_drvdata(&client->dev, mc13xxx);
> +
> + ? ? ? mc13xxx->dev = &client->dev;
> + ? ? ? mutex_init(&mc13xxx->lock);
> +
> + ? ? ? mc13xxx->regmap = regmap_init_i2c(client, &mc13xxx_regmap_i2c_config);
> + ? ? ? if (IS_ERR(mc13xxx->regmap)) {
> + ? ? ? ? ? ? ? ret = PTR_ERR(mc13xxx->regmap);
> + ? ? ? ? ? ? ? dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? dev_set_drvdata(&client->dev, NULL);
Are we  leaking mc13xxx here
May be you can consider using devm* functions ?

>  + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 4/6] mfd: mc13xxx-core: use regmap for register access
  2012-03-14 20:43 ` [PATCH v3 4/6] mfd: mc13xxx-core: use regmap for register access Marc Reilly
@ 2012-03-15 17:43   ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2012-03-15 17:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 15, 2012 at 07:43:08AM +1100, Marc Reilly wrote:
> This change converts the mc13xxx core to use regmap rather than direct
> spi r/w.
> The spidev member of mc13xxx struct becomes redundant and is removed.
> Extra debugging aids are added to mc13xxx_reg_rmw.
> Mutex init is moved to before regmap init.

Reviwed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

For rmw please push the trace down into regmap as a new tracepoint if
you find it useful; one of the wins from regmap is intended to be the
trace and diagnostic infrastructure you get for free with it.  At the
minute only the underlying reads and writes have trace.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120315/ea3df634/attachment.sig>

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2012-03-15 17:43 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-14 20:43 mc13xxx: add I2C support (now with regmap), V3 Marc Reilly
2012-03-14 20:43 ` [PATCH v3 1/6] regmap: add support for 7_25 format Marc Reilly
2012-03-15 10:44   ` Mark Brown
2012-03-14 20:43 ` [PATCH v3 2/6] regmap: Add support for device with 24 data bits Marc Reilly
2012-03-15 10:46   ` Mark Brown
2012-03-14 20:43 ` [PATCH v3 3/6] mfd: mc13xxx-core: Prepare for separate spi and i2c backends Marc Reilly
2012-03-14 20:43 ` [PATCH v3 4/6] mfd: mc13xxx-core: use regmap for register access Marc Reilly
2012-03-15 17:43   ` Mark Brown
2012-03-14 20:43 ` [PATCH v3 5/6] mfd: mc13xxx-core: Move spi specific code into separate module Marc Reilly
2012-03-14 20:43 ` [PATCH v3 6/6] mfd: mc13xxx: Add i2c driver Marc Reilly
2012-03-14 22:15   ` Fabio Estevam
2012-03-15 13:40   ` Shubhrajyoti Datta

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).