All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] support PMIC mc13892
@ 2010-12-06  6:25 yong.shen at freescale.com
  2010-12-06  7:22 ` Uwe Kleine-König
                   ` (3 more replies)
  0 siblings, 4 replies; 21+ messages in thread
From: yong.shen at freescale.com @ 2010-12-06  6:25 UTC (permalink / raw)
  To: linux-arm-kernel

From: Yong Shen <yong.shen@linaro.org>

add support for mc13892, tested on mx51 babbage board

Signed-off-by: Yong Shen <yong.shen@linaro.org>
---
 drivers/mfd/Kconfig                   |    4 +
 drivers/regulator/Kconfig             |    8 +
 drivers/regulator/Makefile            |    1 +
 drivers/regulator/mc13892-regulator.c |  647 +++++++++++++++++++++++++++++++++
 include/linux/mfd/mc13892.h           |   38 ++
 5 files changed, 698 insertions(+), 0 deletions(-)
 create mode 100644 drivers/regulator/mc13892-regulator.c
 create mode 100644 include/linux/mfd/mc13892.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3a1493b..7659af9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -427,11 +427,15 @@ config MFD_PCF50633
 config MFD_MC13783
 	tristate
 
+config MFD_MC13892
+	tristate
+
 config MFD_MC13XXX
 	tristate "Support Freescale MC13783 and MC13892"
 	depends on SPI_MASTER
 	select MFD_CORE
 	select MFD_MC13783
+	select MFD_MC13892
 	help
 	  Support for the Freescale (Atlas) PMIC and audio CODECs
 	  MC13783 and MC13892.
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6e54253..7f7bc22 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -197,6 +197,14 @@ config REGULATOR_MC13783
 	  Say y here to support the regulators found on the Freescale MC13783
 	  PMIC.
 
+config REGULATOR_MC13892
+	tristate "Support regulators on Freescale MC13892 PMIC"
+	depends on MFD_MC13892
+	select REGULATOR_MC13XXX_CORE
+	help
+	  Say y here to support the regulators found on the Freescale MC13892
+	  PMIC.
+
 config REGULATOR_AB3100
 	tristate "ST-Ericsson AB3100 Regulator functions"
 	depends on AB3100_CORE
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 11876be..3107480 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
+obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
 
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
new file mode 100644
index 0000000..6e613d4
--- /dev/null
+++ b/drivers/regulator/mc13892-regulator.c
@@ -0,0 +1,647 @@
+/*
+ * Regulator Driver for Freescale MC13892 PMIC
+ *
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * 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/mfd/mc13892.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include "mc13xxx.h"
+
+#define MC13892_REVISION				7
+
+#define MC13892_POWERCTL0				13
+#define MC13892_POWERCTL0_USEROFFSPI		3
+#define MC13892_POWERCTL0_VCOINCELLVSEL		20
+#define MC13892_POWERCTL0_VCOINCELLVSEL_M		(7<<20)
+#define MC13892_POWERCTL0_VCOINCELLEN		(1<<23)
+
+#define MC13892_SWITCHERS0_SWxHI			(1<<23)
+
+#define MC13892_SWITCHERS0				24
+#define MC13892_SWITCHERS0_SW1VSEL			0
+#define MC13892_SWITCHERS0_SW1VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS0_SW1HI			(1<<23)
+#define MC13892_SWITCHERS0_SW1EN		0
+
+#define MC13892_SWITCHERS1				25
+#define MC13892_SWITCHERS1_SW2VSEL			0
+#define MC13892_SWITCHERS1_SW2VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS1_SW2HI			(1<<23)
+#define MC13892_SWITCHERS1_SW2EN		0
+
+#define MC13892_SWITCHERS2				26
+#define MC13892_SWITCHERS2_SW3VSEL			0
+#define MC13892_SWITCHERS2_SW3VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS2_SW3HI			(1<<23)
+#define MC13892_SWITCHERS2_SW3EN		0
+
+#define MC13892_SWITCHERS3				27
+#define MC13892_SWITCHERS3_SW4VSEL			0
+#define MC13892_SWITCHERS3_SW4VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS3_SW4HI			(1<<23)
+#define MC13892_SWITCHERS3_SW4EN		0
+
+#define MC13892_SWITCHERS4				28
+#define MC13892_SWITCHERS4_SW1MODE			0
+#define MC13892_SWITCHERS4_SW1MODE_AUTO		(8<<0)
+#define MC13892_SWITCHERS4_SW1MODE_M		(0xf<<0)
+#define MC13892_SWITCHERS4_SW2MODE			10
+#define MC13892_SWITCHERS4_SW2MODE_AUTO		(8<<10)
+#define MC13892_SWITCHERS4_SW2MODE_M		(0xf<<10)
+
+#define MC13892_SWITCHERS5				29
+#define MC13892_SWITCHERS5_SW3MODE			0
+#define MC13892_SWITCHERS5_SW3MODE_AUTO		(8<<0)
+#define MC13892_SWITCHERS5_SW3MODE_M		(0xf<<0)
+#define MC13892_SWITCHERS5_SW4MODE			8
+#define MC13892_SWITCHERS5_SW4MODE_AUTO		(8<<8)
+#define MC13892_SWITCHERS5_SW4MODE_M		(0xf<<8)
+#define MC13892_SWITCHERS5_SWBSTEN			(1<<20)
+
+
+#define MC13892_REGULATORSETTING0			30
+#define MC13892_REGULATORSETTING0_VGEN1VSEL		0
+#define MC13892_REGULATORSETTING0_VDIGVSEL		4
+#define MC13892_REGULATORSETTING0_VGEN2VSEL		6
+#define MC13892_REGULATORSETTING0_VPLLVSEL		9
+#define MC13892_REGULATORSETTING0_VUSB2VSEL		11
+#define MC13892_REGULATORSETTING0_VGEN3VSEL		14
+#define MC13892_REGULATORSETTING0_VCAMVSEL		16
+
+#define MC13892_REGULATORSETTING0_VGEN1VSEL_M	(3<<0)
+#define MC13892_REGULATORSETTING0_VDIGVSEL_M	(3<<4)
+#define MC13892_REGULATORSETTING0_VGEN2VSEL_M	(7<<6)
+#define MC13892_REGULATORSETTING0_VPLLVSEL_M	(3<<9)
+#define MC13892_REGULATORSETTING0_VUSB2VSEL_M	(3<<11)
+#define MC13892_REGULATORSETTING0_VGEN3VSEL_M	(1<<14)
+#define MC13892_REGULATORSETTING0_VCAMVSEL_M	(3<<16)
+
+#define MC13892_REGULATORSETTING1			31
+#define MC13892_REGULATORSETTING1_VVIDEOVSEL	2
+#define MC13892_REGULATORSETTING1_VAUDIOVSEL	4
+#define MC13892_REGULATORSETTING1_VSDVSEL		6
+
+#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M	(3<<2)
+#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M	(3<<4)
+#define MC13892_REGULATORSETTING1_VSDVSEL_M		(7<<6)
+
+#define MC13892_REGULATORMODE0			32
+#define MC13892_REGULATORMODE0_VGEN1EN		(1<<0)
+#define MC13892_REGULATORMODE0_VGEN1STDBY		(1<<1)
+#define MC13892_REGULATORMODE0_VGEN1MODE		(1<<2)
+#define MC13892_REGULATORMODE0_VIOHIEN		(1<<3)
+#define MC13892_REGULATORMODE0_VIOHISTDBY		(1<<4)
+#define MC13892_REGULATORMODE0_VIOHIMODE		(1<<5)
+#define MC13892_REGULATORMODE0_VDIGEN		(1<<9)
+#define MC13892_REGULATORMODE0_VDIGSTDBY		(1<<10)
+#define MC13892_REGULATORMODE0_VDIGMODE		(1<<11)
+#define MC13892_REGULATORMODE0_VGEN2EN		(1<<12)
+#define MC13892_REGULATORMODE0_VGEN2STDBY		(1<<13)
+#define MC13892_REGULATORMODE0_VGEN2MODE		(1<<14)
+#define MC13892_REGULATORMODE0_VPLLEN		(1<<15)
+#define MC13892_REGULATORMODE0_VPLLSTDBY		(1<<16)
+#define MC13892_REGULATORMODE0_VPLLMODE		(1<<17)
+#define MC13892_REGULATORMODE0_VUSB2EN		(1<<18)
+#define MC13892_REGULATORMODE0_VUSB2STDBY		(1<<19)
+#define MC13892_REGULATORMODE0_VUSB2MODE		(1<<20)
+
+#define MC13892_REGULATORMODE1			33
+#define MC13892_REGULATORMODE1_VGEN3EN		(1<<0)
+#define MC13892_REGULATORMODE1_VGEN3STDBY		(1<<1)
+#define MC13892_REGULATORMODE1_VGEN3MODE		(1<<2)
+#define MC13892_REGULATORMODE1_VCAMEN		(1<<6)
+#define MC13892_REGULATORMODE1_VCAMSTDBY		(1<<7)
+#define MC13892_REGULATORMODE1_VCAMMODE		(1<<8)
+#define MC13892_REGULATORMODE1_VCAMCONFIGEN		(1<<9)
+#define MC13892_REGULATORMODE1_VVIDEOEN		(1<<12)
+#define MC13892_REGULATORMODE1_VVIDEOSTDBY		(1<<13)
+#define MC13892_REGULATORMODE1_VVIDEOMODE		(1<<14)
+#define MC13892_REGULATORMODE1_VAUDIOEN		(1<<15)
+#define MC13892_REGULATORMODE1_VAUDIOSTDBY		(1<<16)
+#define MC13892_REGULATORMODE1_VAUDIOMODE		(1<<17)
+#define MC13892_REGULATORMODE1_VSDEN		(1<<18)
+#define MC13892_REGULATORMODE1_VSDSTDBY		(1<<19)
+#define MC13892_REGULATORMODE1_VSDMODE		(1<<20)
+
+#define MC13892_POWERMISC				34
+#define MC13892_POWERMISC_GPO1EN			(1<<6)
+#define MC13892_POWERMISC_GPO2EN			(1<<8)
+#define MC13892_POWERMISC_GPO3EN			(1<<10)
+#define MC13892_POWERMISC_GPO4EN			(1<<12)
+#define MC13892_POWERMISC_PWGT1SPIEN		(1<<15)
+#define MC13892_POWERMISC_PWGT2SPIEN		(1<<16)
+#define MC13892_POWERMISC_GPO4ADINEN		(1<<21)
+
+#define MC13892_POWERMISC_PWGTSPI_M			(3 << 15)
+
+#define MC13892_USB1				50
+#define MC13892_USB1_VUSBEN				(1<<3)
+
+static const int mc13892_vcoincell[] = {
+	2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
+	3200000, 3300000,
+};
+
+static const int mc13892_sw1[] = {
+	600000,   625000,  650000,  675000,  700000,  725000,
+	750000,   775000,  800000,  825000,  850000,  875000,
+	900000,   925000,  950000,  975000, 1000000, 1025000,
+	1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+	1350000, 1375000
+};
+
+static const int mc13892_sw[] = {
+	600000,   625000,  650000,  675000,  700000,  725000,
+	750000,   775000,  800000,  825000,  850000,  875000,
+	900000,   925000,  950000,  975000, 1000000, 1025000,
+	1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+	1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
+	1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
+	1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
+	1800000, 1825000, 1850000, 1875000
+};
+
+static const int mc13892_swbst[] = {
+	5000000,
+};
+
+static const int mc13892_viohi[] = {
+	2775000,
+};
+
+static const int mc13892_vpll[] = {
+	1050000, 1250000, 1650000, 1800000,
+};
+
+static const int mc13892_vdig[] = {
+	1050000, 1250000, 1650000, 1800000,
+};
+
+static const int mc13892_vsd[] = {
+	1800000, 2000000, 2600000, 2700000,
+	2800000, 2900000, 3000000, 3150000,
+};
+
+static const int mc13892_vusb2[] = {
+	2400000, 2600000, 2700000, 2775000,
+};
+
+static const int mc13892_vvideo[] = {
+	2500000, 2600000, 270000, 2775000,
+};
+
+static const int mc13892_vaudio[] = {
+	2300000, 2500000, 2775000, 3000000,
+};
+
+static const int mc13892_vcam[] = {
+	2500000, 2600000, 2750000, 3000000,
+};
+
+static const int mc13892_vgen1[] = {
+	1200000, 1500000, 2775000, 3150000,
+};
+
+static const int mc13892_vgen2[] = {
+	1200000, 1500000, 1600000, 1800000,
+	2700000, 2800000, 3000000, 3150000,
+};
+
+static const int mc13892_vgen3[] = {
+	1800000, 2900000,
+};
+
+static const int mc13892_vusb[] = {
+	3300000,
+};
+
+static const int mc13892_gpo[] = {
+	2750000,
+};
+
+static const int mc13892_pwgtdrv[] = {
+	5000000,
+};
+
+static struct regulator_ops mc13892_gpo_regulator_ops;
+/* sw regulators need special care due to the "hi bit" */
+static struct regulator_ops mc13892_sw_regulator_ops;
+
+
+#define MC13892_FIXED_DEFINE(name, reg, voltages)\
+	MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \
+			mc13xxx_fixed_regulator_ops)
+
+#define MC13892_GPO_DEFINE(name, reg, voltages)		\
+	MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \
+			mc13892_gpo_regulator_ops)
+
+#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages)		\
+	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
+			mc13892_sw_regulator_ops)
+
+#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages)		\
+	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
+			mc13xxx_regulator_ops)
+
+static struct mc13xxx_regulator mc13892_regulators[] = {
+	MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0,		\
+			    mc13892_vcoincell),
+	MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1),
+	MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw),
+	MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw),
+	MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw),
+	MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst),
+	MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi),
+	MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13892_vpll),
+	MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13892_vdig),
+	MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13892_vsd),
+	MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13892_vusb2),
+	MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13892_vvideo),
+	MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13892_vaudio),
+	MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
+			    mc13892_vcam),
+	MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13892_vgen1),
+	MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13892_vgen2),
+	MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0,	\
+			    mc13892_vgen3),
+	MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb),
+	MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv),
+	MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv),
+};
+
+int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
+									u32 val)
+{
+	struct mc13xxx *mc13892 = priv->mc13xxx;
+	int ret;
+	u32 valread;
+
+	BUG_ON(val & ~mask);
+
+	ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
+	if (ret)
+		return ret;
+
+	/* Update the stored state for Power Gates. */
+	priv->powermisc_pwgt_state =
+				(priv->powermisc_pwgt_state & ~mask) | val;
+	priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M;
+
+	/* Construct the new register value */
+	valread = (valread & ~mask) | val;
+	/* Overwrite the PWGTxEN with the stored version */
+	valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
+						priv->powermisc_pwgt_state;
+
+	return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
+}
+
+static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int ret;
+	u32 en_val = mc13892_regulators[id].enable_bit;
+	u32 mask = mc13892_regulators[id].enable_bit;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	/* Power Gate enable value is 0 */
+	if (id == MC13892_PWGT1SPI ||
+	    id == MC13892_PWGT2SPI)
+		en_val = 0;
+
+	if (id == MC13892_GPO4)
+		mask |= MC13892_POWERMISC_GPO4ADINEN;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13892_powermisc_rmw(priv, mask, en_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int ret;
+	u32 dis_val = 0;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	/* Power Gate disable value is 1 */
+	if (id == MC13892_PWGT1SPI ||
+	    id == MC13892_PWGT2SPI)
+		dis_val = mc13892_regulators[id].enable_bit;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
+					dis_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	/* Power Gates state is stored in powermisc_pwgt_state
+	 * where the meaning of bits is negated */
+	val = (val & ~MC13892_POWERMISC_PWGTSPI_M) |
+	      (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M);
+
+	return (val & mc13892_regulators[id].enable_bit) != 0;
+}
+
+
+static struct regulator_ops mc13892_gpo_regulator_ops = {
+	.enable = mc13892_gpo_regulator_enable,
+	.disable = mc13892_gpo_regulator_disable,
+	.is_enabled = mc13892_gpo_regulator_is_enabled,
+	.list_voltage = mc13xxx_regulator_list_voltage,
+	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
+	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
+};
+
+static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val, hi;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx,
+				mc13892_regulators[id].vsel_reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+	if (ret)
+		return ret;
+
+	hi  = val & MC13892_SWITCHERS0_SWxHI;
+	val = (val & mc13892_regulators[id].vsel_mask)
+		>> mc13892_regulators[id].vsel_shift;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+	if (hi)
+		val = (25000 * val) + 1100000;
+	else
+		val = (25000 * val) + 600000;
+
+	return val;
+}
+
+static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
+						int min_uV, int max_uV)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int hi, value, val, mask, id = rdev_get_id(rdev);
+	int ret;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+		__func__, id, min_uV, max_uV);
+
+	/* Find the best index */
+	value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
+	dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
+	if (value < 0)
+		return value;
+
+	value = mc13892_regulators[id].voltages[value];
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx,
+				mc13892_regulators[id].vsel_reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+	if (ret)
+		return ret;
+
+	hi  = val & MC13892_SWITCHERS0_SWxHI;
+	if (value > 1375)
+		hi = 1;
+	if (value < 1100)
+		hi = 0;
+
+	if (hi) {
+		value = (value - 1100000) / 25000;
+		value |= MC13892_SWITCHERS0_SWxHI;
+	} else
+		value = (value - 600000) / 25000;
+
+	mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
+			mask,
+			value << mc13892_regulators[id].vsel_shift);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static struct regulator_ops mc13892_sw_regulator_ops = {
+	.is_enabled = mc13xxx_sw_regulator_is_enabled,
+	.list_voltage = mc13xxx_regulator_list_voltage,
+	.set_voltage = mc13892_sw_regulator_set_voltage,
+	.get_voltage = mc13892_sw_regulator_get_voltage,
+};
+
+static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	unsigned int en_val = 0;
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+
+	if (mode == REGULATOR_MODE_FAST)
+		en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg,
+			MC13892_REGULATORMODE1_VCAMCONFIGEN,
+			en_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN)
+		return REGULATOR_MODE_FAST;
+
+	return REGULATOR_MODE_NORMAL;
+}
+
+
+static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
+{
+	struct mc13xxx_regulator_priv *priv;
+	struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
+	struct mc13xxx_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
+	struct mc13xxx_regulator_init_data *init_data;
+	int i, ret;
+	u32 val;
+
+	priv = kzalloc(sizeof(*priv) +
+			pdata->num_regulators * sizeof(priv->regulators[0]),
+			GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->mc13xxx_regulators = mc13892_regulators;
+	priv->mc13xxx = mc13892;
+
+	mc13xxx_lock(mc13892);
+	ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val);
+	mc13xxx_unlock(mc13892);
+	if (ret)
+		goto err_alloc;
+
+	/* enable switch auto mode - ENGR00120510, ENGR00121057 */
+	/* no doc with regs description means no way to know if */
+	/* there's a better way to do it			*/
+	if ((val & 0x0000FFFF) == 0x45d0) {
+		mc13xxx_lock(mc13892);
+		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
+			MC13892_SWITCHERS4_SW1MODE_M |
+			MC13892_SWITCHERS4_SW2MODE_M,
+			MC13892_SWITCHERS4_SW1MODE_AUTO |
+			MC13892_SWITCHERS4_SW2MODE_AUTO);
+		mc13xxx_unlock(mc13892);
+		if (ret)
+			goto err_alloc;
+
+		mc13xxx_lock(mc13892);
+		mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5,
+			MC13892_SWITCHERS5_SW3MODE_M |
+			MC13892_SWITCHERS5_SW4MODE_M,
+			MC13892_SWITCHERS5_SW3MODE_AUTO |
+			MC13892_SWITCHERS5_SW4MODE_AUTO);
+		mc13xxx_unlock(mc13892);
+		if (ret)
+			goto err_alloc;
+	}
+
+	mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
+		= mc13892_vcam_set_mode;
+	mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
+		= mc13892_vcam_get_mode;
+	for (i = 0; i < pdata->num_regulators; i++) {
+		init_data = &pdata->regulators[i];
+		priv->regulators[i] = regulator_register(
+				&mc13892_regulators[init_data->id].desc,
+				&pdev->dev, init_data->init_data, priv);
+
+		if (IS_ERR(priv->regulators[i])) {
+			dev_err(&pdev->dev, "failed to register regulator %s\n",
+				mc13892_regulators[i].desc.name);
+			ret = PTR_ERR(priv->regulators[i]);
+			goto err;
+		}
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+err:
+	while (--i >= 0)
+		regulator_unregister(priv->regulators[i]);
+
+err_alloc:
+	kfree(priv);
+
+	return ret;
+}
+
+static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
+{
+	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
+	struct mc13xxx_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
+	int i;
+
+	platform_set_drvdata(pdev, NULL);
+
+	for (i = 0; i < pdata->num_regulators; i++)
+		regulator_unregister(priv->regulators[i]);
+
+	kfree(priv);
+	return 0;
+}
+
+static struct platform_driver mc13892_regulator_driver = {
+	.driver	= {
+		.name	= "mc13892-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __devexit_p(mc13892_regulator_remove),
+	.probe		= mc13892_regulator_probe,
+};
+
+static int __init mc13892_regulator_init(void)
+{
+	return platform_driver_register(&mc13892_regulator_driver);
+}
+subsys_initcall(mc13892_regulator_init);
+
+static void __exit mc13892_regulator_exit(void)
+{
+	platform_driver_unregister(&mc13892_regulator_driver);
+}
+module_exit(mc13892_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC");
+MODULE_ALIAS("platform:mc13892-regulator");
diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h
new file mode 100644
index 0000000..7df13e8
--- /dev/null
+++ b/include/linux/mfd/mc13892.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * 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 __LINUX_MFD_MC13892_H
+#define __LINUX_MFD_MC13892_H
+#include <linux/mfd/mc13xxx.h>
+
+#define MC13892_SW1		0
+#define MC13892_SW2		1
+#define MC13892_SW3		2
+#define MC13892_SW4		3
+#define MC13892_SWBST	4
+#define MC13892_VIOHI	5
+#define MC13892_VPLL	6
+#define MC13892_VDIG	7
+#define MC13892_VSD	8
+#define MC13892_VUSB2	9
+#define MC13892_VVIDEO	10
+#define MC13892_VAUDIO	11
+#define MC13892_VCAM	12
+#define MC13892_VGEN1	13
+#define MC13892_VGEN2	14
+#define MC13892_VGEN3	15
+#define MC13892_VUSB	16
+#define MC13892_GPO1	17
+#define MC13892_GPO2	18
+#define MC13892_GPO3	19
+#define MC13892_GPO4	20
+#define MC13892_PWGT1SPI	21
+#define MC13892_PWGT2SPI	22
+#define MC13892_VCOINCELL	23
+
+#endif
-- 
1.7.0.4

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

* [PATCH] support PMIC mc13892
  2010-12-06  6:25 [PATCH] support PMIC mc13892 yong.shen at freescale.com
@ 2010-12-06  7:22 ` Uwe Kleine-König
  2010-12-07  2:41   ` Yong Shen
  2010-12-07  7:57   ` Yong Shen
  2010-12-06 10:40 ` David Jander
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 21+ messages in thread
From: Uwe Kleine-König @ 2010-12-06  7:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Mon, Dec 06, 2010 at 02:25:35PM +0800, yong.shen at freescale.com wrote:
> From: Yong Shen <yong.shen@linaro.org>
> 
> add support for mc13892, tested on mx51 babbage board
> 
> Signed-off-by: Yong Shen <yong.shen@linaro.org>
> ---
>  drivers/mfd/Kconfig                   |    4 +
>  drivers/regulator/Kconfig             |    8 +
>  drivers/regulator/Makefile            |    1 +
>  drivers/regulator/mc13892-regulator.c |  647 +++++++++++++++++++++++++++++++++
>  include/linux/mfd/mc13892.h           |   38 ++
>  5 files changed, 698 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/regulator/mc13892-regulator.c
>  create mode 100644 include/linux/mfd/mc13892.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 3a1493b..7659af9 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -427,11 +427,15 @@ config MFD_PCF50633
>  config MFD_MC13783
>  	tristate
>  
> +config MFD_MC13892
> +	tristate
> +
This is not needed, MFD_MC13783 only exists because when MFD_MC13XXX was
introduced some drivers still depended on MFD_MC13783.  As mc13xxx.[ch]
provided enough compatibility cruft MFD_MC13XXX just selected MFD_MC13783.

>  config MFD_MC13XXX
>  	tristate "Support Freescale MC13783 and MC13892"
>  	depends on SPI_MASTER
>  	select MFD_CORE
>  	select MFD_MC13783
> +	select MFD_MC13892
>  	help
>  	  Support for the Freescale (Atlas) PMIC and audio CODECs
>  	  MC13783 and MC13892.
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index 6e54253..7f7bc22 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -197,6 +197,14 @@ config REGULATOR_MC13783
>  	  Say y here to support the regulators found on the Freescale MC13783
>  	  PMIC.
>  
> +config REGULATOR_MC13892
> +	tristate "Support regulators on Freescale MC13892 PMIC"
> +	depends on MFD_MC13892
> +	select REGULATOR_MC13XXX_CORE
> +	help
> +	  Say y here to support the regulators found on the Freescale MC13892
> +	  PMIC.
> +
>  config REGULATOR_AB3100
>  	tristate "ST-Ericsson AB3100 Regulator functions"
>  	depends on AB3100_CORE
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 11876be..3107480 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
>  obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
>  obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
>  obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
> +obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
>  obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
>  obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
>  
> diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
> new file mode 100644
> index 0000000..6e613d4
> --- /dev/null
> +++ b/drivers/regulator/mc13892-regulator.c
> @@ -0,0 +1,647 @@
> +/*
> + * Regulator Driver for Freescale MC13892 PMIC
> + *
> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
> + *
> + * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org>
> + *
> + * 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/mfd/mc13892.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/platform_device.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/err.h>
> +#include "mc13xxx.h"
shouldn't that be

	#include <linux/mfd/mc13xxx.h>

?
> +
> +#define MC13892_REVISION				7
> +
> +#define MC13892_POWERCTL0				13
> +#define MC13892_POWERCTL0_USEROFFSPI		3
> +#define MC13892_POWERCTL0_VCOINCELLVSEL		20
> +#define MC13892_POWERCTL0_VCOINCELLVSEL_M		(7<<20)
> +#define MC13892_POWERCTL0_VCOINCELLEN		(1<<23)
> +
> +#define MC13892_SWITCHERS0_SWxHI			(1<<23)
> +
> +#define MC13892_SWITCHERS0				24
> +#define MC13892_SWITCHERS0_SW1VSEL			0
> +#define MC13892_SWITCHERS0_SW1VSEL_M		(0x1f<<0)
> +#define MC13892_SWITCHERS0_SW1HI			(1<<23)
> +#define MC13892_SWITCHERS0_SW1EN		0
> +
> +#define MC13892_SWITCHERS1				25
> +#define MC13892_SWITCHERS1_SW2VSEL			0
> +#define MC13892_SWITCHERS1_SW2VSEL_M		(0x1f<<0)
> +#define MC13892_SWITCHERS1_SW2HI			(1<<23)
> +#define MC13892_SWITCHERS1_SW2EN		0
> +
> +#define MC13892_SWITCHERS2				26
> +#define MC13892_SWITCHERS2_SW3VSEL			0
> +#define MC13892_SWITCHERS2_SW3VSEL_M		(0x1f<<0)
> +#define MC13892_SWITCHERS2_SW3HI			(1<<23)
> +#define MC13892_SWITCHERS2_SW3EN		0
> +
> +#define MC13892_SWITCHERS3				27
> +#define MC13892_SWITCHERS3_SW4VSEL			0
> +#define MC13892_SWITCHERS3_SW4VSEL_M		(0x1f<<0)
> +#define MC13892_SWITCHERS3_SW4HI			(1<<23)
> +#define MC13892_SWITCHERS3_SW4EN		0
> +
> +#define MC13892_SWITCHERS4				28
> +#define MC13892_SWITCHERS4_SW1MODE			0
> +#define MC13892_SWITCHERS4_SW1MODE_AUTO		(8<<0)
> +#define MC13892_SWITCHERS4_SW1MODE_M		(0xf<<0)
> +#define MC13892_SWITCHERS4_SW2MODE			10
> +#define MC13892_SWITCHERS4_SW2MODE_AUTO		(8<<10)
> +#define MC13892_SWITCHERS4_SW2MODE_M		(0xf<<10)
> +
> +#define MC13892_SWITCHERS5				29
> +#define MC13892_SWITCHERS5_SW3MODE			0
> +#define MC13892_SWITCHERS5_SW3MODE_AUTO		(8<<0)
> +#define MC13892_SWITCHERS5_SW3MODE_M		(0xf<<0)
> +#define MC13892_SWITCHERS5_SW4MODE			8
> +#define MC13892_SWITCHERS5_SW4MODE_AUTO		(8<<8)
> +#define MC13892_SWITCHERS5_SW4MODE_M		(0xf<<8)
> +#define MC13892_SWITCHERS5_SWBSTEN			(1<<20)
> +
> +
> +#define MC13892_REGULATORSETTING0			30
> +#define MC13892_REGULATORSETTING0_VGEN1VSEL		0
> +#define MC13892_REGULATORSETTING0_VDIGVSEL		4
> +#define MC13892_REGULATORSETTING0_VGEN2VSEL		6
> +#define MC13892_REGULATORSETTING0_VPLLVSEL		9
> +#define MC13892_REGULATORSETTING0_VUSB2VSEL		11
> +#define MC13892_REGULATORSETTING0_VGEN3VSEL		14
> +#define MC13892_REGULATORSETTING0_VCAMVSEL		16
> +
> +#define MC13892_REGULATORSETTING0_VGEN1VSEL_M	(3<<0)
> +#define MC13892_REGULATORSETTING0_VDIGVSEL_M	(3<<4)
> +#define MC13892_REGULATORSETTING0_VGEN2VSEL_M	(7<<6)
> +#define MC13892_REGULATORSETTING0_VPLLVSEL_M	(3<<9)
> +#define MC13892_REGULATORSETTING0_VUSB2VSEL_M	(3<<11)
> +#define MC13892_REGULATORSETTING0_VGEN3VSEL_M	(1<<14)
> +#define MC13892_REGULATORSETTING0_VCAMVSEL_M	(3<<16)
> +
> +#define MC13892_REGULATORSETTING1			31
> +#define MC13892_REGULATORSETTING1_VVIDEOVSEL	2
> +#define MC13892_REGULATORSETTING1_VAUDIOVSEL	4
> +#define MC13892_REGULATORSETTING1_VSDVSEL		6
> +
> +#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M	(3<<2)
> +#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M	(3<<4)
> +#define MC13892_REGULATORSETTING1_VSDVSEL_M		(7<<6)
> +
> +#define MC13892_REGULATORMODE0			32
> +#define MC13892_REGULATORMODE0_VGEN1EN		(1<<0)
> +#define MC13892_REGULATORMODE0_VGEN1STDBY		(1<<1)
> +#define MC13892_REGULATORMODE0_VGEN1MODE		(1<<2)
> +#define MC13892_REGULATORMODE0_VIOHIEN		(1<<3)
> +#define MC13892_REGULATORMODE0_VIOHISTDBY		(1<<4)
> +#define MC13892_REGULATORMODE0_VIOHIMODE		(1<<5)
> +#define MC13892_REGULATORMODE0_VDIGEN		(1<<9)
> +#define MC13892_REGULATORMODE0_VDIGSTDBY		(1<<10)
> +#define MC13892_REGULATORMODE0_VDIGMODE		(1<<11)
> +#define MC13892_REGULATORMODE0_VGEN2EN		(1<<12)
> +#define MC13892_REGULATORMODE0_VGEN2STDBY		(1<<13)
> +#define MC13892_REGULATORMODE0_VGEN2MODE		(1<<14)
> +#define MC13892_REGULATORMODE0_VPLLEN		(1<<15)
> +#define MC13892_REGULATORMODE0_VPLLSTDBY		(1<<16)
> +#define MC13892_REGULATORMODE0_VPLLMODE		(1<<17)
> +#define MC13892_REGULATORMODE0_VUSB2EN		(1<<18)
> +#define MC13892_REGULATORMODE0_VUSB2STDBY		(1<<19)
> +#define MC13892_REGULATORMODE0_VUSB2MODE		(1<<20)
> +
> +#define MC13892_REGULATORMODE1			33
> +#define MC13892_REGULATORMODE1_VGEN3EN		(1<<0)
> +#define MC13892_REGULATORMODE1_VGEN3STDBY		(1<<1)
> +#define MC13892_REGULATORMODE1_VGEN3MODE		(1<<2)
> +#define MC13892_REGULATORMODE1_VCAMEN		(1<<6)
> +#define MC13892_REGULATORMODE1_VCAMSTDBY		(1<<7)
> +#define MC13892_REGULATORMODE1_VCAMMODE		(1<<8)
> +#define MC13892_REGULATORMODE1_VCAMCONFIGEN		(1<<9)
> +#define MC13892_REGULATORMODE1_VVIDEOEN		(1<<12)
> +#define MC13892_REGULATORMODE1_VVIDEOSTDBY		(1<<13)
> +#define MC13892_REGULATORMODE1_VVIDEOMODE		(1<<14)
> +#define MC13892_REGULATORMODE1_VAUDIOEN		(1<<15)
> +#define MC13892_REGULATORMODE1_VAUDIOSTDBY		(1<<16)
> +#define MC13892_REGULATORMODE1_VAUDIOMODE		(1<<17)
> +#define MC13892_REGULATORMODE1_VSDEN		(1<<18)
> +#define MC13892_REGULATORMODE1_VSDSTDBY		(1<<19)
> +#define MC13892_REGULATORMODE1_VSDMODE		(1<<20)
> +
> +#define MC13892_POWERMISC				34
> +#define MC13892_POWERMISC_GPO1EN			(1<<6)
> +#define MC13892_POWERMISC_GPO2EN			(1<<8)
> +#define MC13892_POWERMISC_GPO3EN			(1<<10)
> +#define MC13892_POWERMISC_GPO4EN			(1<<12)
> +#define MC13892_POWERMISC_PWGT1SPIEN		(1<<15)
> +#define MC13892_POWERMISC_PWGT2SPIEN		(1<<16)
> +#define MC13892_POWERMISC_GPO4ADINEN		(1<<21)
> +
> +#define MC13892_POWERMISC_PWGTSPI_M			(3 << 15)
> +
> +#define MC13892_USB1				50
> +#define MC13892_USB1_VUSBEN				(1<<3)
> +
> +static const int mc13892_vcoincell[] = {
> +	2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
> +	3200000, 3300000,
> +};
> +
> +static const int mc13892_sw1[] = {
> +	600000,   625000,  650000,  675000,  700000,  725000,
> +	750000,   775000,  800000,  825000,  850000,  875000,
> +	900000,   925000,  950000,  975000, 1000000, 1025000,
> +	1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
> +	1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
> +	1350000, 1375000
> +};
> +
> +static const int mc13892_sw[] = {
> +	600000,   625000,  650000,  675000,  700000,  725000,
> +	750000,   775000,  800000,  825000,  850000,  875000,
> +	900000,   925000,  950000,  975000, 1000000, 1025000,
> +	1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
> +	1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
> +	1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
> +	1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
> +	1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
> +	1800000, 1825000, 1850000, 1875000
> +};
> +
> +static const int mc13892_swbst[] = {
> +	5000000,
> +};
> +
> +static const int mc13892_viohi[] = {
> +	2775000,
> +};
> +
> +static const int mc13892_vpll[] = {
> +	1050000, 1250000, 1650000, 1800000,
> +};
> +
> +static const int mc13892_vdig[] = {
> +	1050000, 1250000, 1650000, 1800000,
> +};
> +
> +static const int mc13892_vsd[] = {
> +	1800000, 2000000, 2600000, 2700000,
> +	2800000, 2900000, 3000000, 3150000,
> +};
> +
> +static const int mc13892_vusb2[] = {
> +	2400000, 2600000, 2700000, 2775000,
> +};
> +
> +static const int mc13892_vvideo[] = {
> +	2500000, 2600000, 270000, 2775000,
> +};
> +
> +static const int mc13892_vaudio[] = {
> +	2300000, 2500000, 2775000, 3000000,
> +};
> +
> +static const int mc13892_vcam[] = {
> +	2500000, 2600000, 2750000, 3000000,
> +};
> +
> +static const int mc13892_vgen1[] = {
> +	1200000, 1500000, 2775000, 3150000,
> +};
> +
> +static const int mc13892_vgen2[] = {
> +	1200000, 1500000, 1600000, 1800000,
> +	2700000, 2800000, 3000000, 3150000,
> +};
> +
> +static const int mc13892_vgen3[] = {
> +	1800000, 2900000,
> +};
> +
> +static const int mc13892_vusb[] = {
> +	3300000,
> +};
> +
> +static const int mc13892_gpo[] = {
> +	2750000,
> +};
> +
> +static const int mc13892_pwgtdrv[] = {
> +	5000000,
> +};
> +
> +static struct regulator_ops mc13892_gpo_regulator_ops;
> +/* sw regulators need special care due to the "hi bit" */
> +static struct regulator_ops mc13892_sw_regulator_ops;
> +
> +
> +#define MC13892_FIXED_DEFINE(name, reg, voltages)\
> +	MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \
> +			mc13xxx_fixed_regulator_ops)
> +
> +#define MC13892_GPO_DEFINE(name, reg, voltages)		\
> +	MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \
> +			mc13892_gpo_regulator_ops)
> +
> +#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages)		\
> +	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
> +			mc13892_sw_regulator_ops)
> +
> +#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages)		\
> +	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
> +			mc13xxx_regulator_ops)
> +
> +static struct mc13xxx_regulator mc13892_regulators[] = {
> +	MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0,		\
> +			    mc13892_vcoincell),
> +	MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1),
> +	MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw),
> +	MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw),
> +	MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw),
> +	MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst),
> +	MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi),
> +	MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0,	\
> +			    mc13892_vpll),
> +	MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\
> +			    mc13892_vdig),
> +	MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1,	\
> +			    mc13892_vsd),
> +	MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0,	\
> +			    mc13892_vusb2),
> +	MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1,	\
> +			    mc13892_vvideo),
> +	MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1,	\
> +			    mc13892_vaudio),
> +	MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
> +			    mc13892_vcam),
> +	MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0,	\
> +			    mc13892_vgen1),
> +	MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0,	\
> +			    mc13892_vgen2),
> +	MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0,	\
> +			    mc13892_vgen3),
> +	MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb),
> +	MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo),
> +	MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo),
> +	MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo),
> +	MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo),
> +	MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv),
> +	MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv),
> +};
> +
> +int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
> +									u32 val)
> +{
> +	struct mc13xxx *mc13892 = priv->mc13xxx;
> +	int ret;
> +	u32 valread;
> +
> +	BUG_ON(val & ~mask);
> +
> +	ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
> +	if (ret)
> +		return ret;
> +
> +	/* Update the stored state for Power Gates. */
> +	priv->powermisc_pwgt_state =
> +				(priv->powermisc_pwgt_state & ~mask) | val;
> +	priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M;
> +
> +	/* Construct the new register value */
> +	valread = (valread & ~mask) | val;
> +	/* Overwrite the PWGTxEN with the stored version */
> +	valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
> +						priv->powermisc_pwgt_state;
> +
> +	return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
> +}
> +
> +static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
> +{
> +	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
> +	int id = rdev_get_id(rdev);
> +	int ret;
> +	u32 en_val = mc13892_regulators[id].enable_bit;
> +	u32 mask = mc13892_regulators[id].enable_bit;
> +
> +	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
> +
> +	/* Power Gate enable value is 0 */
> +	if (id == MC13892_PWGT1SPI ||
> +	    id == MC13892_PWGT2SPI)
> +		en_val = 0;
> +
> +	if (id == MC13892_GPO4)
> +		mask |= MC13892_POWERMISC_GPO4ADINEN;
> +
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13892_powermisc_rmw(priv, mask, en_val);
> +	mc13xxx_unlock(priv->mc13xxx);
> +
> +	return ret;
> +}
> +
> +static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
> +{
> +	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
> +	int id = rdev_get_id(rdev);
> +	int ret;
> +	u32 dis_val = 0;
> +
> +	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
> +
> +	/* Power Gate disable value is 1 */
> +	if (id == MC13892_PWGT1SPI ||
> +	    id == MC13892_PWGT2SPI)
> +		dis_val = mc13892_regulators[id].enable_bit;
> +
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
> +					dis_val);
> +	mc13xxx_unlock(priv->mc13xxx);
> +
> +	return ret;
> +}
> +
> +static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
> +{
> +	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
> +	int ret, id = rdev_get_id(rdev);
> +	unsigned int val;
> +
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
> +	mc13xxx_unlock(priv->mc13xxx);
> +
> +	if (ret)
> +		return ret;
> +
> +	/* Power Gates state is stored in powermisc_pwgt_state
> +	 * where the meaning of bits is negated */
> +	val = (val & ~MC13892_POWERMISC_PWGTSPI_M) |
> +	      (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M);
> +
> +	return (val & mc13892_regulators[id].enable_bit) != 0;
> +}
> +
> +
> +static struct regulator_ops mc13892_gpo_regulator_ops = {
> +	.enable = mc13892_gpo_regulator_enable,
> +	.disable = mc13892_gpo_regulator_disable,
> +	.is_enabled = mc13892_gpo_regulator_is_enabled,
> +	.list_voltage = mc13xxx_regulator_list_voltage,
> +	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
> +	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
> +};
> +
> +static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
> +{
> +	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
> +	int ret, id = rdev_get_id(rdev);
> +	unsigned int val, hi;
> +
> +	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
> +
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13xxx_reg_read(priv->mc13xxx,
> +				mc13892_regulators[id].vsel_reg, &val);
> +	mc13xxx_unlock(priv->mc13xxx);
> +	if (ret)
> +		return ret;
> +
> +	hi  = val & MC13892_SWITCHERS0_SWxHI;
> +	val = (val & mc13892_regulators[id].vsel_mask)
> +		>> mc13892_regulators[id].vsel_shift;
> +
> +	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
> +
> +	if (hi)
> +		val = (25000 * val) + 1100000;
> +	else
> +		val = (25000 * val) + 600000;
> +
> +	return val;
> +}
> +
> +static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
> +						int min_uV, int max_uV)
> +{
> +	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
> +	int hi, value, val, mask, id = rdev_get_id(rdev);
> +	int ret;
> +
> +	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
> +		__func__, id, min_uV, max_uV);
> +
> +	/* Find the best index */
> +	value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
> +	dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
> +	if (value < 0)
> +		return value;
> +
> +	value = mc13892_regulators[id].voltages[value];
> +
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13xxx_reg_read(priv->mc13xxx,
> +				mc13892_regulators[id].vsel_reg, &val);
> +	mc13xxx_unlock(priv->mc13xxx);
> +	if (ret)
> +		return ret;
> +
> +	hi  = val & MC13892_SWITCHERS0_SWxHI;
> +	if (value > 1375)
> +		hi = 1;
> +	if (value < 1100)
> +		hi = 0;
> +
> +	if (hi) {
> +		value = (value - 1100000) / 25000;
> +		value |= MC13892_SWITCHERS0_SWxHI;
> +	} else
> +		value = (value - 600000) / 25000;
> +
> +	mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
> +			mask,
> +			value << mc13892_regulators[id].vsel_shift);
> +	mc13xxx_unlock(priv->mc13xxx);
> +
> +	return ret;
> +}
> +
> +static struct regulator_ops mc13892_sw_regulator_ops = {
> +	.is_enabled = mc13xxx_sw_regulator_is_enabled,
> +	.list_voltage = mc13xxx_regulator_list_voltage,
> +	.set_voltage = mc13892_sw_regulator_set_voltage,
> +	.get_voltage = mc13892_sw_regulator_get_voltage,
> +};
> +
> +static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
> +{
> +	unsigned int en_val = 0;
> +	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
> +	int ret, id = rdev_get_id(rdev);
> +
> +	if (mode == REGULATOR_MODE_FAST)
> +		en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN;
> +
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg,
> +			MC13892_REGULATORMODE1_VCAMCONFIGEN,
> +			en_val);
> +	mc13xxx_unlock(priv->mc13xxx);
> +
> +	return ret;
> +}
> +
> +unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
> +{
> +	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
> +	int ret, id = rdev_get_id(rdev);
> +	unsigned int val;
> +
> +	mc13xxx_lock(priv->mc13xxx);
> +	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
> +	mc13xxx_unlock(priv->mc13xxx);
> +
> +	if (ret)
> +		return ret;
> +
> +	if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN)
> +		return REGULATOR_MODE_FAST;
> +
> +	return REGULATOR_MODE_NORMAL;
> +}
> +
> +
> +static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
> +{
> +	struct mc13xxx_regulator_priv *priv;
> +	struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
> +	struct mc13xxx_regulator_platform_data *pdata =
> +		dev_get_platdata(&pdev->dev);
> +	struct mc13xxx_regulator_init_data *init_data;
> +	int i, ret;
> +	u32 val;
> +
> +	priv = kzalloc(sizeof(*priv) +
> +			pdata->num_regulators * sizeof(priv->regulators[0]),
> +			GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->mc13xxx_regulators = mc13892_regulators;
> +	priv->mc13xxx = mc13892;
> +
> +	mc13xxx_lock(mc13892);
> +	ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val);
> +	mc13xxx_unlock(mc13892);
> +	if (ret)
> +		goto err_alloc;
err_alloc looks wrong

> +
> +	/* enable switch auto mode - ENGR00120510, ENGR00121057 */
> +	/* no doc with regs description means no way to know if */
> +	/* there's a better way to do it			*/
This is an unusual commenting style.  Please use

	/*
	 * enable switch auto mode ...
	 */

> +	if ((val & 0x0000FFFF) == 0x45d0) {
> +		mc13xxx_lock(mc13892);
> +		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
> +			MC13892_SWITCHERS4_SW1MODE_M |
> +			MC13892_SWITCHERS4_SW2MODE_M,
> +			MC13892_SWITCHERS4_SW1MODE_AUTO |
> +			MC13892_SWITCHERS4_SW2MODE_AUTO);
> +		mc13xxx_unlock(mc13892);
It should be possible to hold the lock for longer that a single mc13xxx
API call.  Your error handler just needs to unlock for that.

> +		if (ret)
> +			goto err_alloc;
> +
> +		mc13xxx_lock(mc13892);
> +		mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5,
> +			MC13892_SWITCHERS5_SW3MODE_M |
> +			MC13892_SWITCHERS5_SW4MODE_M,
> +			MC13892_SWITCHERS5_SW3MODE_AUTO |
> +			MC13892_SWITCHERS5_SW4MODE_AUTO);
> +		mc13xxx_unlock(mc13892);
> +		if (ret)
> +			goto err_alloc;
> +	}
> +
> +	mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
> +		= mc13892_vcam_set_mode;
> +	mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
> +		= mc13892_vcam_get_mode;
> +	for (i = 0; i < pdata->num_regulators; i++) {
> +		init_data = &pdata->regulators[i];
> +		priv->regulators[i] = regulator_register(
> +				&mc13892_regulators[init_data->id].desc,
> +				&pdev->dev, init_data->init_data, priv);
> +
> +		if (IS_ERR(priv->regulators[i])) {
> +			dev_err(&pdev->dev, "failed to register regulator %s\n",
> +				mc13892_regulators[i].desc.name);
> +			ret = PTR_ERR(priv->regulators[i]);
> +			goto err;
> +		}
> +	}
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	return 0;
> +err:
> +	while (--i >= 0)
> +		regulator_unregister(priv->regulators[i]);
> +
> +err_alloc:
> +	kfree(priv);
> +
> +	return ret;
> +}
> +
> +static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
> +{
> +	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
> +	struct mc13xxx_regulator_platform_data *pdata =
> +		dev_get_platdata(&pdev->dev);
> +	int i;
> +
> +	platform_set_drvdata(pdev, NULL);
> +
> +	for (i = 0; i < pdata->num_regulators; i++)
> +		regulator_unregister(priv->regulators[i]);
> +
> +	kfree(priv);
> +	return 0;
> +}
> +
> +static struct platform_driver mc13892_regulator_driver = {
> +	.driver	= {
> +		.name	= "mc13892-regulator",
> +		.owner	= THIS_MODULE,
> +	},
> +	.remove		= __devexit_p(mc13892_regulator_remove),
> +	.probe		= mc13892_regulator_probe,
If you ask me just use a single space before =, but there is no common
style visible in the kernel, so do as you prefer.
(The advantage of using a single space is that if later
.averylongmembername needs to be initialized you either have to fix
lines that are technically unrelated or the indention isn't uniform.)

Best regards
Uwe

> +};
> +
> +static int __init mc13892_regulator_init(void)
> +{
> +	return platform_driver_register(&mc13892_regulator_driver);
> +}
> +subsys_initcall(mc13892_regulator_init);
> +
> +static void __exit mc13892_regulator_exit(void)
> +{
> +	platform_driver_unregister(&mc13892_regulator_driver);
> +}
> +module_exit(mc13892_regulator_exit);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
> +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC");
> +MODULE_ALIAS("platform:mc13892-regulator");
> diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h
> new file mode 100644
> index 0000000..7df13e8
> --- /dev/null
> +++ b/include/linux/mfd/mc13892.h
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
> + *
> + * 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 __LINUX_MFD_MC13892_H
> +#define __LINUX_MFD_MC13892_H
> +#include <linux/mfd/mc13xxx.h>
> +
> +#define MC13892_SW1		0
> +#define MC13892_SW2		1
> +#define MC13892_SW3		2
> +#define MC13892_SW4		3
> +#define MC13892_SWBST	4
> +#define MC13892_VIOHI	5
> +#define MC13892_VPLL	6
> +#define MC13892_VDIG	7
> +#define MC13892_VSD	8
> +#define MC13892_VUSB2	9
> +#define MC13892_VVIDEO	10
> +#define MC13892_VAUDIO	11
> +#define MC13892_VCAM	12
> +#define MC13892_VGEN1	13
> +#define MC13892_VGEN2	14
> +#define MC13892_VGEN3	15
> +#define MC13892_VUSB	16
> +#define MC13892_GPO1	17
> +#define MC13892_GPO2	18
> +#define MC13892_GPO3	19
> +#define MC13892_GPO4	20
> +#define MC13892_PWGT1SPI	21
> +#define MC13892_PWGT2SPI	22
> +#define MC13892_VCOINCELL	23
> +
> +#endif
> -- 
> 1.7.0.4

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH] support PMIC mc13892
  2010-12-06  6:25 [PATCH] support PMIC mc13892 yong.shen at freescale.com
  2010-12-06  7:22 ` Uwe Kleine-König
@ 2010-12-06 10:40 ` David Jander
  2010-12-07  2:50   ` Yong Shen
  2010-12-06 10:55 ` Arnaud Patard (Rtp)
  2010-12-06 21:54 ` Marc Reilly
  3 siblings, 1 reply; 21+ messages in thread
From: David Jander @ 2010-12-06 10:40 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Yong,

On Mon, 6 Dec 2010 14:25:35 +0800 <yong.shen@freescale.com> wrote:
>[...]
> --- /dev/null
> +++ b/include/linux/mfd/mc13892.h
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
> + *
> + * 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 __LINUX_MFD_MC13892_H
> +#define __LINUX_MFD_MC13892_H
> +#include <linux/mfd/mc13xxx.h>
> +
> +#define MC13892_SW1		0
> +#define MC13892_SW2		1
> +#define MC13892_SW3		2
> +#define MC13892_SW4		3
> +#define MC13892_SWBST	4
> +#define MC13892_VIOHI	5
> +#define MC13892_VPLL	6
> +#define MC13892_VDIG	7
> +#define MC13892_VSD	8
> +#define MC13892_VUSB2	9
> +#define MC13892_VVIDEO	10
> +#define MC13892_VAUDIO	11
> +#define MC13892_VCAM	12
> +#define MC13892_VGEN1	13
> +#define MC13892_VGEN2	14
> +#define MC13892_VGEN3	15
> +#define MC13892_VUSB	16
> +#define MC13892_GPO1	17
> +#define MC13892_GPO2	18
> +#define MC13892_GPO3	19
> +#define MC13892_GPO4	20
> +#define MC13892_PWGT1SPI	21
> +#define MC13892_PWGT2SPI	22
> +#define MC13892_VCOINCELL	23
> +
> +#endif

I suppose these are needed outside the driver .c file? If so, can't these go in
linux/mfd/mc13xxx.h?
The platform-data struct is in there too, so why not put the corresponding
defines there also?
For other subsystems, those defines that are common are prefixed MC13XXX_ and
those that are individual, get MC13892_ or MC13783_. This makes it also easier
and less intrusive to add support for future chips in this series....

Best regards,

-- 
David Jander
Protonic Holland.

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

* [PATCH] support PMIC mc13892
  2010-12-06  6:25 [PATCH] support PMIC mc13892 yong.shen at freescale.com
  2010-12-06  7:22 ` Uwe Kleine-König
  2010-12-06 10:40 ` David Jander
@ 2010-12-06 10:55 ` Arnaud Patard (Rtp)
  2010-12-06 11:42   ` Alberto Panizzo
  2010-12-07  2:52   ` Yong Shen
  2010-12-06 21:54 ` Marc Reilly
  3 siblings, 2 replies; 21+ messages in thread
From: Arnaud Patard (Rtp) @ 2010-12-06 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

<yong.shen@freescale.com> writes:

Hi,

> From: Yong Shen <yong.shen@linaro.org>
>
> add support for mc13892, tested on mx51 babbage board

Will review/test it asap on my efikamx. thanks for working on this :)

>
> Signed-off-by: Yong Shen <yong.shen@linaro.org>
> ---
>  drivers/mfd/Kconfig                   |    4 +
>  drivers/regulator/Kconfig             |    8 +
>  drivers/regulator/Makefile            |    1 +
>  drivers/regulator/mc13892-regulator.c |  647 +++++++++++++++++++++++++++++++++
>  include/linux/mfd/mc13892.h           |   38 ++
>  5 files changed, 698 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/regulator/mc13892-regulator.c
>  create mode 100644 include/linux/mfd/mc13892.h

[...]

> +
> +static const int mc13892_vvideo[] = {
> +	2500000, 2600000, 270000, 2775000,
> +};

Should be :
static const int mc13892_vvideo[] = {
        270000, 2775000, 2500000, 2600000,
};

I've spotted this in my code some time ago. VVIDEO voltages are not
ascending order.


Arnaud

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

* [PATCH] support PMIC mc13892
  2010-12-06 10:55 ` Arnaud Patard (Rtp)
@ 2010-12-06 11:42   ` Alberto Panizzo
  2010-12-06 11:55     ` Arnaud Patard (Rtp)
  2010-12-07  2:52   ` Yong Shen
  1 sibling, 1 reply; 21+ messages in thread
From: Alberto Panizzo @ 2010-12-06 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

On lun, 2010-12-06 at 11:55 +0100, Arnaud Patard wrote:
> <yong.shen@freescale.com> writes:
> 
> Hi,
> 
> > From: Yong Shen <yong.shen@linaro.org>
> >
> > add support for mc13892, tested on mx51 babbage board
> 
> Will review/test it asap on my efikamx. thanks for working on this :)
> 
> >
> > Signed-off-by: Yong Shen <yong.shen@linaro.org>
> > ---
> >  drivers/mfd/Kconfig                   |    4 +
> >  drivers/regulator/Kconfig             |    8 +
> >  drivers/regulator/Makefile            |    1 +
> >  drivers/regulator/mc13892-regulator.c |  647 +++++++++++++++++++++++++++++++++
> >  include/linux/mfd/mc13892.h           |   38 ++
> >  5 files changed, 698 insertions(+), 0 deletions(-)
> >  create mode 100644 drivers/regulator/mc13892-regulator.c
> >  create mode 100644 include/linux/mfd/mc13892.h
> 
> [...]
> 
> > +
> > +static const int mc13892_vvideo[] = {
> > +	2500000, 2600000, 270000, 2775000,
> > +};
> 
> Should be :
> static const int mc13892_vvideo[] = {
>         270000, 2775000, 2500000, 2600000,
> };
> 
> I've spotted this in my code some time ago. VVIDEO voltages are not
> ascending order.

If this is true, also a private get_best_voltage_index have to be
developed for it.


-- 
Alberto!

        Be Persistent!
                - Greg Kroah-Hartman (FOSDEM 2010)

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

* [PATCH] support PMIC mc13892
  2010-12-06 11:42   ` Alberto Panizzo
@ 2010-12-06 11:55     ` Arnaud Patard (Rtp)
  2010-12-06 13:12       ` Alberto Panizzo
  0 siblings, 1 reply; 21+ messages in thread
From: Arnaud Patard (Rtp) @ 2010-12-06 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

Alberto Panizzo <maramaopercheseimorto@gmail.com> writes:

> On lun, 2010-12-06 at 11:55 +0100, Arnaud Patard wrote:
>> <yong.shen@freescale.com> writes:
>> 
>> Hi,
>> 
>> > From: Yong Shen <yong.shen@linaro.org>
>> >
>> > add support for mc13892, tested on mx51 babbage board
>> 
>> Will review/test it asap on my efikamx. thanks for working on this :)
>> 
>> >
>> > Signed-off-by: Yong Shen <yong.shen@linaro.org>
>> > ---
>> >  drivers/mfd/Kconfig                   |    4 +
>> >  drivers/regulator/Kconfig             |    8 +
>> >  drivers/regulator/Makefile            |    1 +
>> >  drivers/regulator/mc13892-regulator.c |  647 +++++++++++++++++++++++++++++++++
>> >  include/linux/mfd/mc13892.h           |   38 ++
>> >  5 files changed, 698 insertions(+), 0 deletions(-)
>> >  create mode 100644 drivers/regulator/mc13892-regulator.c
>> >  create mode 100644 include/linux/mfd/mc13892.h
>> 
>> [...]
>> 
>> > +
>> > +static const int mc13892_vvideo[] = {
>> > +	2500000, 2600000, 270000, 2775000,
>> > +};
>> 
>> Should be :
>> static const int mc13892_vvideo[] = {
>>         270000, 2775000, 2500000, 2600000,
>> };
>> 
>> I've spotted this in my code some time ago. VVIDEO voltages are not
>> ascending order.
>
> If this is true, also a private get_best_voltage_index have to be
> developed for it.

It _is_ true. That's sure. About get_best_voltage_index, it's working
fine with it as it doesn't care about voltage order afaik. See the
comment in the get_best_voltage_index() function.


Arnaud

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

* [PATCH] support PMIC mc13892
  2010-12-06 11:55     ` Arnaud Patard (Rtp)
@ 2010-12-06 13:12       ` Alberto Panizzo
  0 siblings, 0 replies; 21+ messages in thread
From: Alberto Panizzo @ 2010-12-06 13:12 UTC (permalink / raw)
  To: linux-arm-kernel

On lun, 2010-12-06 at 12:55 +0100, Arnaud Patard wrote:
> Alberto Panizzo <maramaopercheseimorto@gmail.com> writes:
> 
> > On lun, 2010-12-06 at 11:55 +0100, Arnaud Patard wrote:
> >> <yong.shen@freescale.com> writes:
> >> 
> >> Hi,
> >> 
> >> > From: Yong Shen <yong.shen@linaro.org>
> >> >
> >> > add support for mc13892, tested on mx51 babbage board
> >> 
> >> Will review/test it asap on my efikamx. thanks for working on this :)
> >> 
> >> >
> >> > Signed-off-by: Yong Shen <yong.shen@linaro.org>
> >> > ---
> >> >  drivers/mfd/Kconfig                   |    4 +
> >> >  drivers/regulator/Kconfig             |    8 +
> >> >  drivers/regulator/Makefile            |    1 +
> >> >  drivers/regulator/mc13892-regulator.c |  647 +++++++++++++++++++++++++++++++++
> >> >  include/linux/mfd/mc13892.h           |   38 ++
> >> >  5 files changed, 698 insertions(+), 0 deletions(-)
> >> >  create mode 100644 drivers/regulator/mc13892-regulator.c
> >> >  create mode 100644 include/linux/mfd/mc13892.h
> >> 
> >> [...]
> >> 
> >> > +
> >> > +static const int mc13892_vvideo[] = {
> >> > +	2500000, 2600000, 270000, 2775000,
> >> > +};
> >> 
> >> Should be :
> >> static const int mc13892_vvideo[] = {
> >>         270000, 2775000, 2500000, 2600000,
> >> };
> >> 
> >> I've spotted this in my code some time ago. VVIDEO voltages are not
> >> ascending order.
> >
> > If this is true, also a private get_best_voltage_index have to be
> > developed for it.
> 
> It _is_ true. That's sure. About get_best_voltage_index, it's working
> fine with it as it doesn't care about voltage order afaik. See the
> comment in the get_best_voltage_index() function.

Yes, I'm getting wired today.
get_best_voltage_index find the minimum value within the array that is
>= min_uV.


-- 
Alberto!

        Be Persistent!
                - Greg Kroah-Hartman (FOSDEM 2010)

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

* [PATCH] support PMIC mc13892
  2010-12-06  6:25 [PATCH] support PMIC mc13892 yong.shen at freescale.com
                   ` (2 preceding siblings ...)
  2010-12-06 10:55 ` Arnaud Patard (Rtp)
@ 2010-12-06 21:54 ` Marc Reilly
  2010-12-07  7:14   ` [PATCH] Added i2c support for mc13xxx-core Marc Reilly
                     ` (2 more replies)
  3 siblings, 3 replies; 21+ messages in thread
From: Marc Reilly @ 2010-12-06 21:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Monday, December 06, 2010 05:25:35 pm yong.shen at freescale.com wrote:
> From: Yong Shen <yong.shen@linaro.org>
> 
> add support for mc13892, tested on mx51 babbage board
> 

I'd love to test this but our 13892 is connected via I2C, so I guess I'll need 
to modify it a bit to add I2C support. (I don't think the 13873 has I2C 
connectivity though).

I'll let you know how it goes.

Cheers
Marc

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

* [PATCH] support PMIC mc13892
  2010-12-06  7:22 ` Uwe Kleine-König
@ 2010-12-07  2:41   ` Yong Shen
  2010-12-07  7:57   ` Yong Shen
  1 sibling, 0 replies; 21+ messages in thread
From: Yong Shen @ 2010-12-07  2:41 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

2010/12/6 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> Hello,
>
> On Mon, Dec 06, 2010 at 02:25:35PM +0800, yong.shen at freescale.com wrote:
>> From: Yong Shen <yong.shen@linaro.org>
>>
>> add support for mc13892, tested on mx51 babbage board
>>
>> Signed-off-by: Yong Shen <yong.shen@linaro.org>
>> ---
>> ?drivers/mfd/Kconfig ? ? ? ? ? ? ? ? ? | ? ?4 +
>> ?drivers/regulator/Kconfig ? ? ? ? ? ? | ? ?8 +
>> ?drivers/regulator/Makefile ? ? ? ? ? ?| ? ?1 +
>> ?drivers/regulator/mc13892-regulator.c | ?647 +++++++++++++++++++++++++++++++++
>> ?include/linux/mfd/mc13892.h ? ? ? ? ? | ? 38 ++
>> ?5 files changed, 698 insertions(+), 0 deletions(-)
>> ?create mode 100644 drivers/regulator/mc13892-regulator.c
>> ?create mode 100644 include/linux/mfd/mc13892.h
>>
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 3a1493b..7659af9 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -427,11 +427,15 @@ config MFD_PCF50633
>> ?config MFD_MC13783
>> ? ? ? tristate
>>
>> +config MFD_MC13892
>> + ? ? tristate
>> +
> This is not needed, MFD_MC13783 only exists because when MFD_MC13XXX was
> introduced some drivers still depended on MFD_MC13783. ?As mc13xxx.[ch]
> provided enough compatibility cruft MFD_MC13XXX just selected MFD_MC13783.
My original thought was to keep align with previous structure. In the
case you mentioned, I will remove it.
>
>> ?config MFD_MC13XXX
>> ? ? ? tristate "Support Freescale MC13783 and MC13892"
>> ? ? ? depends on SPI_MASTER
>> ? ? ? select MFD_CORE
>> ? ? ? select MFD_MC13783
>> + ? ? select MFD_MC13892
>> ? ? ? help
>> ? ? ? ? Support for the Freescale (Atlas) PMIC and audio CODECs
>> ? ? ? ? MC13783 and MC13892.
>> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
>> index 6e54253..7f7bc22 100644
>> --- a/drivers/regulator/Kconfig
>> +++ b/drivers/regulator/Kconfig
>> @@ -197,6 +197,14 @@ config REGULATOR_MC13783
>> ? ? ? ? Say y here to support the regulators found on the Freescale MC13783
>> ? ? ? ? PMIC.
>>
>> +config REGULATOR_MC13892
>> + ? ? tristate "Support regulators on Freescale MC13892 PMIC"
>> + ? ? depends on MFD_MC13892
>> + ? ? select REGULATOR_MC13XXX_CORE
>> + ? ? help
>> + ? ? ? Say y here to support the regulators found on the Freescale MC13892
>> + ? ? ? PMIC.
>> +
>> ?config REGULATOR_AB3100
>> ? ? ? tristate "ST-Ericsson AB3100 Regulator functions"
>> ? ? ? depends on AB3100_CORE
>> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
>> index 11876be..3107480 100644
>> --- a/drivers/regulator/Makefile
>> +++ b/drivers/regulator/Makefile
>> @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X) ? ? ?+= da903x.o
>> ?obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
>> ?obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
>> ?obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
>> +obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
>> ?obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += ?mc13xxx-regulator-core.o
>> ?obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
>>
>> diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
>> new file mode 100644
>> index 0000000..6e613d4
>> --- /dev/null
>> +++ b/drivers/regulator/mc13892-regulator.c
>> @@ -0,0 +1,647 @@
>> +/*
>> + * Regulator Driver for Freescale MC13892 PMIC
>> + *
>> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
>> + *
>> + * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org>
>> + *
>> + * 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/mfd/mc13892.h>
>> +#include <linux/regulator/machine.h>
>> +#include <linux/regulator/driver.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/kernel.h>
>> +#include <linux/slab.h>
>> +#include <linux/init.h>
>> +#include <linux/err.h>
>> +#include "mc13xxx.h"
> shouldn't that be
>
> ? ? ? ?#include <linux/mfd/mc13xxx.h>
>
> ?
>> +
>> +#define MC13892_REVISION ? ? ? ? ? ? ? ? ? ? ? ? ? ? 7
>> +
>> +#define MC13892_POWERCTL0 ? ? ? ? ? ? ? ? ? ? ? ? ? ?13
>> +#define MC13892_POWERCTL0_USEROFFSPI ? ? ? ? 3
>> +#define MC13892_POWERCTL0_VCOINCELLVSEL ? ? ? ? ? ? ?20
>> +#define MC13892_POWERCTL0_VCOINCELLVSEL_M ? ? ? ? ? ?(7<<20)
>> +#define MC13892_POWERCTL0_VCOINCELLEN ? ? ? ? ? ? ? ?(1<<23)
>> +
>> +#define MC13892_SWITCHERS0_SWxHI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +
>> +#define MC13892_SWITCHERS0 ? ? ? ? ? ? ? ? ? ? ? ? ? 24
>> +#define MC13892_SWITCHERS0_SW1VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS0_SW1VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS0_SW1HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS0_SW1EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS1 ? ? ? ? ? ? ? ? ? ? ? ? ? 25
>> +#define MC13892_SWITCHERS1_SW2VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS1_SW2VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS1_SW2HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS1_SW2EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS2 ? ? ? ? ? ? ? ? ? ? ? ? ? 26
>> +#define MC13892_SWITCHERS2_SW3VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS2_SW3VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS2_SW3HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS2_SW3EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS3 ? ? ? ? ? ? ? ? ? ? ? ? ? 27
>> +#define MC13892_SWITCHERS3_SW4VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS3_SW4VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS3_SW4HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS3_SW4EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS4 ? ? ? ? ? ? ? ? ? ? ? ? ? 28
>> +#define MC13892_SWITCHERS4_SW1MODE ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS4_SW1MODE_AUTO ? ? ? ? ? ? ?(8<<0)
>> +#define MC13892_SWITCHERS4_SW1MODE_M ? ? ? ? (0xf<<0)
>> +#define MC13892_SWITCHERS4_SW2MODE ? ? ? ? ? ? ? ? ? 10
>> +#define MC13892_SWITCHERS4_SW2MODE_AUTO ? ? ? ? ? ? ?(8<<10)
>> +#define MC13892_SWITCHERS4_SW2MODE_M ? ? ? ? (0xf<<10)
>> +
>> +#define MC13892_SWITCHERS5 ? ? ? ? ? ? ? ? ? ? ? ? ? 29
>> +#define MC13892_SWITCHERS5_SW3MODE ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS5_SW3MODE_AUTO ? ? ? ? ? ? ?(8<<0)
>> +#define MC13892_SWITCHERS5_SW3MODE_M ? ? ? ? (0xf<<0)
>> +#define MC13892_SWITCHERS5_SW4MODE ? ? ? ? ? ? ? ? ? 8
>> +#define MC13892_SWITCHERS5_SW4MODE_AUTO ? ? ? ? ? ? ?(8<<8)
>> +#define MC13892_SWITCHERS5_SW4MODE_M ? ? ? ? (0xf<<8)
>> +#define MC13892_SWITCHERS5_SWBSTEN ? ? ? ? ? ? ? ? ? (1<<20)
>> +
>> +
>> +#define MC13892_REGULATORSETTING0 ? ? ? ? ? ? ? ? ? ?30
>> +#define MC13892_REGULATORSETTING0_VGEN1VSEL ? ? ? ? ?0
>> +#define MC13892_REGULATORSETTING0_VDIGVSEL ? ? ? ? ? 4
>> +#define MC13892_REGULATORSETTING0_VGEN2VSEL ? ? ? ? ?6
>> +#define MC13892_REGULATORSETTING0_VPLLVSEL ? ? ? ? ? 9
>> +#define MC13892_REGULATORSETTING0_VUSB2VSEL ? ? ? ? ?11
>> +#define MC13892_REGULATORSETTING0_VGEN3VSEL ? ? ? ? ?14
>> +#define MC13892_REGULATORSETTING0_VCAMVSEL ? ? ? ? ? 16
>> +
>> +#define MC13892_REGULATORSETTING0_VGEN1VSEL_M ? ? ? ?(3<<0)
>> +#define MC13892_REGULATORSETTING0_VDIGVSEL_M (3<<4)
>> +#define MC13892_REGULATORSETTING0_VGEN2VSEL_M ? ? ? ?(7<<6)
>> +#define MC13892_REGULATORSETTING0_VPLLVSEL_M (3<<9)
>> +#define MC13892_REGULATORSETTING0_VUSB2VSEL_M ? ? ? ?(3<<11)
>> +#define MC13892_REGULATORSETTING0_VGEN3VSEL_M ? ? ? ?(1<<14)
>> +#define MC13892_REGULATORSETTING0_VCAMVSEL_M (3<<16)
>> +
>> +#define MC13892_REGULATORSETTING1 ? ? ? ? ? ? ? ? ? ?31
>> +#define MC13892_REGULATORSETTING1_VVIDEOVSEL 2
>> +#define MC13892_REGULATORSETTING1_VAUDIOVSEL 4
>> +#define MC13892_REGULATORSETTING1_VSDVSEL ? ? ? ? ? ?6
>> +
>> +#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M ? ? ? (3<<2)
>> +#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M ? ? ? (3<<4)
>> +#define MC13892_REGULATORSETTING1_VSDVSEL_M ? ? ? ? ?(7<<6)
>> +
>> +#define MC13892_REGULATORMODE0 ? ? ? ? ? ? ? ? ? ? ? 32
>> +#define MC13892_REGULATORMODE0_VGEN1EN ? ? ? ? ? ? ? (1<<0)
>> +#define MC13892_REGULATORMODE0_VGEN1STDBY ? ? ? ? ? ?(1<<1)
>> +#define MC13892_REGULATORMODE0_VGEN1MODE ? ? ? ? ? ? (1<<2)
>> +#define MC13892_REGULATORMODE0_VIOHIEN ? ? ? ? ? ? ? (1<<3)
>> +#define MC13892_REGULATORMODE0_VIOHISTDBY ? ? ? ? ? ?(1<<4)
>> +#define MC13892_REGULATORMODE0_VIOHIMODE ? ? ? ? ? ? (1<<5)
>> +#define MC13892_REGULATORMODE0_VDIGEN ? ? ? ? ? ? ? ?(1<<9)
>> +#define MC13892_REGULATORMODE0_VDIGSTDBY ? ? ? ? ? ? (1<<10)
>> +#define MC13892_REGULATORMODE0_VDIGMODE ? ? ? ? ? ? ?(1<<11)
>> +#define MC13892_REGULATORMODE0_VGEN2EN ? ? ? ? ? ? ? (1<<12)
>> +#define MC13892_REGULATORMODE0_VGEN2STDBY ? ? ? ? ? ?(1<<13)
>> +#define MC13892_REGULATORMODE0_VGEN2MODE ? ? ? ? ? ? (1<<14)
>> +#define MC13892_REGULATORMODE0_VPLLEN ? ? ? ? ? ? ? ?(1<<15)
>> +#define MC13892_REGULATORMODE0_VPLLSTDBY ? ? ? ? ? ? (1<<16)
>> +#define MC13892_REGULATORMODE0_VPLLMODE ? ? ? ? ? ? ?(1<<17)
>> +#define MC13892_REGULATORMODE0_VUSB2EN ? ? ? ? ? ? ? (1<<18)
>> +#define MC13892_REGULATORMODE0_VUSB2STDBY ? ? ? ? ? ?(1<<19)
>> +#define MC13892_REGULATORMODE0_VUSB2MODE ? ? ? ? ? ? (1<<20)
>> +
>> +#define MC13892_REGULATORMODE1 ? ? ? ? ? ? ? ? ? ? ? 33
>> +#define MC13892_REGULATORMODE1_VGEN3EN ? ? ? ? ? ? ? (1<<0)
>> +#define MC13892_REGULATORMODE1_VGEN3STDBY ? ? ? ? ? ?(1<<1)
>> +#define MC13892_REGULATORMODE1_VGEN3MODE ? ? ? ? ? ? (1<<2)
>> +#define MC13892_REGULATORMODE1_VCAMEN ? ? ? ? ? ? ? ?(1<<6)
>> +#define MC13892_REGULATORMODE1_VCAMSTDBY ? ? ? ? ? ? (1<<7)
>> +#define MC13892_REGULATORMODE1_VCAMMODE ? ? ? ? ? ? ?(1<<8)
>> +#define MC13892_REGULATORMODE1_VCAMCONFIGEN ? ? ? ? ?(1<<9)
>> +#define MC13892_REGULATORMODE1_VVIDEOEN ? ? ? ? ? ? ?(1<<12)
>> +#define MC13892_REGULATORMODE1_VVIDEOSTDBY ? ? ? ? ? (1<<13)
>> +#define MC13892_REGULATORMODE1_VVIDEOMODE ? ? ? ? ? ?(1<<14)
>> +#define MC13892_REGULATORMODE1_VAUDIOEN ? ? ? ? ? ? ?(1<<15)
>> +#define MC13892_REGULATORMODE1_VAUDIOSTDBY ? ? ? ? ? (1<<16)
>> +#define MC13892_REGULATORMODE1_VAUDIOMODE ? ? ? ? ? ?(1<<17)
>> +#define MC13892_REGULATORMODE1_VSDEN ? ? ? ? (1<<18)
>> +#define MC13892_REGULATORMODE1_VSDSTDBY ? ? ? ? ? ? ?(1<<19)
>> +#define MC13892_REGULATORMODE1_VSDMODE ? ? ? ? ? ? ? (1<<20)
>> +
>> +#define MC13892_POWERMISC ? ? ? ? ? ? ? ? ? ? ? ? ? ?34
>> +#define MC13892_POWERMISC_GPO1EN ? ? ? ? ? ? ? ? ? ? (1<<6)
>> +#define MC13892_POWERMISC_GPO2EN ? ? ? ? ? ? ? ? ? ? (1<<8)
>> +#define MC13892_POWERMISC_GPO3EN ? ? ? ? ? ? ? ? ? ? (1<<10)
>> +#define MC13892_POWERMISC_GPO4EN ? ? ? ? ? ? ? ? ? ? (1<<12)
>> +#define MC13892_POWERMISC_PWGT1SPIEN ? ? ? ? (1<<15)
>> +#define MC13892_POWERMISC_PWGT2SPIEN ? ? ? ? (1<<16)
>> +#define MC13892_POWERMISC_GPO4ADINEN ? ? ? ? (1<<21)
>> +
>> +#define MC13892_POWERMISC_PWGTSPI_M ? ? ? ? ? ? ? ? ?(3 << 15)
>> +
>> +#define MC13892_USB1 ? ? ? ? ? ? ? ? ? ? ? ? 50
>> +#define MC13892_USB1_VUSBEN ? ? ? ? ? ? ? ? ? ? ? ? ?(1<<3)
>> +
>> +static const int mc13892_vcoincell[] = {
>> + ? ? 2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
>> + ? ? 3200000, 3300000,
>> +};
>> +
>> +static const int mc13892_sw1[] = {
>> + ? ? 600000, ? 625000, ?650000, ?675000, ?700000, ?725000,
>> + ? ? 750000, ? 775000, ?800000, ?825000, ?850000, ?875000,
>> + ? ? 900000, ? 925000, ?950000, ?975000, 1000000, 1025000,
>> + ? ? 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
>> + ? ? 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
>> + ? ? 1350000, 1375000
>> +};
>> +
>> +static const int mc13892_sw[] = {
>> + ? ? 600000, ? 625000, ?650000, ?675000, ?700000, ?725000,
>> + ? ? 750000, ? 775000, ?800000, ?825000, ?850000, ?875000,
>> + ? ? 900000, ? 925000, ?950000, ?975000, 1000000, 1025000,
>> + ? ? 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
>> + ? ? 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
>> + ? ? 1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
>> + ? ? 1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
>> + ? ? 1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
>> + ? ? 1800000, 1825000, 1850000, 1875000
>> +};
>> +
>> +static const int mc13892_swbst[] = {
>> + ? ? 5000000,
>> +};
>> +
>> +static const int mc13892_viohi[] = {
>> + ? ? 2775000,
>> +};
>> +
>> +static const int mc13892_vpll[] = {
>> + ? ? 1050000, 1250000, 1650000, 1800000,
>> +};
>> +
>> +static const int mc13892_vdig[] = {
>> + ? ? 1050000, 1250000, 1650000, 1800000,
>> +};
>> +
>> +static const int mc13892_vsd[] = {
>> + ? ? 1800000, 2000000, 2600000, 2700000,
>> + ? ? 2800000, 2900000, 3000000, 3150000,
>> +};
>> +
>> +static const int mc13892_vusb2[] = {
>> + ? ? 2400000, 2600000, 2700000, 2775000,
>> +};
>> +
>> +static const int mc13892_vvideo[] = {
>> + ? ? 2500000, 2600000, 270000, 2775000,
>> +};
>> +
>> +static const int mc13892_vaudio[] = {
>> + ? ? 2300000, 2500000, 2775000, 3000000,
>> +};
>> +
>> +static const int mc13892_vcam[] = {
>> + ? ? 2500000, 2600000, 2750000, 3000000,
>> +};
>> +
>> +static const int mc13892_vgen1[] = {
>> + ? ? 1200000, 1500000, 2775000, 3150000,
>> +};
>> +
>> +static const int mc13892_vgen2[] = {
>> + ? ? 1200000, 1500000, 1600000, 1800000,
>> + ? ? 2700000, 2800000, 3000000, 3150000,
>> +};
>> +
>> +static const int mc13892_vgen3[] = {
>> + ? ? 1800000, 2900000,
>> +};
>> +
>> +static const int mc13892_vusb[] = {
>> + ? ? 3300000,
>> +};
>> +
>> +static const int mc13892_gpo[] = {
>> + ? ? 2750000,
>> +};
>> +
>> +static const int mc13892_pwgtdrv[] = {
>> + ? ? 5000000,
>> +};
>> +
>> +static struct regulator_ops mc13892_gpo_regulator_ops;
>> +/* sw regulators need special care due to the "hi bit" */
>> +static struct regulator_ops mc13892_sw_regulator_ops;
>> +
>> +
>> +#define MC13892_FIXED_DEFINE(name, reg, voltages)\
>> + ? ? MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13xxx_fixed_regulator_ops)
>> +
>> +#define MC13892_GPO_DEFINE(name, reg, voltages) ? ? ? ? ? ? ?\
>> + ? ? MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13892_gpo_regulator_ops)
>> +
>> +#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages) ? ? ? ? ? ? \
>> + ? ? MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13892_sw_regulator_ops)
>> +
>> +#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages) ? ? ? ? ? \
>> + ? ? MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13xxx_regulator_ops)
>> +
>> +static struct mc13xxx_regulator mc13892_regulators[] = {
>> + ? ? MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, ? ? ? ? ? ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vcoincell),
>> + ? ? MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1),
>> + ? ? MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw),
>> + ? ? MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw),
>> + ? ? MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw),
>> + ? ? MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst),
>> + ? ? MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi),
>> + ? ? MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0, ? ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vpll),
>> + ? ? MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, ? ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vdig),
>> + ? ? MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1, ? ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vsd),
>> + ? ? MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vusb2),
>> + ? ? MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1, ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vvideo),
>> + ? ? MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1, ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vaudio),
>> + ? ? MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vcam),
>> + ? ? MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vgen1),
>> + ? ? MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vgen2),
>> + ? ? MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vgen3),
>> + ? ? MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb),
>> + ? ? MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv),
>> + ? ? MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv),
>> +};
>> +
>> +int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 val)
>> +{
>> + ? ? struct mc13xxx *mc13892 = priv->mc13xxx;
>> + ? ? int ret;
>> + ? ? u32 valread;
>> +
>> + ? ? BUG_ON(val & ~mask);
>> +
>> + ? ? ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? /* Update the stored state for Power Gates. */
>> + ? ? priv->powermisc_pwgt_state =
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (priv->powermisc_pwgt_state & ~mask) | val;
>> + ? ? priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M;
>> +
>> + ? ? /* Construct the new register value */
>> + ? ? valread = (valread & ~mask) | val;
>> + ? ? /* Overwrite the PWGTxEN with the stored version */
>> + ? ? valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? priv->powermisc_pwgt_state;
>> +
>> + ? ? return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
>> +}
>> +
>> +static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int id = rdev_get_id(rdev);
>> + ? ? int ret;
>> + ? ? u32 en_val = mc13892_regulators[id].enable_bit;
>> + ? ? u32 mask = mc13892_regulators[id].enable_bit;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
>> +
>> + ? ? /* Power Gate enable value is 0 */
>> + ? ? if (id == MC13892_PWGT1SPI ||
>> + ? ? ? ? id == MC13892_PWGT2SPI)
>> + ? ? ? ? ? ? en_val = 0;
>> +
>> + ? ? if (id == MC13892_GPO4)
>> + ? ? ? ? ? ? mask |= MC13892_POWERMISC_GPO4ADINEN;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13892_powermisc_rmw(priv, mask, en_val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int id = rdev_get_id(rdev);
>> + ? ? int ret;
>> + ? ? u32 dis_val = 0;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
>> +
>> + ? ? /* Power Gate disable value is 1 */
>> + ? ? if (id == MC13892_PWGT1SPI ||
>> + ? ? ? ? id == MC13892_PWGT2SPI)
>> + ? ? ? ? ? ? dis_val = mc13892_regulators[id].enable_bit;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dis_val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> + ? ? unsigned int val;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? /* Power Gates state is stored in powermisc_pwgt_state
>> + ? ? ?* where the meaning of bits is negated */
>> + ? ? val = (val & ~MC13892_POWERMISC_PWGTSPI_M) |
>> + ? ? ? ? ? (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M);
>> +
>> + ? ? return (val & mc13892_regulators[id].enable_bit) != 0;
>> +}
>> +
>> +
>> +static struct regulator_ops mc13892_gpo_regulator_ops = {
>> + ? ? .enable = mc13892_gpo_regulator_enable,
>> + ? ? .disable = mc13892_gpo_regulator_disable,
>> + ? ? .is_enabled = mc13892_gpo_regulator_is_enabled,
>> + ? ? .list_voltage = mc13xxx_regulator_list_voltage,
>> + ? ? .set_voltage = mc13xxx_fixed_regulator_set_voltage,
>> + ? ? .get_voltage = mc13xxx_fixed_regulator_get_voltage,
>> +};
>> +
>> +static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> + ? ? unsigned int val, hi;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13892_regulators[id].vsel_reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? hi ?= val & MC13892_SWITCHERS0_SWxHI;
>> + ? ? val = (val & mc13892_regulators[id].vsel_mask)
>> + ? ? ? ? ? ? >> mc13892_regulators[id].vsel_shift;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
>> +
>> + ? ? if (hi)
>> + ? ? ? ? ? ? val = (25000 * val) + 1100000;
>> + ? ? else
>> + ? ? ? ? ? ? val = (25000 * val) + 600000;
>> +
>> + ? ? return val;
>> +}
>> +
>> +static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int min_uV, int max_uV)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int hi, value, val, mask, id = rdev_get_id(rdev);
>> + ? ? int ret;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
>> + ? ? ? ? ? ? __func__, id, min_uV, max_uV);
>> +
>> + ? ? /* Find the best index */
>> + ? ? value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
>> + ? ? if (value < 0)
>> + ? ? ? ? ? ? return value;
>> +
>> + ? ? value = mc13892_regulators[id].voltages[value];
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13892_regulators[id].vsel_reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? hi ?= val & MC13892_SWITCHERS0_SWxHI;
>> + ? ? if (value > 1375)
>> + ? ? ? ? ? ? hi = 1;
>> + ? ? if (value < 1100)
>> + ? ? ? ? ? ? hi = 0;
>> +
>> + ? ? if (hi) {
>> + ? ? ? ? ? ? value = (value - 1100000) / 25000;
>> + ? ? ? ? ? ? value |= MC13892_SWITCHERS0_SWxHI;
>> + ? ? } else
>> + ? ? ? ? ? ? value = (value - 600000) / 25000;
>> +
>> + ? ? mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
>> + ? ? ? ? ? ? ? ? ? ? mask,
>> + ? ? ? ? ? ? ? ? ? ? value << mc13892_regulators[id].vsel_shift);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static struct regulator_ops mc13892_sw_regulator_ops = {
>> + ? ? .is_enabled = mc13xxx_sw_regulator_is_enabled,
>> + ? ? .list_voltage = mc13xxx_regulator_list_voltage,
>> + ? ? .set_voltage = mc13892_sw_regulator_set_voltage,
>> + ? ? .get_voltage = mc13892_sw_regulator_get_voltage,
>> +};
>> +
>> +static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
>> +{
>> + ? ? unsigned int en_val = 0;
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> +
>> + ? ? if (mode == REGULATOR_MODE_FAST)
>> + ? ? ? ? ? ? en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_REGULATORMODE1_VCAMCONFIGEN,
>> + ? ? ? ? ? ? ? ? ? ? en_val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> + ? ? unsigned int val;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN)
>> + ? ? ? ? ? ? return REGULATOR_MODE_FAST;
>> +
>> + ? ? return REGULATOR_MODE_NORMAL;
>> +}
>> +
>> +
>> +static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv;
>> + ? ? struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
>> + ? ? struct mc13xxx_regulator_platform_data *pdata =
>> + ? ? ? ? ? ? dev_get_platdata(&pdev->dev);
>> + ? ? struct mc13xxx_regulator_init_data *init_data;
>> + ? ? int i, ret;
>> + ? ? u32 val;
>> +
>> + ? ? priv = kzalloc(sizeof(*priv) +
>> + ? ? ? ? ? ? ? ? ? ? pdata->num_regulators * sizeof(priv->regulators[0]),
>> + ? ? ? ? ? ? ? ? ? ? GFP_KERNEL);
>> + ? ? if (!priv)
>> + ? ? ? ? ? ? return -ENOMEM;
>> +
>> + ? ? priv->mc13xxx_regulators = mc13892_regulators;
>> + ? ? priv->mc13xxx = mc13892;
>> +
>> + ? ? mc13xxx_lock(mc13892);
>> + ? ? ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val);
>> + ? ? mc13xxx_unlock(mc13892);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? goto err_alloc;
> err_alloc looks wrong
>
>> +
>> + ? ? /* enable switch auto mode - ENGR00120510, ENGR00121057 */
>> + ? ? /* no doc with regs description means no way to know if */
>> + ? ? /* there's a better way to do it ? ? ? ? ? ? ? ? ? ? ? ?*/
> This is an unusual commenting style. ?Please use
True. In fact, I am going to remove ENGR*** stuff, cause they are only
meaningful inside freescale.
>
> ? ? ? ?/*
> ? ? ? ? * enable switch auto mode ...
> ? ? ? ? */
>
>> + ? ? if ((val & 0x0000FFFF) == 0x45d0) {
>> + ? ? ? ? ? ? mc13xxx_lock(mc13892);
>> + ? ? ? ? ? ? ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW1MODE_M |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW2MODE_M,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW1MODE_AUTO |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW2MODE_AUTO);
>> + ? ? ? ? ? ? mc13xxx_unlock(mc13892);
> It should be possible to hold the lock for longer that a single mc13xxx
> API call. ?Your error handler just needs to unlock for that.
Agreed.
>
>> + ? ? ? ? ? ? if (ret)
>> + ? ? ? ? ? ? ? ? ? ? goto err_alloc;
>> +
>> + ? ? ? ? ? ? mc13xxx_lock(mc13892);
>> + ? ? ? ? ? ? mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW3MODE_M |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW4MODE_M,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW3MODE_AUTO |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW4MODE_AUTO);
>> + ? ? ? ? ? ? mc13xxx_unlock(mc13892);
>> + ? ? ? ? ? ? if (ret)
>> + ? ? ? ? ? ? ? ? ? ? goto err_alloc;
>> + ? ? }
>> +
>> + ? ? mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
>> + ? ? ? ? ? ? = mc13892_vcam_set_mode;
>> + ? ? mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
>> + ? ? ? ? ? ? = mc13892_vcam_get_mode;
>> + ? ? for (i = 0; i < pdata->num_regulators; i++) {
>> + ? ? ? ? ? ? init_data = &pdata->regulators[i];
>> + ? ? ? ? ? ? priv->regulators[i] = regulator_register(
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? &mc13892_regulators[init_data->id].desc,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? &pdev->dev, init_data->init_data, priv);
>> +
>> + ? ? ? ? ? ? if (IS_ERR(priv->regulators[i])) {
>> + ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to register regulator %s\n",
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13892_regulators[i].desc.name);
>> + ? ? ? ? ? ? ? ? ? ? ret = PTR_ERR(priv->regulators[i]);
>> + ? ? ? ? ? ? ? ? ? ? goto err;
>> + ? ? ? ? ? ? }
>> + ? ? }
>> +
>> + ? ? platform_set_drvdata(pdev, priv);
>> +
>> + ? ? return 0;
>> +err:
>> + ? ? while (--i >= 0)
>> + ? ? ? ? ? ? regulator_unregister(priv->regulators[i]);
>> +
>> +err_alloc:
>> + ? ? kfree(priv);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
>> + ? ? struct mc13xxx_regulator_platform_data *pdata =
>> + ? ? ? ? ? ? dev_get_platdata(&pdev->dev);
>> + ? ? int i;
>> +
>> + ? ? platform_set_drvdata(pdev, NULL);
>> +
>> + ? ? for (i = 0; i < pdata->num_regulators; i++)
>> + ? ? ? ? ? ? regulator_unregister(priv->regulators[i]);
>> +
>> + ? ? kfree(priv);
>> + ? ? return 0;
>> +}
>> +
>> +static struct platform_driver mc13892_regulator_driver = {
>> + ? ? .driver = {
>> + ? ? ? ? ? ? .name ? = "mc13892-regulator",
>> + ? ? ? ? ? ? .owner ?= THIS_MODULE,
>> + ? ? },
>> + ? ? .remove ? ? ? ? = __devexit_p(mc13892_regulator_remove),
>> + ? ? .probe ? ? ? ? ?= mc13892_regulator_probe,
> If you ask me just use a single space before =, but there is no common
> style visible in the kernel, so do as you prefer.
> (The advantage of using a single space is that if later
> .averylongmembername needs to be initialized you either have to fix
> lines that are technically unrelated or the indention isn't uniform.)
Good suggestion. What I do is use a tab in front of '=', for better looking :).
>
> Best regards
> Uwe
>
>> +};
>> +
>> +static int __init mc13892_regulator_init(void)
>> +{
>> + ? ? return platform_driver_register(&mc13892_regulator_driver);
>> +}
>> +subsys_initcall(mc13892_regulator_init);
>> +
>> +static void __exit mc13892_regulator_exit(void)
>> +{
>> + ? ? platform_driver_unregister(&mc13892_regulator_driver);
>> +}
>> +module_exit(mc13892_regulator_exit);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
>> +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC");
>> +MODULE_ALIAS("platform:mc13892-regulator");
>> diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h
>> new file mode 100644
>> index 0000000..7df13e8
>> --- /dev/null
>> +++ b/include/linux/mfd/mc13892.h
>> @@ -0,0 +1,38 @@
>> +/*
>> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
>> + *
>> + * 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 __LINUX_MFD_MC13892_H
>> +#define __LINUX_MFD_MC13892_H
>> +#include <linux/mfd/mc13xxx.h>
>> +
>> +#define MC13892_SW1 ? ? ? ? ?0
>> +#define MC13892_SW2 ? ? ? ? ?1
>> +#define MC13892_SW3 ? ? ? ? ?2
>> +#define MC13892_SW4 ? ? ? ? ?3
>> +#define MC13892_SWBST ? ? ? ?4
>> +#define MC13892_VIOHI ? ? ? ?5
>> +#define MC13892_VPLL 6
>> +#define MC13892_VDIG 7
>> +#define MC13892_VSD ?8
>> +#define MC13892_VUSB2 ? ? ? ?9
>> +#define MC13892_VVIDEO ? ? ? 10
>> +#define MC13892_VAUDIO ? ? ? 11
>> +#define MC13892_VCAM 12
>> +#define MC13892_VGEN1 ? ? ? ?13
>> +#define MC13892_VGEN2 ? ? ? ?14
>> +#define MC13892_VGEN3 ? ? ? ?15
>> +#define MC13892_VUSB 16
>> +#define MC13892_GPO1 17
>> +#define MC13892_GPO2 18
>> +#define MC13892_GPO3 19
>> +#define MC13892_GPO4 20
>> +#define MC13892_PWGT1SPI ? ? 21
>> +#define MC13892_PWGT2SPI ? ? 22
>> +#define MC13892_VCOINCELL ? ?23
>> +
>> +#endif
>> --
>> 1.7.0.4
>
> --
> Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | Uwe Kleine-K?nig ? ? ? ? ? ?|
> Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
>
Thanks
Yong

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

* [PATCH] support PMIC mc13892
  2010-12-06 10:40 ` David Jander
@ 2010-12-07  2:50   ` Yong Shen
  0 siblings, 0 replies; 21+ messages in thread
From: Yong Shen @ 2010-12-07  2:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi David,

On Mon, Dec 6, 2010 at 6:40 PM, David Jander <david.jander@protonic.nl> wrote:
>
> Hi Yong,
>
> On Mon, 6 Dec 2010 14:25:35 +0800 <yong.shen@freescale.com> wrote:
>>[...]
>> --- /dev/null
>> +++ b/include/linux/mfd/mc13892.h
>> @@ -0,0 +1,38 @@
>> +/*
>> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
>> + *
>> + * 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 __LINUX_MFD_MC13892_H
>> +#define __LINUX_MFD_MC13892_H
>> +#include <linux/mfd/mc13xxx.h>
>> +
>> +#define MC13892_SW1 ? ? ? ? ?0
>> +#define MC13892_SW2 ? ? ? ? ?1
>> +#define MC13892_SW3 ? ? ? ? ?2
>> +#define MC13892_SW4 ? ? ? ? ?3
>> +#define MC13892_SWBST ? ? ? ?4
>> +#define MC13892_VIOHI ? ? ? ?5
>> +#define MC13892_VPLL 6
>> +#define MC13892_VDIG 7
>> +#define MC13892_VSD ?8
>> +#define MC13892_VUSB2 ? ? ? ?9
>> +#define MC13892_VVIDEO ? ? ? 10
>> +#define MC13892_VAUDIO ? ? ? 11
>> +#define MC13892_VCAM 12
>> +#define MC13892_VGEN1 ? ? ? ?13
>> +#define MC13892_VGEN2 ? ? ? ?14
>> +#define MC13892_VGEN3 ? ? ? ?15
>> +#define MC13892_VUSB 16
>> +#define MC13892_GPO1 17
>> +#define MC13892_GPO2 18
>> +#define MC13892_GPO3 19
>> +#define MC13892_GPO4 20
>> +#define MC13892_PWGT1SPI ? ? 21
>> +#define MC13892_PWGT2SPI ? ? 22
>> +#define MC13892_VCOINCELL ? ?23
>> +
>> +#endif
>
> I suppose these are needed outside the driver .c file? If so, can't these go in
> linux/mfd/mc13xxx.h?

This head is only for regulator usage, however linux/mfd/mc13xxx.h is
for multiple functions.
> The platform-data struct is in there too, so why not put the corresponding
> defines there also?
> For other subsystems, those defines that are common are prefixed MC13XXX_ and
> those that are individual, get MC13892_ or MC13783_. This makes it also easier
> and less intrusive to add support for future chips in this series....
>
This is debatable. Previously, I put it under
include/linux/regulator/, but after reviewing comments from other guys
(see previous email for mc13783), I also realized that this is private
for mc13xxx regulator drivers, basically no other users, so it is
better to stay in drivers/regulator/.

Thanks
Yong

> Best regards,
>
> --
> David Jander
> Protonic Holland.
>

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

* [PATCH] support PMIC mc13892
  2010-12-06 10:55 ` Arnaud Patard (Rtp)
  2010-12-06 11:42   ` Alberto Panizzo
@ 2010-12-07  2:52   ` Yong Shen
  1 sibling, 0 replies; 21+ messages in thread
From: Yong Shen @ 2010-12-07  2:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 6, 2010 at 6:55 PM, Arnaud Patard <arnaud.patard@rtp-net.org> wrote:
> <yong.shen@freescale.com> writes:
>
> Hi,
>
>> From: Yong Shen <yong.shen@linaro.org>
>>
>> add support for mc13892, tested on mx51 babbage board
>
> Will review/test it asap on my efikamx. thanks for working on this :)
Welcome, it is also one of my tasks.
>
>>
>> Signed-off-by: Yong Shen <yong.shen@linaro.org>
>> ---
>> ?drivers/mfd/Kconfig ? ? ? ? ? ? ? ? ? | ? ?4 +
>> ?drivers/regulator/Kconfig ? ? ? ? ? ? | ? ?8 +
>> ?drivers/regulator/Makefile ? ? ? ? ? ?| ? ?1 +
>> ?drivers/regulator/mc13892-regulator.c | ?647 +++++++++++++++++++++++++++++++++
>> ?include/linux/mfd/mc13892.h ? ? ? ? ? | ? 38 ++
>> ?5 files changed, 698 insertions(+), 0 deletions(-)
>> ?create mode 100644 drivers/regulator/mc13892-regulator.c
>> ?create mode 100644 include/linux/mfd/mc13892.h
>
> [...]
>
>> +
>> +static const int mc13892_vvideo[] = {
>> + ? ? 2500000, 2600000, 270000, 2775000,
>> +};
>
> Should be :
> static const int mc13892_vvideo[] = {
> ? ? ? ?270000, 2775000, 2500000, 2600000,
> };

confirmed by spec. I will update it.

Thanks
Yong
>
> I've spotted this in my code some time ago. VVIDEO voltages are not
> ascending order.
>
>
> Arnaud
>

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-06 21:54 ` Marc Reilly
@ 2010-12-07  7:14   ` Marc Reilly
  2010-12-07  8:32     ` Yong Shen
  2010-12-08  6:24     ` Yong Shen
  2010-12-07  7:23   ` Marc Reilly
  2010-12-07  7:23   ` Marc Reilly
  2 siblings, 2 replies; 21+ messages in thread
From: Marc Reilly @ 2010-12-07  7:14 UTC (permalink / raw)
  To: linux-arm-kernel

---
 drivers/mfd/mc13xxx-core.c |  332 +++++++++++++++++++++++++++++++-------------
 1 files changed, 234 insertions(+), 98 deletions(-)

diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index a2ac2ed..229cf43 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -9,7 +9,6 @@
  * 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>
@@ -18,12 +17,28 @@
 #include <linux/spi/spi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/mc13xxx.h>
+#include <linux/i2c.h>
+
+enum mc13xxx_id {
+	MC13XXX_ID_MC13783,
+	MC13XXX_ID_MC13892,
+	MC13XXX_ID_INVALID,
+};
 
 struct mc13xxx {
-	struct spi_device *spidev;
+	union {
+		struct spi_device *spidev;
+		struct i2c_client* client;
+	};
+	struct device *pdev;
+	enum mc13xxx_id icid;
+
 	struct mutex lock;
 	int irq;
 
+	int (*read_dev)(struct mc13xxx*, unsigned int, u32*);
+	int (*write_dev)(struct mc13xxx*, unsigned int, u32);
+
 	irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
 	void *irqdata[MC13XXX_NUM_IRQ];
 };
@@ -150,36 +165,46 @@ EXPORT_SYMBOL(mc13783_to_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->pdev, "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->pdev, "%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->pdev, "%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));
 
 	if (offset > MC13XXX_NUMREGS)
 		return -EINVAL;
 
+	ret = mc13xxx->read_dev(mc13xxx, offset, val);
+	dev_vdbg(mc13xxx->pdev, "[0x%02x] -> 0x%06x\n", offset, *val);
+
+	return ret;
+}
+EXPORT_SYMBOL(mc13xxx_reg_read);
+
+#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));
@@ -201,26 +226,28 @@ 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)
 {
-	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);
+	dev_vdbg(mc13xxx->pdev, "[0x%02x] <- 0x%06x\n", offset, val);
 
 	if (offset > MC13XXX_NUMREGS || val > 0xffffff)
 		return -EINVAL;
 
+	return mc13xxx->write_dev(mc13xxx, offset, val);
+}
+EXPORT_SYMBOL(mc13xxx_reg_write);
+
+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));
@@ -241,7 +268,33 @@ int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
 
 	return 0;
 }
-EXPORT_SYMBOL(mc13xxx_reg_write);
+
+static int mc13xxx_i2c_reg_read(struct mc13xxx *mc13xxx, unsigned int offset,
+		u32 *val)
+{
+	int ret;
+	unsigned char buff[3] = {0,0,0};
+
+	ret = i2c_smbus_read_i2c_block_data(mc13xxx->client, offset, 3, buff);
+	*val = buff[0] << 16 | buff[1] << 8 | buff[2];
+
+	return ret == 3 ? 0 : ret;
+}
+
+static int mc13xxx_i2c_reg_write(struct mc13xxx *mc13xxx, unsigned int offset,
+		u32 val)
+{
+	int ret;
+	unsigned char buff[3];
+
+	buff[0] = (val >> 16) & 0xff;
+	buff[1] = (val >> 8) & 0xff;
+	buff[2] = val & 0xff;
+
+	ret = i2c_smbus_write_i2c_block_data(mc13xxx->client, offset, 3, buff);
+
+	return ret;
+}
 
 int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
 		u32 mask, u32 val)
@@ -445,7 +498,7 @@ static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx,
 			if (handled == IRQ_HANDLED)
 				num_handled++;
 		} else {
-			dev_err(&mc13xxx->spidev->dev,
+			dev_err(mc13xxx->pdev,
 					"BUG: irq %u but no handler\n",
 					baseirq + irq);
 
@@ -481,11 +534,6 @@ 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,
-};
 
 const char *mc13xxx_chipname[] = {
 	[MC13XXX_ID_MC13783] = "mc13783",
@@ -493,41 +541,38 @@ const char *mc13xxx_chipname[] = {
 };
 
 #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, int usespi)
 {
 	u32 icid;
 	u32 revision;
 	const char *name;
 	int ret;
 
-	ret = mc13xxx_reg_read(mc13xxx, 46, &icid);
+	ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
 	if (ret)
 		return ret;
 
-	icid = (icid >> 6) & 0x7;
+	icid = (revision >> 6) & 0x7;
 
 	switch (icid) {
 	case 2:
-		*id = MC13XXX_ID_MC13783;
+		mc13xxx->icid = MC13XXX_ID_MC13783;
 		name = "mc13783";
 		break;
 	case 7:
-		*id = MC13XXX_ID_MC13892;
+		mc13xxx->icid = MC13XXX_ID_MC13892;
 		name = "mc13892";
 		break;
 	default:
-		*id = MC13XXX_ID_INVALID;
+		mc13xxx->icid = MC13XXX_ID_INVALID;
 		break;
 	}
 
-	if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) {
-		ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
-		if (ret)
-			return ret;
-
-		dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, "
+	if (mc13xxx->icid == MC13XXX_ID_MC13783 ||
+			mc13xxx->icid == MC13XXX_ID_MC13892) {
+		dev_info(mc13xxx->pdev, "%s: rev: %d.%d, "
 				"fin: %d, fab: %d, icid: %d/%d\n",
-				mc13xxx_chipname[*id],
+				mc13xxx_chipname[mc13xxx->icid],
 				maskval(revision, MC13XXX_REVISION_REVFULL),
 				maskval(revision, MC13XXX_REVISION_REVMETAL),
 				maskval(revision, MC13XXX_REVISION_FIN),
@@ -535,27 +580,23 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
 				maskval(revision, MC13XXX_REVISION_ICID),
 				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");
+	if (mc13xxx->icid != MC13XXX_ID_INVALID) {
+		if (usespi) {
+			const struct spi_device_id *devid =
+				spi_get_device_id(mc13xxx->spidev);
+			if (!devid || devid->driver_data != mc13xxx->icid)
+				dev_warn(mc13xxx->pdev, "device id doesn't "
+						"match auto detection!\n");
+		} else {
+			/* TODO */
+		}
 	}
-
 	return 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->icid];
 }
 
 #include <linux/mfd/mc13783.h>
@@ -563,7 +604,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
 {
 	struct mc13xxx_platform_data *pdata =
-		dev_get_platdata(&mc13xxx->spidev->dev);
+		dev_get_platdata(mc13xxx->pdev);
 
 	return pdata->flags;
 }
@@ -601,7 +642,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
 	};
 	init_completion(&adcdone_data.done);
 
-	dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__);
+	dev_dbg(mc13xxx->pdev, "%s\n", __func__);
 
 	mc13xxx_lock(mc13xxx);
 
@@ -643,7 +684,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
 		return -EINVAL;
 	}
 
-	dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__);
+	dev_dbg(mc13783->mc13xxx.pdev, "%s: request irq\n", __func__);
 	mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE,
 			mc13783_handler_adcdone, __func__, &adcdone_data);
 	mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE);
@@ -701,7 +742,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->pdev, -1, &cell, 1, NULL, 0);
 }
 
 static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
@@ -709,11 +750,48 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
 	return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
 }
 
-static int mc13xxx_probe(struct spi_device *spi)
+static int mc13xxx_common_probe(struct mc13xxx* mc13xxx, 
+				struct mc13xxx_platform_data* pdata)
+{
+	mc13xxx_unlock(mc13xxx);
+
+	if (!pdata)
+		return 0;
+
+	if (pdata->flags & MC13XXX_USE_ADC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-adc");
+
+	if (pdata->flags & MC13XXX_USE_CODEC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+
+	if (pdata->flags & MC13XXX_USE_REGULATOR) {
+		struct mc13xxx_regulator_platform_data regulator_pdata = {
+			.num_regulators = pdata->num_regulators,
+			.regulators = pdata->regulators,
+		};
+
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
+				&regulator_pdata, sizeof(regulator_pdata));
+	}
+
+	if (pdata->flags & MC13XXX_USE_RTC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
+
+	if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
+		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+
+	if (pdata->flags & MC13XXX_USE_LED) {
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
+					pdata->leds, sizeof(*pdata->leds));
+	}
+
+	return 0;
+}
+
+static int mc13xxx_spi_probe(struct spi_device *spi)
 {
 	struct mc13xxx *mc13xxx;
 	struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
-	enum mc13xxx_id id;
 	int ret;
 
 	mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
@@ -725,13 +803,17 @@ static int mc13xxx_probe(struct spi_device *spi)
 	spi->bits_per_word = 32;
 	spi_setup(spi);
 
+	mc13xxx->pdev = &spi->dev;
 	mc13xxx->spidev = spi;
+	mc13xxx->read_dev = mc13xxx_spi_reg_read;
+	mc13xxx->write_dev = mc13xxx_spi_reg_write;
+	mc13xxx->irq = spi->irq;
 
 	mutex_init(&mc13xxx->lock);
 	mc13xxx_lock(mc13xxx);
 
-	ret = mc13xxx_identify(mc13xxx, &id);
-	if (ret || id == MC13XXX_ID_INVALID)
+	ret = mc13xxx_identify(mc13xxx, 1);
+	if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
 		goto err_revision;
 
 	/* mask all irqs */
@@ -743,7 +825,7 @@ 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) {
@@ -755,43 +837,15 @@ err_revision:
 		return ret;
 	}
 
-	mc13xxx_unlock(mc13xxx);
-
-	if (pdata->flags & MC13XXX_USE_ADC)
-		mc13xxx_add_subdevice(mc13xxx, "%s-adc");
-
-	if (pdata->flags & MC13XXX_USE_CODEC)
-		mc13xxx_add_subdevice(mc13xxx, "%s-codec");
-
-	if (pdata->flags & MC13XXX_USE_REGULATOR) {
-		struct mc13xxx_regulator_platform_data regulator_pdata = {
-			.num_regulators = pdata->num_regulators,
-			.regulators = pdata->regulators,
-		};
-
-		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
-				&regulator_pdata, sizeof(regulator_pdata));
-	}
-
-	if (pdata->flags & MC13XXX_USE_RTC)
-		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
-
-	if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
-		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
-
-	if (pdata->flags & MC13XXX_USE_LED) {
-		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
-					pdata->leds, sizeof(*pdata->leds));
-	}
-
-	return 0;
+	return mc13xxx_common_probe(mc13xxx, pdata);
 }
 
-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);
+	free_irq(mc13xxx->irq, mc13xxx);
 
 	mfd_remove_devices(&spi->dev);
 
@@ -819,18 +873,100 @@ static struct spi_driver mc13xxx_driver = {
 		.bus = &spi_bus_type,
 		.owner = THIS_MODULE,
 	},
-	.probe = mc13xxx_probe,
-	.remove = __devexit_p(mc13xxx_remove),
+	.probe = mc13xxx_spi_probe,
+	.remove = __devexit_p(mc13xxx_spi_remove),
+};
+
+static int mc13xxx_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id* id)
+{
+	struct mc13xxx *mc13xxx;
+	struct mc13xxx_platform_data *pdata = dev_get_platdata(&client->dev);
+	int ret;
+
+	mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
+	if (!mc13xxx)
+		return -ENOMEM;
+
+	dev_set_drvdata(&client->dev, mc13xxx);
+	mc13xxx->pdev = &client->dev;
+	mc13xxx->client = client;
+	mc13xxx->read_dev = mc13xxx_i2c_reg_read;
+	mc13xxx->write_dev = mc13xxx_i2c_reg_write;
+	mc13xxx->irq = client->irq;
+
+	mutex_init(&mc13xxx->lock);
+	mc13xxx_lock(mc13xxx);
+
+	ret = mc13xxx_identify(mc13xxx, 0);
+	if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
+		goto err_revision;
+
+	/* mask all irqs */
+	ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
+	if (ret)
+		goto err_mask;
+
+	ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
+	if (ret)
+		goto err_mask;
+
+	ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread,
+			IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
+
+	if (ret) {
+err_mask:
+err_revision:
+		mutex_unlock(&mc13xxx->lock);
+		kfree(mc13xxx);
+		return ret;
+	}
+
+	return mc13xxx_common_probe(mc13xxx,pdata);
+}
+
+static int __devexit mc13xxx_i2c_remove(struct i2c_client *client)
+{
+	struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev);
+
+	free_irq(mc13xxx->irq, mc13xxx);
+
+	mfd_remove_devices(&client->dev);
+
+	kfree(mc13xxx);
+
+	return 0;
+}
+
+static const struct i2c_device_id mc13xxx_i2c_idtable[] = {
+	{ "mc13892", MC13XXX_ID_MC13892},
+	{ }
+};
+
+static struct i2c_driver mc13xxx_i2c_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "mc13xxx-i2c"
+	},
+	.id_table = mc13xxx_i2c_idtable,
+	.probe = mc13xxx_i2c_probe,
+	.remove = __devexit_p(mc13xxx_i2c_remove),
 };
 
 static int __init mc13xxx_init(void)
 {
-	return spi_register_driver(&mc13xxx_driver);
+	int i2cret;
+	int spiret;
+	i2cret = i2c_add_driver(&mc13xxx_i2c_driver);
+	spiret = spi_register_driver(&mc13xxx_driver);
+
+	return (i2cret == 0) && (spiret == 0);
 }
 subsys_initcall(mc13xxx_init);
 
 static void __exit mc13xxx_exit(void)
 {
+	i2c_del_driver(&mc13xxx_i2c_driver);
 	spi_unregister_driver(&mc13xxx_driver);
 }
 module_exit(mc13xxx_exit);
-- 
1.7.1

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-06 21:54 ` Marc Reilly
  2010-12-07  7:14   ` [PATCH] Added i2c support for mc13xxx-core Marc Reilly
@ 2010-12-07  7:23   ` Marc Reilly
  2010-12-07  7:23   ` Marc Reilly
  2 siblings, 0 replies; 21+ messages in thread
From: Marc Reilly @ 2010-12-07  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This patch adds i2c support for the mc13892. It should apply over Yong's
earlier patches.
I've kept everything to one file for the moment, and aimed for minimal impact
on Yong's code to hopefully ease initial integration.

Tested basic functionality on iMX35 based platform (with an mc13892)

Cheers,
Marc

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-06 21:54 ` Marc Reilly
  2010-12-07  7:14   ` [PATCH] Added i2c support for mc13xxx-core Marc Reilly
  2010-12-07  7:23   ` Marc Reilly
@ 2010-12-07  7:23   ` Marc Reilly
  2 siblings, 0 replies; 21+ messages in thread
From: Marc Reilly @ 2010-12-07  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

---
 drivers/mfd/mc13xxx-core.c |  332 +++++++++++++++++++++++++++++++-------------
 1 files changed, 234 insertions(+), 98 deletions(-)

diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index a2ac2ed..229cf43 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -9,7 +9,6 @@
  * 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>
@@ -18,12 +17,28 @@
 #include <linux/spi/spi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/mc13xxx.h>
+#include <linux/i2c.h>
+
+enum mc13xxx_id {
+	MC13XXX_ID_MC13783,
+	MC13XXX_ID_MC13892,
+	MC13XXX_ID_INVALID,
+};
 
 struct mc13xxx {
-	struct spi_device *spidev;
+	union {
+		struct spi_device *spidev;
+		struct i2c_client* client;
+	};
+	struct device *pdev;
+	enum mc13xxx_id icid;
+
 	struct mutex lock;
 	int irq;
 
+	int (*read_dev)(struct mc13xxx*, unsigned int, u32*);
+	int (*write_dev)(struct mc13xxx*, unsigned int, u32);
+
 	irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
 	void *irqdata[MC13XXX_NUM_IRQ];
 };
@@ -150,36 +165,46 @@ EXPORT_SYMBOL(mc13783_to_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->pdev, "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->pdev, "%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->pdev, "%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));
 
 	if (offset > MC13XXX_NUMREGS)
 		return -EINVAL;
 
+	ret = mc13xxx->read_dev(mc13xxx, offset, val);
+	dev_vdbg(mc13xxx->pdev, "[0x%02x] -> 0x%06x\n", offset, *val);
+
+	return ret;
+}
+EXPORT_SYMBOL(mc13xxx_reg_read);
+
+#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));
@@ -201,26 +226,28 @@ 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)
 {
-	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);
+	dev_vdbg(mc13xxx->pdev, "[0x%02x] <- 0x%06x\n", offset, val);
 
 	if (offset > MC13XXX_NUMREGS || val > 0xffffff)
 		return -EINVAL;
 
+	return mc13xxx->write_dev(mc13xxx, offset, val);
+}
+EXPORT_SYMBOL(mc13xxx_reg_write);
+
+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));
@@ -241,7 +268,33 @@ int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
 
 	return 0;
 }
-EXPORT_SYMBOL(mc13xxx_reg_write);
+
+static int mc13xxx_i2c_reg_read(struct mc13xxx *mc13xxx, unsigned int offset,
+		u32 *val)
+{
+	int ret;
+	unsigned char buff[3] = {0,0,0};
+
+	ret = i2c_smbus_read_i2c_block_data(mc13xxx->client, offset, 3, buff);
+	*val = buff[0] << 16 | buff[1] << 8 | buff[2];
+
+	return ret == 3 ? 0 : ret;
+}
+
+static int mc13xxx_i2c_reg_write(struct mc13xxx *mc13xxx, unsigned int offset,
+		u32 val)
+{
+	int ret;
+	unsigned char buff[3];
+
+	buff[0] = (val >> 16) & 0xff;
+	buff[1] = (val >> 8) & 0xff;
+	buff[2] = val & 0xff;
+
+	ret = i2c_smbus_write_i2c_block_data(mc13xxx->client, offset, 3, buff);
+
+	return ret;
+}
 
 int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
 		u32 mask, u32 val)
@@ -445,7 +498,7 @@ static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx,
 			if (handled == IRQ_HANDLED)
 				num_handled++;
 		} else {
-			dev_err(&mc13xxx->spidev->dev,
+			dev_err(mc13xxx->pdev,
 					"BUG: irq %u but no handler\n",
 					baseirq + irq);
 
@@ -481,11 +534,6 @@ 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,
-};
 
 const char *mc13xxx_chipname[] = {
 	[MC13XXX_ID_MC13783] = "mc13783",
@@ -493,41 +541,38 @@ const char *mc13xxx_chipname[] = {
 };
 
 #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, int usespi)
 {
 	u32 icid;
 	u32 revision;
 	const char *name;
 	int ret;
 
-	ret = mc13xxx_reg_read(mc13xxx, 46, &icid);
+	ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
 	if (ret)
 		return ret;
 
-	icid = (icid >> 6) & 0x7;
+	icid = (revision >> 6) & 0x7;
 
 	switch (icid) {
 	case 2:
-		*id = MC13XXX_ID_MC13783;
+		mc13xxx->icid = MC13XXX_ID_MC13783;
 		name = "mc13783";
 		break;
 	case 7:
-		*id = MC13XXX_ID_MC13892;
+		mc13xxx->icid = MC13XXX_ID_MC13892;
 		name = "mc13892";
 		break;
 	default:
-		*id = MC13XXX_ID_INVALID;
+		mc13xxx->icid = MC13XXX_ID_INVALID;
 		break;
 	}
 
-	if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) {
-		ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
-		if (ret)
-			return ret;
-
-		dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, "
+	if (mc13xxx->icid == MC13XXX_ID_MC13783 ||
+			mc13xxx->icid == MC13XXX_ID_MC13892) {
+		dev_info(mc13xxx->pdev, "%s: rev: %d.%d, "
 				"fin: %d, fab: %d, icid: %d/%d\n",
-				mc13xxx_chipname[*id],
+				mc13xxx_chipname[mc13xxx->icid],
 				maskval(revision, MC13XXX_REVISION_REVFULL),
 				maskval(revision, MC13XXX_REVISION_REVMETAL),
 				maskval(revision, MC13XXX_REVISION_FIN),
@@ -535,27 +580,23 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
 				maskval(revision, MC13XXX_REVISION_ICID),
 				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");
+	if (mc13xxx->icid != MC13XXX_ID_INVALID) {
+		if (usespi) {
+			const struct spi_device_id *devid =
+				spi_get_device_id(mc13xxx->spidev);
+			if (!devid || devid->driver_data != mc13xxx->icid)
+				dev_warn(mc13xxx->pdev, "device id doesn't "
+						"match auto detection!\n");
+		} else {
+			/* TODO */
+		}
 	}
-
 	return 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->icid];
 }
 
 #include <linux/mfd/mc13783.h>
@@ -563,7 +604,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
 {
 	struct mc13xxx_platform_data *pdata =
-		dev_get_platdata(&mc13xxx->spidev->dev);
+		dev_get_platdata(mc13xxx->pdev);
 
 	return pdata->flags;
 }
@@ -601,7 +642,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
 	};
 	init_completion(&adcdone_data.done);
 
-	dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__);
+	dev_dbg(mc13xxx->pdev, "%s\n", __func__);
 
 	mc13xxx_lock(mc13xxx);
 
@@ -643,7 +684,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
 		return -EINVAL;
 	}
 
-	dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__);
+	dev_dbg(mc13783->mc13xxx.pdev, "%s: request irq\n", __func__);
 	mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE,
 			mc13783_handler_adcdone, __func__, &adcdone_data);
 	mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE);
@@ -701,7 +742,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->pdev, -1, &cell, 1, NULL, 0);
 }
 
 static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
@@ -709,11 +750,48 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
 	return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
 }
 
-static int mc13xxx_probe(struct spi_device *spi)
+static int mc13xxx_common_probe(struct mc13xxx* mc13xxx, 
+				struct mc13xxx_platform_data* pdata)
+{
+	mc13xxx_unlock(mc13xxx);
+
+	if (!pdata)
+		return 0;
+
+	if (pdata->flags & MC13XXX_USE_ADC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-adc");
+
+	if (pdata->flags & MC13XXX_USE_CODEC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+
+	if (pdata->flags & MC13XXX_USE_REGULATOR) {
+		struct mc13xxx_regulator_platform_data regulator_pdata = {
+			.num_regulators = pdata->num_regulators,
+			.regulators = pdata->regulators,
+		};
+
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
+				&regulator_pdata, sizeof(regulator_pdata));
+	}
+
+	if (pdata->flags & MC13XXX_USE_RTC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
+
+	if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
+		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+
+	if (pdata->flags & MC13XXX_USE_LED) {
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
+					pdata->leds, sizeof(*pdata->leds));
+	}
+
+	return 0;
+}
+
+static int mc13xxx_spi_probe(struct spi_device *spi)
 {
 	struct mc13xxx *mc13xxx;
 	struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
-	enum mc13xxx_id id;
 	int ret;
 
 	mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
@@ -725,13 +803,17 @@ static int mc13xxx_probe(struct spi_device *spi)
 	spi->bits_per_word = 32;
 	spi_setup(spi);
 
+	mc13xxx->pdev = &spi->dev;
 	mc13xxx->spidev = spi;
+	mc13xxx->read_dev = mc13xxx_spi_reg_read;
+	mc13xxx->write_dev = mc13xxx_spi_reg_write;
+	mc13xxx->irq = spi->irq;
 
 	mutex_init(&mc13xxx->lock);
 	mc13xxx_lock(mc13xxx);
 
-	ret = mc13xxx_identify(mc13xxx, &id);
-	if (ret || id == MC13XXX_ID_INVALID)
+	ret = mc13xxx_identify(mc13xxx, 1);
+	if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
 		goto err_revision;
 
 	/* mask all irqs */
@@ -743,7 +825,7 @@ 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) {
@@ -755,43 +837,15 @@ err_revision:
 		return ret;
 	}
 
-	mc13xxx_unlock(mc13xxx);
-
-	if (pdata->flags & MC13XXX_USE_ADC)
-		mc13xxx_add_subdevice(mc13xxx, "%s-adc");
-
-	if (pdata->flags & MC13XXX_USE_CODEC)
-		mc13xxx_add_subdevice(mc13xxx, "%s-codec");
-
-	if (pdata->flags & MC13XXX_USE_REGULATOR) {
-		struct mc13xxx_regulator_platform_data regulator_pdata = {
-			.num_regulators = pdata->num_regulators,
-			.regulators = pdata->regulators,
-		};
-
-		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
-				&regulator_pdata, sizeof(regulator_pdata));
-	}
-
-	if (pdata->flags & MC13XXX_USE_RTC)
-		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
-
-	if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
-		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
-
-	if (pdata->flags & MC13XXX_USE_LED) {
-		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
-					pdata->leds, sizeof(*pdata->leds));
-	}
-
-	return 0;
+	return mc13xxx_common_probe(mc13xxx, pdata);
 }
 
-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);
+	free_irq(mc13xxx->irq, mc13xxx);
 
 	mfd_remove_devices(&spi->dev);
 
@@ -819,18 +873,100 @@ static struct spi_driver mc13xxx_driver = {
 		.bus = &spi_bus_type,
 		.owner = THIS_MODULE,
 	},
-	.probe = mc13xxx_probe,
-	.remove = __devexit_p(mc13xxx_remove),
+	.probe = mc13xxx_spi_probe,
+	.remove = __devexit_p(mc13xxx_spi_remove),
+};
+
+static int mc13xxx_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id* id)
+{
+	struct mc13xxx *mc13xxx;
+	struct mc13xxx_platform_data *pdata = dev_get_platdata(&client->dev);
+	int ret;
+
+	mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
+	if (!mc13xxx)
+		return -ENOMEM;
+
+	dev_set_drvdata(&client->dev, mc13xxx);
+	mc13xxx->pdev = &client->dev;
+	mc13xxx->client = client;
+	mc13xxx->read_dev = mc13xxx_i2c_reg_read;
+	mc13xxx->write_dev = mc13xxx_i2c_reg_write;
+	mc13xxx->irq = client->irq;
+
+	mutex_init(&mc13xxx->lock);
+	mc13xxx_lock(mc13xxx);
+
+	ret = mc13xxx_identify(mc13xxx, 0);
+	if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
+		goto err_revision;
+
+	/* mask all irqs */
+	ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
+	if (ret)
+		goto err_mask;
+
+	ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
+	if (ret)
+		goto err_mask;
+
+	ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread,
+			IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
+
+	if (ret) {
+err_mask:
+err_revision:
+		mutex_unlock(&mc13xxx->lock);
+		kfree(mc13xxx);
+		return ret;
+	}
+
+	return mc13xxx_common_probe(mc13xxx,pdata);
+}
+
+static int __devexit mc13xxx_i2c_remove(struct i2c_client *client)
+{
+	struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev);
+
+	free_irq(mc13xxx->irq, mc13xxx);
+
+	mfd_remove_devices(&client->dev);
+
+	kfree(mc13xxx);
+
+	return 0;
+}
+
+static const struct i2c_device_id mc13xxx_i2c_idtable[] = {
+	{ "mc13892", MC13XXX_ID_MC13892},
+	{ }
+};
+
+static struct i2c_driver mc13xxx_i2c_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "mc13xxx-i2c"
+	},
+	.id_table = mc13xxx_i2c_idtable,
+	.probe = mc13xxx_i2c_probe,
+	.remove = __devexit_p(mc13xxx_i2c_remove),
 };
 
 static int __init mc13xxx_init(void)
 {
-	return spi_register_driver(&mc13xxx_driver);
+	int i2cret;
+	int spiret;
+	i2cret = i2c_add_driver(&mc13xxx_i2c_driver);
+	spiret = spi_register_driver(&mc13xxx_driver);
+
+	return (i2cret == 0) && (spiret == 0);
 }
 subsys_initcall(mc13xxx_init);
 
 static void __exit mc13xxx_exit(void)
 {
+	i2c_del_driver(&mc13xxx_i2c_driver);
 	spi_unregister_driver(&mc13xxx_driver);
 }
 module_exit(mc13xxx_exit);
-- 
1.7.1

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

* [PATCH] support PMIC mc13892
  2010-12-06  7:22 ` Uwe Kleine-König
  2010-12-07  2:41   ` Yong Shen
@ 2010-12-07  7:57   ` Yong Shen
  2010-12-07  8:02     ` Uwe Kleine-König
  1 sibling, 1 reply; 21+ messages in thread
From: Yong Shen @ 2010-12-07  7:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

2010/12/6 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> Hello,
>
> On Mon, Dec 06, 2010 at 02:25:35PM +0800, yong.shen at freescale.com wrote:
>> From: Yong Shen <yong.shen@linaro.org>
>>
>> add support for mc13892, tested on mx51 babbage board
>>
>> Signed-off-by: Yong Shen <yong.shen@linaro.org>
>> ---
>> ?drivers/mfd/Kconfig ? ? ? ? ? ? ? ? ? | ? ?4 +
>> ?drivers/regulator/Kconfig ? ? ? ? ? ? | ? ?8 +
>> ?drivers/regulator/Makefile ? ? ? ? ? ?| ? ?1 +
>> ?drivers/regulator/mc13892-regulator.c | ?647 +++++++++++++++++++++++++++++++++
>> ?include/linux/mfd/mc13892.h ? ? ? ? ? | ? 38 ++
>> ?5 files changed, 698 insertions(+), 0 deletions(-)
>> ?create mode 100644 drivers/regulator/mc13892-regulator.c
>> ?create mode 100644 include/linux/mfd/mc13892.h
>>
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 3a1493b..7659af9 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -427,11 +427,15 @@ config MFD_PCF50633
>> ?config MFD_MC13783
>> ? ? ? tristate
>>
>> +config MFD_MC13892
>> + ? ? tristate
>> +
> This is not needed, MFD_MC13783 only exists because when MFD_MC13XXX was
> introduced some drivers still depended on MFD_MC13783. ?As mc13xxx.[ch]
> provided enough compatibility cruft MFD_MC13XXX just selected MFD_MC13783.
>
>> ?config MFD_MC13XXX
>> ? ? ? tristate "Support Freescale MC13783 and MC13892"
>> ? ? ? depends on SPI_MASTER
>> ? ? ? select MFD_CORE
>> ? ? ? select MFD_MC13783
>> + ? ? select MFD_MC13892
>> ? ? ? help
>> ? ? ? ? Support for the Freescale (Atlas) PMIC and audio CODECs
>> ? ? ? ? MC13783 and MC13892.
>> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
>> index 6e54253..7f7bc22 100644
>> --- a/drivers/regulator/Kconfig
>> +++ b/drivers/regulator/Kconfig
>> @@ -197,6 +197,14 @@ config REGULATOR_MC13783
>> ? ? ? ? Say y here to support the regulators found on the Freescale MC13783
>> ? ? ? ? PMIC.
>>
>> +config REGULATOR_MC13892
>> + ? ? tristate "Support regulators on Freescale MC13892 PMIC"
>> + ? ? depends on MFD_MC13892
>> + ? ? select REGULATOR_MC13XXX_CORE
>> + ? ? help
>> + ? ? ? Say y here to support the regulators found on the Freescale MC13892
>> + ? ? ? PMIC.
>> +
>> ?config REGULATOR_AB3100
>> ? ? ? tristate "ST-Ericsson AB3100 Regulator functions"
>> ? ? ? depends on AB3100_CORE
>> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
>> index 11876be..3107480 100644
>> --- a/drivers/regulator/Makefile
>> +++ b/drivers/regulator/Makefile
>> @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X) ? ? ?+= da903x.o
>> ?obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
>> ?obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
>> ?obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
>> +obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
>> ?obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += ?mc13xxx-regulator-core.o
>> ?obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
>>
>> diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
>> new file mode 100644
>> index 0000000..6e613d4
>> --- /dev/null
>> +++ b/drivers/regulator/mc13892-regulator.c
>> @@ -0,0 +1,647 @@
>> +/*
>> + * Regulator Driver for Freescale MC13892 PMIC
>> + *
>> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
>> + *
>> + * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org>
>> + *
>> + * 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/mfd/mc13892.h>
>> +#include <linux/regulator/machine.h>
>> +#include <linux/regulator/driver.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/kernel.h>
>> +#include <linux/slab.h>
>> +#include <linux/init.h>
>> +#include <linux/err.h>
>> +#include "mc13xxx.h"
> shouldn't that be
>
> ? ? ? ?#include <linux/mfd/mc13xxx.h>
>
> ?
>> +
>> +#define MC13892_REVISION ? ? ? ? ? ? ? ? ? ? ? ? ? ? 7
>> +
>> +#define MC13892_POWERCTL0 ? ? ? ? ? ? ? ? ? ? ? ? ? ?13
>> +#define MC13892_POWERCTL0_USEROFFSPI ? ? ? ? 3
>> +#define MC13892_POWERCTL0_VCOINCELLVSEL ? ? ? ? ? ? ?20
>> +#define MC13892_POWERCTL0_VCOINCELLVSEL_M ? ? ? ? ? ?(7<<20)
>> +#define MC13892_POWERCTL0_VCOINCELLEN ? ? ? ? ? ? ? ?(1<<23)
>> +
>> +#define MC13892_SWITCHERS0_SWxHI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +
>> +#define MC13892_SWITCHERS0 ? ? ? ? ? ? ? ? ? ? ? ? ? 24
>> +#define MC13892_SWITCHERS0_SW1VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS0_SW1VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS0_SW1HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS0_SW1EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS1 ? ? ? ? ? ? ? ? ? ? ? ? ? 25
>> +#define MC13892_SWITCHERS1_SW2VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS1_SW2VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS1_SW2HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS1_SW2EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS2 ? ? ? ? ? ? ? ? ? ? ? ? ? 26
>> +#define MC13892_SWITCHERS2_SW3VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS2_SW3VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS2_SW3HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS2_SW3EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS3 ? ? ? ? ? ? ? ? ? ? ? ? ? 27
>> +#define MC13892_SWITCHERS3_SW4VSEL ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS3_SW4VSEL_M ? ? ? ? (0x1f<<0)
>> +#define MC13892_SWITCHERS3_SW4HI ? ? ? ? ? ? ? ? ? ? (1<<23)
>> +#define MC13892_SWITCHERS3_SW4EN ? ? ? ? ? ? 0
>> +
>> +#define MC13892_SWITCHERS4 ? ? ? ? ? ? ? ? ? ? ? ? ? 28
>> +#define MC13892_SWITCHERS4_SW1MODE ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS4_SW1MODE_AUTO ? ? ? ? ? ? ?(8<<0)
>> +#define MC13892_SWITCHERS4_SW1MODE_M ? ? ? ? (0xf<<0)
>> +#define MC13892_SWITCHERS4_SW2MODE ? ? ? ? ? ? ? ? ? 10
>> +#define MC13892_SWITCHERS4_SW2MODE_AUTO ? ? ? ? ? ? ?(8<<10)
>> +#define MC13892_SWITCHERS4_SW2MODE_M ? ? ? ? (0xf<<10)
>> +
>> +#define MC13892_SWITCHERS5 ? ? ? ? ? ? ? ? ? ? ? ? ? 29
>> +#define MC13892_SWITCHERS5_SW3MODE ? ? ? ? ? ? ? ? ? 0
>> +#define MC13892_SWITCHERS5_SW3MODE_AUTO ? ? ? ? ? ? ?(8<<0)
>> +#define MC13892_SWITCHERS5_SW3MODE_M ? ? ? ? (0xf<<0)
>> +#define MC13892_SWITCHERS5_SW4MODE ? ? ? ? ? ? ? ? ? 8
>> +#define MC13892_SWITCHERS5_SW4MODE_AUTO ? ? ? ? ? ? ?(8<<8)
>> +#define MC13892_SWITCHERS5_SW4MODE_M ? ? ? ? (0xf<<8)
>> +#define MC13892_SWITCHERS5_SWBSTEN ? ? ? ? ? ? ? ? ? (1<<20)
>> +
>> +
>> +#define MC13892_REGULATORSETTING0 ? ? ? ? ? ? ? ? ? ?30
>> +#define MC13892_REGULATORSETTING0_VGEN1VSEL ? ? ? ? ?0
>> +#define MC13892_REGULATORSETTING0_VDIGVSEL ? ? ? ? ? 4
>> +#define MC13892_REGULATORSETTING0_VGEN2VSEL ? ? ? ? ?6
>> +#define MC13892_REGULATORSETTING0_VPLLVSEL ? ? ? ? ? 9
>> +#define MC13892_REGULATORSETTING0_VUSB2VSEL ? ? ? ? ?11
>> +#define MC13892_REGULATORSETTING0_VGEN3VSEL ? ? ? ? ?14
>> +#define MC13892_REGULATORSETTING0_VCAMVSEL ? ? ? ? ? 16
>> +
>> +#define MC13892_REGULATORSETTING0_VGEN1VSEL_M ? ? ? ?(3<<0)
>> +#define MC13892_REGULATORSETTING0_VDIGVSEL_M (3<<4)
>> +#define MC13892_REGULATORSETTING0_VGEN2VSEL_M ? ? ? ?(7<<6)
>> +#define MC13892_REGULATORSETTING0_VPLLVSEL_M (3<<9)
>> +#define MC13892_REGULATORSETTING0_VUSB2VSEL_M ? ? ? ?(3<<11)
>> +#define MC13892_REGULATORSETTING0_VGEN3VSEL_M ? ? ? ?(1<<14)
>> +#define MC13892_REGULATORSETTING0_VCAMVSEL_M (3<<16)
>> +
>> +#define MC13892_REGULATORSETTING1 ? ? ? ? ? ? ? ? ? ?31
>> +#define MC13892_REGULATORSETTING1_VVIDEOVSEL 2
>> +#define MC13892_REGULATORSETTING1_VAUDIOVSEL 4
>> +#define MC13892_REGULATORSETTING1_VSDVSEL ? ? ? ? ? ?6
>> +
>> +#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M ? ? ? (3<<2)
>> +#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M ? ? ? (3<<4)
>> +#define MC13892_REGULATORSETTING1_VSDVSEL_M ? ? ? ? ?(7<<6)
>> +
>> +#define MC13892_REGULATORMODE0 ? ? ? ? ? ? ? ? ? ? ? 32
>> +#define MC13892_REGULATORMODE0_VGEN1EN ? ? ? ? ? ? ? (1<<0)
>> +#define MC13892_REGULATORMODE0_VGEN1STDBY ? ? ? ? ? ?(1<<1)
>> +#define MC13892_REGULATORMODE0_VGEN1MODE ? ? ? ? ? ? (1<<2)
>> +#define MC13892_REGULATORMODE0_VIOHIEN ? ? ? ? ? ? ? (1<<3)
>> +#define MC13892_REGULATORMODE0_VIOHISTDBY ? ? ? ? ? ?(1<<4)
>> +#define MC13892_REGULATORMODE0_VIOHIMODE ? ? ? ? ? ? (1<<5)
>> +#define MC13892_REGULATORMODE0_VDIGEN ? ? ? ? ? ? ? ?(1<<9)
>> +#define MC13892_REGULATORMODE0_VDIGSTDBY ? ? ? ? ? ? (1<<10)
>> +#define MC13892_REGULATORMODE0_VDIGMODE ? ? ? ? ? ? ?(1<<11)
>> +#define MC13892_REGULATORMODE0_VGEN2EN ? ? ? ? ? ? ? (1<<12)
>> +#define MC13892_REGULATORMODE0_VGEN2STDBY ? ? ? ? ? ?(1<<13)
>> +#define MC13892_REGULATORMODE0_VGEN2MODE ? ? ? ? ? ? (1<<14)
>> +#define MC13892_REGULATORMODE0_VPLLEN ? ? ? ? ? ? ? ?(1<<15)
>> +#define MC13892_REGULATORMODE0_VPLLSTDBY ? ? ? ? ? ? (1<<16)
>> +#define MC13892_REGULATORMODE0_VPLLMODE ? ? ? ? ? ? ?(1<<17)
>> +#define MC13892_REGULATORMODE0_VUSB2EN ? ? ? ? ? ? ? (1<<18)
>> +#define MC13892_REGULATORMODE0_VUSB2STDBY ? ? ? ? ? ?(1<<19)
>> +#define MC13892_REGULATORMODE0_VUSB2MODE ? ? ? ? ? ? (1<<20)
>> +
>> +#define MC13892_REGULATORMODE1 ? ? ? ? ? ? ? ? ? ? ? 33
>> +#define MC13892_REGULATORMODE1_VGEN3EN ? ? ? ? ? ? ? (1<<0)
>> +#define MC13892_REGULATORMODE1_VGEN3STDBY ? ? ? ? ? ?(1<<1)
>> +#define MC13892_REGULATORMODE1_VGEN3MODE ? ? ? ? ? ? (1<<2)
>> +#define MC13892_REGULATORMODE1_VCAMEN ? ? ? ? ? ? ? ?(1<<6)
>> +#define MC13892_REGULATORMODE1_VCAMSTDBY ? ? ? ? ? ? (1<<7)
>> +#define MC13892_REGULATORMODE1_VCAMMODE ? ? ? ? ? ? ?(1<<8)
>> +#define MC13892_REGULATORMODE1_VCAMCONFIGEN ? ? ? ? ?(1<<9)
>> +#define MC13892_REGULATORMODE1_VVIDEOEN ? ? ? ? ? ? ?(1<<12)
>> +#define MC13892_REGULATORMODE1_VVIDEOSTDBY ? ? ? ? ? (1<<13)
>> +#define MC13892_REGULATORMODE1_VVIDEOMODE ? ? ? ? ? ?(1<<14)
>> +#define MC13892_REGULATORMODE1_VAUDIOEN ? ? ? ? ? ? ?(1<<15)
>> +#define MC13892_REGULATORMODE1_VAUDIOSTDBY ? ? ? ? ? (1<<16)
>> +#define MC13892_REGULATORMODE1_VAUDIOMODE ? ? ? ? ? ?(1<<17)
>> +#define MC13892_REGULATORMODE1_VSDEN ? ? ? ? (1<<18)
>> +#define MC13892_REGULATORMODE1_VSDSTDBY ? ? ? ? ? ? ?(1<<19)
>> +#define MC13892_REGULATORMODE1_VSDMODE ? ? ? ? ? ? ? (1<<20)
>> +
>> +#define MC13892_POWERMISC ? ? ? ? ? ? ? ? ? ? ? ? ? ?34
>> +#define MC13892_POWERMISC_GPO1EN ? ? ? ? ? ? ? ? ? ? (1<<6)
>> +#define MC13892_POWERMISC_GPO2EN ? ? ? ? ? ? ? ? ? ? (1<<8)
>> +#define MC13892_POWERMISC_GPO3EN ? ? ? ? ? ? ? ? ? ? (1<<10)
>> +#define MC13892_POWERMISC_GPO4EN ? ? ? ? ? ? ? ? ? ? (1<<12)
>> +#define MC13892_POWERMISC_PWGT1SPIEN ? ? ? ? (1<<15)
>> +#define MC13892_POWERMISC_PWGT2SPIEN ? ? ? ? (1<<16)
>> +#define MC13892_POWERMISC_GPO4ADINEN ? ? ? ? (1<<21)
>> +
>> +#define MC13892_POWERMISC_PWGTSPI_M ? ? ? ? ? ? ? ? ?(3 << 15)
>> +
>> +#define MC13892_USB1 ? ? ? ? ? ? ? ? ? ? ? ? 50
>> +#define MC13892_USB1_VUSBEN ? ? ? ? ? ? ? ? ? ? ? ? ?(1<<3)
>> +
>> +static const int mc13892_vcoincell[] = {
>> + ? ? 2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
>> + ? ? 3200000, 3300000,
>> +};
>> +
>> +static const int mc13892_sw1[] = {
>> + ? ? 600000, ? 625000, ?650000, ?675000, ?700000, ?725000,
>> + ? ? 750000, ? 775000, ?800000, ?825000, ?850000, ?875000,
>> + ? ? 900000, ? 925000, ?950000, ?975000, 1000000, 1025000,
>> + ? ? 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
>> + ? ? 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
>> + ? ? 1350000, 1375000
>> +};
>> +
>> +static const int mc13892_sw[] = {
>> + ? ? 600000, ? 625000, ?650000, ?675000, ?700000, ?725000,
>> + ? ? 750000, ? 775000, ?800000, ?825000, ?850000, ?875000,
>> + ? ? 900000, ? 925000, ?950000, ?975000, 1000000, 1025000,
>> + ? ? 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
>> + ? ? 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
>> + ? ? 1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
>> + ? ? 1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
>> + ? ? 1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
>> + ? ? 1800000, 1825000, 1850000, 1875000
>> +};
>> +
>> +static const int mc13892_swbst[] = {
>> + ? ? 5000000,
>> +};
>> +
>> +static const int mc13892_viohi[] = {
>> + ? ? 2775000,
>> +};
>> +
>> +static const int mc13892_vpll[] = {
>> + ? ? 1050000, 1250000, 1650000, 1800000,
>> +};
>> +
>> +static const int mc13892_vdig[] = {
>> + ? ? 1050000, 1250000, 1650000, 1800000,
>> +};
>> +
>> +static const int mc13892_vsd[] = {
>> + ? ? 1800000, 2000000, 2600000, 2700000,
>> + ? ? 2800000, 2900000, 3000000, 3150000,
>> +};
>> +
>> +static const int mc13892_vusb2[] = {
>> + ? ? 2400000, 2600000, 2700000, 2775000,
>> +};
>> +
>> +static const int mc13892_vvideo[] = {
>> + ? ? 2500000, 2600000, 270000, 2775000,
>> +};
>> +
>> +static const int mc13892_vaudio[] = {
>> + ? ? 2300000, 2500000, 2775000, 3000000,
>> +};
>> +
>> +static const int mc13892_vcam[] = {
>> + ? ? 2500000, 2600000, 2750000, 3000000,
>> +};
>> +
>> +static const int mc13892_vgen1[] = {
>> + ? ? 1200000, 1500000, 2775000, 3150000,
>> +};
>> +
>> +static const int mc13892_vgen2[] = {
>> + ? ? 1200000, 1500000, 1600000, 1800000,
>> + ? ? 2700000, 2800000, 3000000, 3150000,
>> +};
>> +
>> +static const int mc13892_vgen3[] = {
>> + ? ? 1800000, 2900000,
>> +};
>> +
>> +static const int mc13892_vusb[] = {
>> + ? ? 3300000,
>> +};
>> +
>> +static const int mc13892_gpo[] = {
>> + ? ? 2750000,
>> +};
>> +
>> +static const int mc13892_pwgtdrv[] = {
>> + ? ? 5000000,
>> +};
>> +
>> +static struct regulator_ops mc13892_gpo_regulator_ops;
>> +/* sw regulators need special care due to the "hi bit" */
>> +static struct regulator_ops mc13892_sw_regulator_ops;
>> +
>> +
>> +#define MC13892_FIXED_DEFINE(name, reg, voltages)\
>> + ? ? MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13xxx_fixed_regulator_ops)
>> +
>> +#define MC13892_GPO_DEFINE(name, reg, voltages) ? ? ? ? ? ? ?\
>> + ? ? MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13892_gpo_regulator_ops)
>> +
>> +#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages) ? ? ? ? ? ? \
>> + ? ? MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13892_sw_regulator_ops)
>> +
>> +#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages) ? ? ? ? ? \
>> + ? ? MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
>> + ? ? ? ? ? ? ? ? ? ? mc13xxx_regulator_ops)
>> +
>> +static struct mc13xxx_regulator mc13892_regulators[] = {
>> + ? ? MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, ? ? ? ? ? ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vcoincell),
>> + ? ? MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1),
>> + ? ? MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw),
>> + ? ? MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw),
>> + ? ? MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw),
>> + ? ? MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst),
>> + ? ? MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi),
>> + ? ? MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0, ? ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vpll),
>> + ? ? MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, ? ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vdig),
>> + ? ? MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1, ? ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vsd),
>> + ? ? MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vusb2),
>> + ? ? MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1, ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vvideo),
>> + ? ? MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1, ?\
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vaudio),
>> + ? ? MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vcam),
>> + ? ? MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vgen1),
>> + ? ? MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vgen2),
>> + ? ? MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0, ? \
>> + ? ? ? ? ? ? ? ? ? ? ? ? mc13892_vgen3),
>> + ? ? MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb),
>> + ? ? MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo),
>> + ? ? MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv),
>> + ? ? MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv),
>> +};
>> +
>> +int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 val)
>> +{
>> + ? ? struct mc13xxx *mc13892 = priv->mc13xxx;
>> + ? ? int ret;
>> + ? ? u32 valread;
>> +
>> + ? ? BUG_ON(val & ~mask);
>> +
>> + ? ? ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? /* Update the stored state for Power Gates. */
>> + ? ? priv->powermisc_pwgt_state =
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (priv->powermisc_pwgt_state & ~mask) | val;
>> + ? ? priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M;
>> +
>> + ? ? /* Construct the new register value */
>> + ? ? valread = (valread & ~mask) | val;
>> + ? ? /* Overwrite the PWGTxEN with the stored version */
>> + ? ? valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? priv->powermisc_pwgt_state;
>> +
>> + ? ? return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
>> +}
>> +
>> +static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int id = rdev_get_id(rdev);
>> + ? ? int ret;
>> + ? ? u32 en_val = mc13892_regulators[id].enable_bit;
>> + ? ? u32 mask = mc13892_regulators[id].enable_bit;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
>> +
>> + ? ? /* Power Gate enable value is 0 */
>> + ? ? if (id == MC13892_PWGT1SPI ||
>> + ? ? ? ? id == MC13892_PWGT2SPI)
>> + ? ? ? ? ? ? en_val = 0;
>> +
>> + ? ? if (id == MC13892_GPO4)
>> + ? ? ? ? ? ? mask |= MC13892_POWERMISC_GPO4ADINEN;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13892_powermisc_rmw(priv, mask, en_val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int id = rdev_get_id(rdev);
>> + ? ? int ret;
>> + ? ? u32 dis_val = 0;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
>> +
>> + ? ? /* Power Gate disable value is 1 */
>> + ? ? if (id == MC13892_PWGT1SPI ||
>> + ? ? ? ? id == MC13892_PWGT2SPI)
>> + ? ? ? ? ? ? dis_val = mc13892_regulators[id].enable_bit;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dis_val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> + ? ? unsigned int val;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? /* Power Gates state is stored in powermisc_pwgt_state
>> + ? ? ?* where the meaning of bits is negated */
>> + ? ? val = (val & ~MC13892_POWERMISC_PWGTSPI_M) |
>> + ? ? ? ? ? (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M);
>> +
>> + ? ? return (val & mc13892_regulators[id].enable_bit) != 0;
>> +}
>> +
>> +
>> +static struct regulator_ops mc13892_gpo_regulator_ops = {
>> + ? ? .enable = mc13892_gpo_regulator_enable,
>> + ? ? .disable = mc13892_gpo_regulator_disable,
>> + ? ? .is_enabled = mc13892_gpo_regulator_is_enabled,
>> + ? ? .list_voltage = mc13xxx_regulator_list_voltage,
>> + ? ? .set_voltage = mc13xxx_fixed_regulator_set_voltage,
>> + ? ? .get_voltage = mc13xxx_fixed_regulator_get_voltage,
>> +};
>> +
>> +static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> + ? ? unsigned int val, hi;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13892_regulators[id].vsel_reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? hi ?= val & MC13892_SWITCHERS0_SWxHI;
>> + ? ? val = (val & mc13892_regulators[id].vsel_mask)
>> + ? ? ? ? ? ? >> mc13892_regulators[id].vsel_shift;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
>> +
>> + ? ? if (hi)
>> + ? ? ? ? ? ? val = (25000 * val) + 1100000;
>> + ? ? else
>> + ? ? ? ? ? ? val = (25000 * val) + 600000;
>> +
>> + ? ? return val;
>> +}
>> +
>> +static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int min_uV, int max_uV)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int hi, value, val, mask, id = rdev_get_id(rdev);
>> + ? ? int ret;
>> +
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
>> + ? ? ? ? ? ? __func__, id, min_uV, max_uV);
>> +
>> + ? ? /* Find the best index */
>> + ? ? value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
>> + ? ? dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
>> + ? ? if (value < 0)
>> + ? ? ? ? ? ? return value;
>> +
>> + ? ? value = mc13892_regulators[id].voltages[value];
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13892_regulators[id].vsel_reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? hi ?= val & MC13892_SWITCHERS0_SWxHI;
>> + ? ? if (value > 1375)
>> + ? ? ? ? ? ? hi = 1;
>> + ? ? if (value < 1100)
>> + ? ? ? ? ? ? hi = 0;
>> +
>> + ? ? if (hi) {
>> + ? ? ? ? ? ? value = (value - 1100000) / 25000;
>> + ? ? ? ? ? ? value |= MC13892_SWITCHERS0_SWxHI;
>> + ? ? } else
>> + ? ? ? ? ? ? value = (value - 600000) / 25000;
>> +
>> + ? ? mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
>> + ? ? ? ? ? ? ? ? ? ? mask,
>> + ? ? ? ? ? ? ? ? ? ? value << mc13892_regulators[id].vsel_shift);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static struct regulator_ops mc13892_sw_regulator_ops = {
>> + ? ? .is_enabled = mc13xxx_sw_regulator_is_enabled,
>> + ? ? .list_voltage = mc13xxx_regulator_list_voltage,
>> + ? ? .set_voltage = mc13892_sw_regulator_set_voltage,
>> + ? ? .get_voltage = mc13892_sw_regulator_get_voltage,
>> +};
>> +
>> +static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
>> +{
>> + ? ? unsigned int en_val = 0;
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> +
>> + ? ? if (mode == REGULATOR_MODE_FAST)
>> + ? ? ? ? ? ? en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_REGULATORMODE1_VCAMCONFIGEN,
>> + ? ? ? ? ? ? ? ? ? ? en_val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
>> + ? ? int ret, id = rdev_get_id(rdev);
>> + ? ? unsigned int val;
>> +
>> + ? ? mc13xxx_lock(priv->mc13xxx);
>> + ? ? ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
>> + ? ? mc13xxx_unlock(priv->mc13xxx);
>> +
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return ret;
>> +
>> + ? ? if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN)
>> + ? ? ? ? ? ? return REGULATOR_MODE_FAST;
>> +
>> + ? ? return REGULATOR_MODE_NORMAL;
>> +}
>> +
>> +
>> +static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv;
>> + ? ? struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
>> + ? ? struct mc13xxx_regulator_platform_data *pdata =
>> + ? ? ? ? ? ? dev_get_platdata(&pdev->dev);
>> + ? ? struct mc13xxx_regulator_init_data *init_data;
>> + ? ? int i, ret;
>> + ? ? u32 val;
>> +
>> + ? ? priv = kzalloc(sizeof(*priv) +
>> + ? ? ? ? ? ? ? ? ? ? pdata->num_regulators * sizeof(priv->regulators[0]),
>> + ? ? ? ? ? ? ? ? ? ? GFP_KERNEL);
>> + ? ? if (!priv)
>> + ? ? ? ? ? ? return -ENOMEM;
>> +
>> + ? ? priv->mc13xxx_regulators = mc13892_regulators;
>> + ? ? priv->mc13xxx = mc13892;
>> +
>> + ? ? mc13xxx_lock(mc13892);
>> + ? ? ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val);
>> + ? ? mc13xxx_unlock(mc13892);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? goto err_alloc;
> err_alloc looks wrong
>
>> +
>> + ? ? /* enable switch auto mode - ENGR00120510, ENGR00121057 */
>> + ? ? /* no doc with regs description means no way to know if */
>> + ? ? /* there's a better way to do it ? ? ? ? ? ? ? ? ? ? ? ?*/
> This is an unusual commenting style. ?Please use
>
> ? ? ? ?/*
> ? ? ? ? * enable switch auto mode ...
> ? ? ? ? */
>
>> + ? ? if ((val & 0x0000FFFF) == 0x45d0) {
>> + ? ? ? ? ? ? mc13xxx_lock(mc13892);
>> + ? ? ? ? ? ? ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW1MODE_M |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW2MODE_M,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW1MODE_AUTO |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW2MODE_AUTO);
>> + ? ? ? ? ? ? mc13xxx_unlock(mc13892);
> It should be possible to hold the lock for longer that a single mc13xxx
> API call. ?Your error handler just needs to unlock for that.
I found this can not work, since regulator_register in probe function
will in turn call regulator ops->enable or alike, which require
mc13xxx_lock again. So we do not use long lock here.
>
>> + ? ? ? ? ? ? if (ret)
>> + ? ? ? ? ? ? ? ? ? ? goto err_alloc;
>> +
>> + ? ? ? ? ? ? mc13xxx_lock(mc13892);
>> + ? ? ? ? ? ? mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW3MODE_M |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW4MODE_M,
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW3MODE_AUTO |
>> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS5_SW4MODE_AUTO);
>> + ? ? ? ? ? ? mc13xxx_unlock(mc13892);
>> + ? ? ? ? ? ? if (ret)
>> + ? ? ? ? ? ? ? ? ? ? goto err_alloc;
>> + ? ? }
>> +
>> + ? ? mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
>> + ? ? ? ? ? ? = mc13892_vcam_set_mode;
>> + ? ? mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
>> + ? ? ? ? ? ? = mc13892_vcam_get_mode;
>> + ? ? for (i = 0; i < pdata->num_regulators; i++) {
>> + ? ? ? ? ? ? init_data = &pdata->regulators[i];
>> + ? ? ? ? ? ? priv->regulators[i] = regulator_register(
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? &mc13892_regulators[init_data->id].desc,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? &pdev->dev, init_data->init_data, priv);
>> +
>> + ? ? ? ? ? ? if (IS_ERR(priv->regulators[i])) {
>> + ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to register regulator %s\n",
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13892_regulators[i].desc.name);
>> + ? ? ? ? ? ? ? ? ? ? ret = PTR_ERR(priv->regulators[i]);
>> + ? ? ? ? ? ? ? ? ? ? goto err;
>> + ? ? ? ? ? ? }
>> + ? ? }
>> +
>> + ? ? platform_set_drvdata(pdev, priv);
>> +
>> + ? ? return 0;
>> +err:
>> + ? ? while (--i >= 0)
>> + ? ? ? ? ? ? regulator_unregister(priv->regulators[i]);
>> +
>> +err_alloc:
>> + ? ? kfree(priv);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
>> +{
>> + ? ? struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
>> + ? ? struct mc13xxx_regulator_platform_data *pdata =
>> + ? ? ? ? ? ? dev_get_platdata(&pdev->dev);
>> + ? ? int i;
>> +
>> + ? ? platform_set_drvdata(pdev, NULL);
>> +
>> + ? ? for (i = 0; i < pdata->num_regulators; i++)
>> + ? ? ? ? ? ? regulator_unregister(priv->regulators[i]);
>> +
>> + ? ? kfree(priv);
>> + ? ? return 0;
>> +}
>> +
>> +static struct platform_driver mc13892_regulator_driver = {
>> + ? ? .driver = {
>> + ? ? ? ? ? ? .name ? = "mc13892-regulator",
>> + ? ? ? ? ? ? .owner ?= THIS_MODULE,
>> + ? ? },
>> + ? ? .remove ? ? ? ? = __devexit_p(mc13892_regulator_remove),
>> + ? ? .probe ? ? ? ? ?= mc13892_regulator_probe,
> If you ask me just use a single space before =, but there is no common
> style visible in the kernel, so do as you prefer.
> (The advantage of using a single space is that if later
> .averylongmembername needs to be initialized you either have to fix
> lines that are technically unrelated or the indention isn't uniform.)
>
> Best regards
> Uwe
>
>> +};
>> +
>> +static int __init mc13892_regulator_init(void)
>> +{
>> + ? ? return platform_driver_register(&mc13892_regulator_driver);
>> +}
>> +subsys_initcall(mc13892_regulator_init);
>> +
>> +static void __exit mc13892_regulator_exit(void)
>> +{
>> + ? ? platform_driver_unregister(&mc13892_regulator_driver);
>> +}
>> +module_exit(mc13892_regulator_exit);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
>> +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC");
>> +MODULE_ALIAS("platform:mc13892-regulator");
>> diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h
>> new file mode 100644
>> index 0000000..7df13e8
>> --- /dev/null
>> +++ b/include/linux/mfd/mc13892.h
>> @@ -0,0 +1,38 @@
>> +/*
>> + * Copyright 2010 Yong Shen <yong.shen@linaro.org>
>> + *
>> + * 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 __LINUX_MFD_MC13892_H
>> +#define __LINUX_MFD_MC13892_H
>> +#include <linux/mfd/mc13xxx.h>
>> +
>> +#define MC13892_SW1 ? ? ? ? ?0
>> +#define MC13892_SW2 ? ? ? ? ?1
>> +#define MC13892_SW3 ? ? ? ? ?2
>> +#define MC13892_SW4 ? ? ? ? ?3
>> +#define MC13892_SWBST ? ? ? ?4
>> +#define MC13892_VIOHI ? ? ? ?5
>> +#define MC13892_VPLL 6
>> +#define MC13892_VDIG 7
>> +#define MC13892_VSD ?8
>> +#define MC13892_VUSB2 ? ? ? ?9
>> +#define MC13892_VVIDEO ? ? ? 10
>> +#define MC13892_VAUDIO ? ? ? 11
>> +#define MC13892_VCAM 12
>> +#define MC13892_VGEN1 ? ? ? ?13
>> +#define MC13892_VGEN2 ? ? ? ?14
>> +#define MC13892_VGEN3 ? ? ? ?15
>> +#define MC13892_VUSB 16
>> +#define MC13892_GPO1 17
>> +#define MC13892_GPO2 18
>> +#define MC13892_GPO3 19
>> +#define MC13892_GPO4 20
>> +#define MC13892_PWGT1SPI ? ? 21
>> +#define MC13892_PWGT2SPI ? ? 22
>> +#define MC13892_VCOINCELL ? ?23
>> +
>> +#endif
>> --
>> 1.7.0.4
>
> --
> Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | Uwe Kleine-K?nig ? ? ? ? ? ?|
> Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
>

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

* [PATCH] support PMIC mc13892
  2010-12-07  7:57   ` Yong Shen
@ 2010-12-07  8:02     ` Uwe Kleine-König
  0 siblings, 0 replies; 21+ messages in thread
From: Uwe Kleine-König @ 2010-12-07  8:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Yong,

On Tue, Dec 07, 2010 at 03:57:12PM +0800, Yong Shen wrote:
> 2010/12/6 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> >> + ? ? if ((val & 0x0000FFFF) == 0x45d0) {
> >> + ? ? ? ? ? ? mc13xxx_lock(mc13892);
> >> + ? ? ? ? ? ? ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
> >> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW1MODE_M |
> >> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW2MODE_M,
> >> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW1MODE_AUTO |
> >> + ? ? ? ? ? ? ? ? ? ? MC13892_SWITCHERS4_SW2MODE_AUTO);
> >> + ? ? ? ? ? ? mc13xxx_unlock(mc13892);
> > It should be possible to hold the lock for longer that a single mc13xxx
> > API call. ?Your error handler just needs to unlock for that.
> I found this can not work, since regulator_register in probe function
> will in turn call regulator ops->enable or alike, which require
> mc13xxx_lock again. So we do not use long lock here.
You probably cannot only take the lock once per function, but here for
these two mc13xxx_reg_rmw it should be possible.

> >> [...]
> >> +
> >> +static struct platform_driver mc13892_regulator_driver = {
> >> + ? ? .driver = {
> >> + ? ? ? ? ? ? .name ? = "mc13892-regulator",
> >> + ? ? ? ? ? ? .owner ?= THIS_MODULE,
> >> + ? ? },
> >> + ? ? .remove ? ? ? ? = __devexit_p(mc13892_regulator_remove),
> >> + ? ? .probe ? ? ? ? ?= mc13892_regulator_probe,
> > If you ask me just use a single space before =, but there is no common
> > style visible in the kernel, so do as you prefer.
> > (The advantage of using a single space is that if later
> > .averylongmembername needs to be initialized you either have to fix
> > lines that are technically unrelated or the indention isn't uniform.)
BTW, using tabs you get a mixture, too.  Then some =s are aligned, some
don't.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-07  7:14   ` [PATCH] Added i2c support for mc13xxx-core Marc Reilly
@ 2010-12-07  8:32     ` Yong Shen
  2010-12-07 10:09       ` Marc Reilly
  2010-12-08  6:24     ` Yong Shen
  1 sibling, 1 reply; 21+ messages in thread
From: Yong Shen @ 2010-12-07  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

What's your code base? I can not apply your patch.
You may also want to cc directly to u.kleine-koenig at pengutronix.de,
sameo at linux.intel.com who are the module owner of mc13xxx-core.c.

Cheers
Yong

On Tue, Dec 7, 2010 at 3:14 PM, Marc Reilly <marc@cpdesign.com.au> wrote:
> ---
> ?drivers/mfd/mc13xxx-core.c | ?332 +++++++++++++++++++++++++++++++-------------
> ?1 files changed, 234 insertions(+), 98 deletions(-)
>
> diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
> index a2ac2ed..229cf43 100644
> --- a/drivers/mfd/mc13xxx-core.c
> +++ b/drivers/mfd/mc13xxx-core.c
> @@ -9,7 +9,6 @@
> ?* 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>
> @@ -18,12 +17,28 @@
> ?#include <linux/spi/spi.h>
> ?#include <linux/mfd/core.h>
> ?#include <linux/mfd/mc13xxx.h>
> +#include <linux/i2c.h>
> +
> +enum mc13xxx_id {
> + ? ? ? MC13XXX_ID_MC13783,
> + ? ? ? MC13XXX_ID_MC13892,
> + ? ? ? MC13XXX_ID_INVALID,
> +};
>
> ?struct mc13xxx {
> - ? ? ? struct spi_device *spidev;
> + ? ? ? union {
> + ? ? ? ? ? ? ? struct spi_device *spidev;
> + ? ? ? ? ? ? ? struct i2c_client* client;
> + ? ? ? };
> + ? ? ? struct device *pdev;
> + ? ? ? enum mc13xxx_id icid;
> +
> ? ? ? ?struct mutex lock;
> ? ? ? ?int irq;
>
> + ? ? ? int (*read_dev)(struct mc13xxx*, unsigned int, u32*);
> + ? ? ? int (*write_dev)(struct mc13xxx*, unsigned int, u32);
> +
> ? ? ? ?irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
> ? ? ? ?void *irqdata[MC13XXX_NUM_IRQ];
> ?};
> @@ -150,36 +165,46 @@ EXPORT_SYMBOL(mc13783_to_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->pdev, "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->pdev, "%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->pdev, "%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));
>
> ? ? ? ?if (offset > MC13XXX_NUMREGS)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> + ? ? ? ret = mc13xxx->read_dev(mc13xxx, offset, val);
> + ? ? ? dev_vdbg(mc13xxx->pdev, "[0x%02x] -> 0x%06x\n", offset, *val);
> +
> + ? ? ? return ret;
> +}
> +EXPORT_SYMBOL(mc13xxx_reg_read);
> +
> +#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));
> @@ -201,26 +226,28 @@ 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)
> ?{
> - ? ? ? 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);
> + ? ? ? dev_vdbg(mc13xxx->pdev, "[0x%02x] <- 0x%06x\n", offset, val);
>
> ? ? ? ?if (offset > MC13XXX_NUMREGS || val > 0xffffff)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> + ? ? ? return mc13xxx->write_dev(mc13xxx, offset, val);
> +}
> +EXPORT_SYMBOL(mc13xxx_reg_write);
> +
> +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));
> @@ -241,7 +268,33 @@ int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
>
> ? ? ? ?return 0;
> ?}
> -EXPORT_SYMBOL(mc13xxx_reg_write);
> +
> +static int mc13xxx_i2c_reg_read(struct mc13xxx *mc13xxx, unsigned int offset,
> + ? ? ? ? ? ? ? u32 *val)
> +{
> + ? ? ? int ret;
> + ? ? ? unsigned char buff[3] = {0,0,0};
> +
> + ? ? ? ret = i2c_smbus_read_i2c_block_data(mc13xxx->client, offset, 3, buff);
> + ? ? ? *val = buff[0] << 16 | buff[1] << 8 | buff[2];
> +
> + ? ? ? return ret == 3 ? 0 : ret;
> +}
> +
> +static int mc13xxx_i2c_reg_write(struct mc13xxx *mc13xxx, unsigned int offset,
> + ? ? ? ? ? ? ? u32 val)
> +{
> + ? ? ? int ret;
> + ? ? ? unsigned char buff[3];
> +
> + ? ? ? buff[0] = (val >> 16) & 0xff;
> + ? ? ? buff[1] = (val >> 8) & 0xff;
> + ? ? ? buff[2] = val & 0xff;
> +
> + ? ? ? ret = i2c_smbus_write_i2c_block_data(mc13xxx->client, offset, 3, buff);
> +
> + ? ? ? return ret;
> +}
>
> ?int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
> ? ? ? ? ? ? ? ?u32 mask, u32 val)
> @@ -445,7 +498,7 @@ static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx,
> ? ? ? ? ? ? ? ? ? ? ? ?if (handled == IRQ_HANDLED)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_handled++;
> ? ? ? ? ? ? ? ?} else {
> - ? ? ? ? ? ? ? ? ? ? ? dev_err(&mc13xxx->spidev->dev,
> + ? ? ? ? ? ? ? ? ? ? ? dev_err(mc13xxx->pdev,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"BUG: irq %u but no handler\n",
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?baseirq + irq);
>
> @@ -481,11 +534,6 @@ 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,
> -};
>
> ?const char *mc13xxx_chipname[] = {
> ? ? ? ?[MC13XXX_ID_MC13783] = "mc13783",
> @@ -493,41 +541,38 @@ const char *mc13xxx_chipname[] = {
> ?};
>
> ?#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, int usespi)
> ?{
> ? ? ? ?u32 icid;
> ? ? ? ?u32 revision;
> ? ? ? ?const char *name;
> ? ? ? ?int ret;
>
> - ? ? ? ret = mc13xxx_reg_read(mc13xxx, 46, &icid);
> + ? ? ? ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
> ? ? ? ?if (ret)
> ? ? ? ? ? ? ? ?return ret;
>
> - ? ? ? icid = (icid >> 6) & 0x7;
> + ? ? ? icid = (revision >> 6) & 0x7;
>
> ? ? ? ?switch (icid) {
> ? ? ? ?case 2:
> - ? ? ? ? ? ? ? *id = MC13XXX_ID_MC13783;
> + ? ? ? ? ? ? ? mc13xxx->icid = MC13XXX_ID_MC13783;
> ? ? ? ? ? ? ? ?name = "mc13783";
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?case 7:
> - ? ? ? ? ? ? ? *id = MC13XXX_ID_MC13892;
> + ? ? ? ? ? ? ? mc13xxx->icid = MC13XXX_ID_MC13892;
> ? ? ? ? ? ? ? ?name = "mc13892";
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?default:
> - ? ? ? ? ? ? ? *id = MC13XXX_ID_INVALID;
> + ? ? ? ? ? ? ? mc13xxx->icid = MC13XXX_ID_INVALID;
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
>
> - ? ? ? if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) {
> - ? ? ? ? ? ? ? ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
> - ? ? ? ? ? ? ? if (ret)
> - ? ? ? ? ? ? ? ? ? ? ? return ret;
> -
> - ? ? ? ? ? ? ? dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, "
> + ? ? ? if (mc13xxx->icid == MC13XXX_ID_MC13783 ||
> + ? ? ? ? ? ? ? ? ? ? ? mc13xxx->icid == MC13XXX_ID_MC13892) {
> + ? ? ? ? ? ? ? dev_info(mc13xxx->pdev, "%s: rev: %d.%d, "
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"fin: %d, fab: %d, icid: %d/%d\n",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13xxx_chipname[*id],
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13xxx_chipname[mc13xxx->icid],
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_REVFULL),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_REVMETAL),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_FIN),
> @@ -535,27 +580,23 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_ICID),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?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");
> + ? ? ? if (mc13xxx->icid != MC13XXX_ID_INVALID) {
> + ? ? ? ? ? ? ? if (usespi) {
> + ? ? ? ? ? ? ? ? ? ? ? const struct spi_device_id *devid =
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spi_get_device_id(mc13xxx->spidev);
> + ? ? ? ? ? ? ? ? ? ? ? if (!devid || devid->driver_data != mc13xxx->icid)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_warn(mc13xxx->pdev, "device id doesn't "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "match auto detection!\n");
> + ? ? ? ? ? ? ? } else {
> + ? ? ? ? ? ? ? ? ? ? ? /* TODO */
> + ? ? ? ? ? ? ? }
> ? ? ? ?}
> -
> ? ? ? ?return 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->icid];
> ?}
>
> ?#include <linux/mfd/mc13783.h>
> @@ -563,7 +604,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
> ?int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
> ?{
> ? ? ? ?struct mc13xxx_platform_data *pdata =
> - ? ? ? ? ? ? ? dev_get_platdata(&mc13xxx->spidev->dev);
> + ? ? ? ? ? ? ? dev_get_platdata(mc13xxx->pdev);
>
> ? ? ? ?return pdata->flags;
> ?}
> @@ -601,7 +642,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
> ? ? ? ?};
> ? ? ? ?init_completion(&adcdone_data.done);
>
> - ? ? ? dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__);
> + ? ? ? dev_dbg(mc13xxx->pdev, "%s\n", __func__);
>
> ? ? ? ?mc13xxx_lock(mc13xxx);
>
> @@ -643,7 +684,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?}
>
> - ? ? ? dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__);
> + ? ? ? dev_dbg(mc13783->mc13xxx.pdev, "%s: request irq\n", __func__);
> ? ? ? ?mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE,
> ? ? ? ? ? ? ? ? ? ? ? ?mc13783_handler_adcdone, __func__, &adcdone_data);
> ? ? ? ?mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE);
> @@ -701,7 +742,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->pdev, -1, &cell, 1, NULL, 0);
> ?}
>
> ?static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
> @@ -709,11 +750,48 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
> ? ? ? ?return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
> ?}
>
> -static int mc13xxx_probe(struct spi_device *spi)
> +static int mc13xxx_common_probe(struct mc13xxx* mc13xxx,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct mc13xxx_platform_data* pdata)
> +{
> + ? ? ? mc13xxx_unlock(mc13xxx);
> +
> + ? ? ? if (!pdata)
> + ? ? ? ? ? ? ? return 0;
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_ADC)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-adc");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_CODEC)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-codec");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_REGULATOR) {
> + ? ? ? ? ? ? ? struct mc13xxx_regulator_platform_data regulator_pdata = {
> + ? ? ? ? ? ? ? ? ? ? ? .num_regulators = pdata->num_regulators,
> + ? ? ? ? ? ? ? ? ? ? ? .regulators = pdata->regulators,
> + ? ? ? ? ? ? ? };
> +
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &regulator_pdata, sizeof(regulator_pdata));
> + ? ? ? }
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_RTC)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-ts");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_LED) {
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pdata->leds, sizeof(*pdata->leds));
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +
> +static int mc13xxx_spi_probe(struct spi_device *spi)
> ?{
> ? ? ? ?struct mc13xxx *mc13xxx;
> ? ? ? ?struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
> - ? ? ? enum mc13xxx_id id;
> ? ? ? ?int ret;
>
> ? ? ? ?mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
> @@ -725,13 +803,17 @@ static int mc13xxx_probe(struct spi_device *spi)
> ? ? ? ?spi->bits_per_word = 32;
> ? ? ? ?spi_setup(spi);
>
> + ? ? ? mc13xxx->pdev = &spi->dev;
> ? ? ? ?mc13xxx->spidev = spi;
> + ? ? ? mc13xxx->read_dev = mc13xxx_spi_reg_read;
> + ? ? ? mc13xxx->write_dev = mc13xxx_spi_reg_write;
> + ? ? ? mc13xxx->irq = spi->irq;
>
> ? ? ? ?mutex_init(&mc13xxx->lock);
> ? ? ? ?mc13xxx_lock(mc13xxx);
>
> - ? ? ? ret = mc13xxx_identify(mc13xxx, &id);
> - ? ? ? if (ret || id == MC13XXX_ID_INVALID)
> + ? ? ? ret = mc13xxx_identify(mc13xxx, 1);
> + ? ? ? if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
> ? ? ? ? ? ? ? ?goto err_revision;
>
> ? ? ? ?/* mask all irqs */
> @@ -743,7 +825,7 @@ 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) {
> @@ -755,43 +837,15 @@ err_revision:
> ? ? ? ? ? ? ? ?return ret;
> ? ? ? ?}
>
> - ? ? ? mc13xxx_unlock(mc13xxx);
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_ADC)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-adc");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_CODEC)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-codec");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_REGULATOR) {
> - ? ? ? ? ? ? ? struct mc13xxx_regulator_platform_data regulator_pdata = {
> - ? ? ? ? ? ? ? ? ? ? ? .num_regulators = pdata->num_regulators,
> - ? ? ? ? ? ? ? ? ? ? ? .regulators = pdata->regulators,
> - ? ? ? ? ? ? ? };
> -
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &regulator_pdata, sizeof(regulator_pdata));
> - ? ? ? }
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_RTC)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-ts");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_LED) {
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pdata->leds, sizeof(*pdata->leds));
> - ? ? ? }
> -
> - ? ? ? return 0;
> + ? ? ? return mc13xxx_common_probe(mc13xxx, pdata);
> ?}
>
> -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);
> + ? ? ? free_irq(mc13xxx->irq, mc13xxx);
>
> ? ? ? ?mfd_remove_devices(&spi->dev);
>
> @@ -819,18 +873,100 @@ static struct spi_driver mc13xxx_driver = {
> ? ? ? ? ? ? ? ?.bus = &spi_bus_type,
> ? ? ? ? ? ? ? ?.owner = THIS_MODULE,
> ? ? ? ?},
> - ? ? ? .probe = mc13xxx_probe,
> - ? ? ? .remove = __devexit_p(mc13xxx_remove),
> + ? ? ? .probe = mc13xxx_spi_probe,
> + ? ? ? .remove = __devexit_p(mc13xxx_spi_remove),
> +};
> +
> +static int mc13xxx_i2c_probe(struct i2c_client *client,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?const struct i2c_device_id* id)
> +{
> + ? ? ? struct mc13xxx *mc13xxx;
> + ? ? ? struct mc13xxx_platform_data *pdata = dev_get_platdata(&client->dev);
> + ? ? ? int ret;
> +
> + ? ? ? mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
> + ? ? ? if (!mc13xxx)
> + ? ? ? ? ? ? ? return -ENOMEM;
> +
> + ? ? ? dev_set_drvdata(&client->dev, mc13xxx);
> + ? ? ? mc13xxx->pdev = &client->dev;
> + ? ? ? mc13xxx->client = client;
> + ? ? ? mc13xxx->read_dev = mc13xxx_i2c_reg_read;
> + ? ? ? mc13xxx->write_dev = mc13xxx_i2c_reg_write;
> + ? ? ? mc13xxx->irq = client->irq;
> +
> + ? ? ? mutex_init(&mc13xxx->lock);
> + ? ? ? mc13xxx_lock(mc13xxx);
> +
> + ? ? ? ret = mc13xxx_identify(mc13xxx, 0);
> + ? ? ? if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
> + ? ? ? ? ? ? ? goto err_revision;
> +
> + ? ? ? /* mask all irqs */
> + ? ? ? ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? goto err_mask;
> +
> + ? ? ? ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? goto err_mask;
> +
> + ? ? ? ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread,
> + ? ? ? ? ? ? ? ? ? ? ? IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
> +
> + ? ? ? if (ret) {
> +err_mask:
> +err_revision:
> + ? ? ? ? ? ? ? mutex_unlock(&mc13xxx->lock);
> + ? ? ? ? ? ? ? kfree(mc13xxx);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? return mc13xxx_common_probe(mc13xxx,pdata);
> +}
> +
> +static int __devexit mc13xxx_i2c_remove(struct i2c_client *client)
> +{
> + ? ? ? struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev);
> +
> + ? ? ? free_irq(mc13xxx->irq, mc13xxx);
> +
> + ? ? ? mfd_remove_devices(&client->dev);
> +
> + ? ? ? kfree(mc13xxx);
> +
> + ? ? ? return 0;
> +}
> +
> +static const struct i2c_device_id mc13xxx_i2c_idtable[] = {
> + ? ? ? { "mc13892", MC13XXX_ID_MC13892},
> + ? ? ? { }
> +};
> +
> +static struct i2c_driver mc13xxx_i2c_driver = {
> + ? ? ? .driver = {
> + ? ? ? ? ? ? ? .owner = THIS_MODULE,
> + ? ? ? ? ? ? ? .name = "mc13xxx-i2c"
> + ? ? ? },
> + ? ? ? .id_table = mc13xxx_i2c_idtable,
> + ? ? ? .probe = mc13xxx_i2c_probe,
> + ? ? ? .remove = __devexit_p(mc13xxx_i2c_remove),
> ?};
>
> ?static int __init mc13xxx_init(void)
> ?{
> - ? ? ? return spi_register_driver(&mc13xxx_driver);
> + ? ? ? int i2cret;
> + ? ? ? int spiret;
> + ? ? ? i2cret = i2c_add_driver(&mc13xxx_i2c_driver);
> + ? ? ? spiret = spi_register_driver(&mc13xxx_driver);
> +
> + ? ? ? return (i2cret == 0) && (spiret == 0);
> ?}
> ?subsys_initcall(mc13xxx_init);
>
> ?static void __exit mc13xxx_exit(void)
> ?{
> + ? ? ? i2c_del_driver(&mc13xxx_i2c_driver);
> ? ? ? ?spi_unregister_driver(&mc13xxx_driver);
> ?}
> ?module_exit(mc13xxx_exit);
> --
> 1.7.1
>
>

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-07  8:32     ` Yong Shen
@ 2010-12-07 10:09       ` Marc Reilly
  0 siblings, 0 replies; 21+ messages in thread
From: Marc Reilly @ 2010-12-07 10:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

> What's your code base? I can not apply your patch.

I'm sorry, I'm not very good with git.
I'm working off the imx-for-2.6.38 branch (is that what you were asking?)

> You may also want to cc directly to u.kleine-koenig at pengutronix.de,
> sameo at linux.intel.com who are the module owner of mc13xxx-core.c.
Thanks for the heads up. CC'd them to this email, hopefully not too much 
effort to find my previous email(s) on the list. :) I welcome any comments 
before doing a V2 (a re-submit is obviously required anyway).

> 
> Cheers
> Yong

Thanks to you. 
At least this exercise has shown that your regulator code works for mc13892. I 
added all but VVIDEO, VAUDIO, VCAM and VCOINCELL to my board and the reported 
voltages for each reg were correct.

Cheers
Marc

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-07  7:14   ` [PATCH] Added i2c support for mc13xxx-core Marc Reilly
  2010-12-07  8:32     ` Yong Shen
@ 2010-12-08  6:24     ` Yong Shen
  2010-12-08  8:07       ` Marc Reilly
  1 sibling, 1 reply; 21+ messages in thread
From: Yong Shen @ 2010-12-08  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

It's better to use git format-patch to gernerate patch for review, by
which you can add some commit information and s-o-b stuff.
Please see inline comments.

On Tue, Dec 7, 2010 at 3:14 PM, Marc Reilly <marc@cpdesign.com.au> wrote:
> ---
> ?drivers/mfd/mc13xxx-core.c | ?332 +++++++++++++++++++++++++++++++-------------
> ?1 files changed, 234 insertions(+), 98 deletions(-)
>
> diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
> index a2ac2ed..229cf43 100644
> --- a/drivers/mfd/mc13xxx-core.c
> +++ b/drivers/mfd/mc13xxx-core.c
> @@ -9,7 +9,6 @@
> ?* 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>
> @@ -18,12 +17,28 @@
> ?#include <linux/spi/spi.h>
> ?#include <linux/mfd/core.h>
> ?#include <linux/mfd/mc13xxx.h>
> +#include <linux/i2c.h>
> +
> +enum mc13xxx_id {
> + ? ? ? MC13XXX_ID_MC13783,
> + ? ? ? MC13XXX_ID_MC13892,
> + ? ? ? MC13XXX_ID_INVALID,
> +};
>
> ?struct mc13xxx {
> - ? ? ? struct spi_device *spidev;
> + ? ? ? union {
> + ? ? ? ? ? ? ? struct spi_device *spidev;
> + ? ? ? ? ? ? ? struct i2c_client* client;
> + ? ? ? };
> + ? ? ? struct device *pdev;
> + ? ? ? enum mc13xxx_id icid;
> +
> ? ? ? ?struct mutex lock;
> ? ? ? ?int irq;
>
> + ? ? ? int (*read_dev)(struct mc13xxx*, unsigned int, u32*);
> + ? ? ? int (*write_dev)(struct mc13xxx*, unsigned int, u32);
> +
> ? ? ? ?irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
> ? ? ? ?void *irqdata[MC13XXX_NUM_IRQ];
> ?};
> @@ -150,36 +165,46 @@ EXPORT_SYMBOL(mc13783_to_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->pdev, "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->pdev, "%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->pdev, "%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));
>
> ? ? ? ?if (offset > MC13XXX_NUMREGS)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> + ? ? ? ret = mc13xxx->read_dev(mc13xxx, offset, val);
> + ? ? ? dev_vdbg(mc13xxx->pdev, "[0x%02x] -> 0x%06x\n", offset, *val);
> +
> + ? ? ? return ret;
> +}
> +EXPORT_SYMBOL(mc13xxx_reg_read);
> +
> +#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));
> @@ -201,26 +226,28 @@ 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)
> ?{
> - ? ? ? 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);
> + ? ? ? dev_vdbg(mc13xxx->pdev, "[0x%02x] <- 0x%06x\n", offset, val);
>
> ? ? ? ?if (offset > MC13XXX_NUMREGS || val > 0xffffff)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> + ? ? ? return mc13xxx->write_dev(mc13xxx, offset, val);
> +}
> +EXPORT_SYMBOL(mc13xxx_reg_write);
> +
> +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));
> @@ -241,7 +268,33 @@ int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
>
> ? ? ? ?return 0;
> ?}
> -EXPORT_SYMBOL(mc13xxx_reg_write);
> +
> +static int mc13xxx_i2c_reg_read(struct mc13xxx *mc13xxx, unsigned int offset,
> + ? ? ? ? ? ? ? u32 *val)
> +{
> + ? ? ? int ret;
> + ? ? ? unsigned char buff[3] = {0,0,0};
> +
> + ? ? ? ret = i2c_smbus_read_i2c_block_data(mc13xxx->client, offset, 3, buff);
> + ? ? ? *val = buff[0] << 16 | buff[1] << 8 | buff[2];
> +
> + ? ? ? return ret == 3 ? 0 : ret;
> +}
> +
> +static int mc13xxx_i2c_reg_write(struct mc13xxx *mc13xxx, unsigned int offset,
> + ? ? ? ? ? ? ? u32 val)
> +{
> + ? ? ? int ret;
> + ? ? ? unsigned char buff[3];
> +
> + ? ? ? buff[0] = (val >> 16) & 0xff;
> + ? ? ? buff[1] = (val >> 8) & 0xff;
> + ? ? ? buff[2] = val & 0xff;
> +
> + ? ? ? ret = i2c_smbus_write_i2c_block_data(mc13xxx->client, offset, 3, buff);
> +
> + ? ? ? return ret;
> +}
>
> ?int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
> ? ? ? ? ? ? ? ?u32 mask, u32 val)
> @@ -445,7 +498,7 @@ static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx,
> ? ? ? ? ? ? ? ? ? ? ? ?if (handled == IRQ_HANDLED)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_handled++;
> ? ? ? ? ? ? ? ?} else {
> - ? ? ? ? ? ? ? ? ? ? ? dev_err(&mc13xxx->spidev->dev,
> + ? ? ? ? ? ? ? ? ? ? ? dev_err(mc13xxx->pdev,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"BUG: irq %u but no handler\n",
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?baseirq + irq);
>
> @@ -481,11 +534,6 @@ 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,
> -};
>
> ?const char *mc13xxx_chipname[] = {
> ? ? ? ?[MC13XXX_ID_MC13783] = "mc13783",
> @@ -493,41 +541,38 @@ const char *mc13xxx_chipname[] = {
> ?};
>
> ?#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, int usespi)
> ?{
> ? ? ? ?u32 icid;
> ? ? ? ?u32 revision;
> ? ? ? ?const char *name;
> ? ? ? ?int ret;
>
> - ? ? ? ret = mc13xxx_reg_read(mc13xxx, 46, &icid);
> + ? ? ? ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
> ? ? ? ?if (ret)
> ? ? ? ? ? ? ? ?return ret;
>
> - ? ? ? icid = (icid >> 6) & 0x7;
> + ? ? ? icid = (revision >> 6) & 0x7;
>
> ? ? ? ?switch (icid) {
> ? ? ? ?case 2:
> - ? ? ? ? ? ? ? *id = MC13XXX_ID_MC13783;
> + ? ? ? ? ? ? ? mc13xxx->icid = MC13XXX_ID_MC13783;
> ? ? ? ? ? ? ? ?name = "mc13783";
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?case 7:
> - ? ? ? ? ? ? ? *id = MC13XXX_ID_MC13892;
> + ? ? ? ? ? ? ? mc13xxx->icid = MC13XXX_ID_MC13892;
> ? ? ? ? ? ? ? ?name = "mc13892";
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?default:
> - ? ? ? ? ? ? ? *id = MC13XXX_ID_INVALID;
> + ? ? ? ? ? ? ? mc13xxx->icid = MC13XXX_ID_INVALID;
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
>
> - ? ? ? if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) {
> - ? ? ? ? ? ? ? ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
> - ? ? ? ? ? ? ? if (ret)
> - ? ? ? ? ? ? ? ? ? ? ? return ret;
> -
> - ? ? ? ? ? ? ? dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, "
> + ? ? ? if (mc13xxx->icid == MC13XXX_ID_MC13783 ||
> + ? ? ? ? ? ? ? ? ? ? ? mc13xxx->icid == MC13XXX_ID_MC13892) {
> + ? ? ? ? ? ? ? dev_info(mc13xxx->pdev, "%s: rev: %d.%d, "
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"fin: %d, fab: %d, icid: %d/%d\n",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13xxx_chipname[*id],
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mc13xxx_chipname[mc13xxx->icid],
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_REVFULL),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_REVMETAL),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_FIN),
> @@ -535,27 +580,23 @@ static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?maskval(revision, MC13XXX_REVISION_ICID),
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?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");
> + ? ? ? if (mc13xxx->icid != MC13XXX_ID_INVALID) {
> + ? ? ? ? ? ? ? if (usespi) {
> + ? ? ? ? ? ? ? ? ? ? ? const struct spi_device_id *devid =
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spi_get_device_id(mc13xxx->spidev);
> + ? ? ? ? ? ? ? ? ? ? ? if (!devid || devid->driver_data != mc13xxx->icid)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_warn(mc13xxx->pdev, "device id doesn't "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "match auto detection!\n");
> + ? ? ? ? ? ? ? } else {
> + ? ? ? ? ? ? ? ? ? ? ? /* TODO */

todo what? remove this or add real code here.
> + ? ? ? ? ? ? ? }
> ? ? ? ?}
> -
> ? ? ? ?return 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->icid];
> ?}
>
> ?#include <linux/mfd/mc13783.h>
> @@ -563,7 +604,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
> ?int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
> ?{
> ? ? ? ?struct mc13xxx_platform_data *pdata =
> - ? ? ? ? ? ? ? dev_get_platdata(&mc13xxx->spidev->dev);
> + ? ? ? ? ? ? ? dev_get_platdata(mc13xxx->pdev);
>
> ? ? ? ?return pdata->flags;
> ?}
> @@ -601,7 +642,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
> ? ? ? ?};
> ? ? ? ?init_completion(&adcdone_data.done);
>
> - ? ? ? dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__);
> + ? ? ? dev_dbg(mc13xxx->pdev, "%s\n", __func__);
>
> ? ? ? ?mc13xxx_lock(mc13xxx);
>
> @@ -643,7 +684,7 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?}
>
> - ? ? ? dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__);
> + ? ? ? dev_dbg(mc13783->mc13xxx.pdev, "%s: request irq\n", __func__);
> ? ? ? ?mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE,
> ? ? ? ? ? ? ? ? ? ? ? ?mc13783_handler_adcdone, __func__, &adcdone_data);
> ? ? ? ?mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE);
> @@ -701,7 +742,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->pdev, -1, &cell, 1, NULL, 0);
> ?}
>
> ?static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
> @@ -709,11 +750,48 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
> ? ? ? ?return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
> ?}
>
> -static int mc13xxx_probe(struct spi_device *spi)
> +static int mc13xxx_common_probe(struct mc13xxx* mc13xxx,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct mc13xxx_platform_data* pdata)
> +{
> + ? ? ? mc13xxx_unlock(mc13xxx);
> +
> + ? ? ? if (!pdata)
> + ? ? ? ? ? ? ? return 0;
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_ADC)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-adc");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_CODEC)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-codec");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_REGULATOR) {
> + ? ? ? ? ? ? ? struct mc13xxx_regulator_platform_data regulator_pdata = {
> + ? ? ? ? ? ? ? ? ? ? ? .num_regulators = pdata->num_regulators,
> + ? ? ? ? ? ? ? ? ? ? ? .regulators = pdata->regulators,
> + ? ? ? ? ? ? ? };
> +
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &regulator_pdata, sizeof(regulator_pdata));
> + ? ? ? }
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_RTC)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-ts");
> +
> + ? ? ? if (pdata->flags & MC13XXX_USE_LED) {
> + ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pdata->leds, sizeof(*pdata->leds));
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +
> +static int mc13xxx_spi_probe(struct spi_device *spi)
> ?{
> ? ? ? ?struct mc13xxx *mc13xxx;
> ? ? ? ?struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
> - ? ? ? enum mc13xxx_id id;
> ? ? ? ?int ret;
>
> ? ? ? ?mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
> @@ -725,13 +803,17 @@ static int mc13xxx_probe(struct spi_device *spi)
> ? ? ? ?spi->bits_per_word = 32;
> ? ? ? ?spi_setup(spi);
>
> + ? ? ? mc13xxx->pdev = &spi->dev;
> ? ? ? ?mc13xxx->spidev = spi;
> + ? ? ? mc13xxx->read_dev = mc13xxx_spi_reg_read;
> + ? ? ? mc13xxx->write_dev = mc13xxx_spi_reg_write;
> + ? ? ? mc13xxx->irq = spi->irq;
>
> ? ? ? ?mutex_init(&mc13xxx->lock);
> ? ? ? ?mc13xxx_lock(mc13xxx);
>
> - ? ? ? ret = mc13xxx_identify(mc13xxx, &id);
> - ? ? ? if (ret || id == MC13XXX_ID_INVALID)
> + ? ? ? ret = mc13xxx_identify(mc13xxx, 1);
> + ? ? ? if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
> ? ? ? ? ? ? ? ?goto err_revision;
>
> ? ? ? ?/* mask all irqs */
> @@ -743,7 +825,7 @@ 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) {
> @@ -755,43 +837,15 @@ err_revision:
> ? ? ? ? ? ? ? ?return ret;
> ? ? ? ?}
>
> - ? ? ? mc13xxx_unlock(mc13xxx);
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_ADC)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-adc");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_CODEC)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-codec");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_REGULATOR) {
> - ? ? ? ? ? ? ? struct mc13xxx_regulator_platform_data regulator_pdata = {
> - ? ? ? ? ? ? ? ? ? ? ? .num_regulators = pdata->num_regulators,
> - ? ? ? ? ? ? ? ? ? ? ? .regulators = pdata->regulators,
> - ? ? ? ? ? ? ? };
> -
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &regulator_pdata, sizeof(regulator_pdata));
> - ? ? ? }
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_RTC)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice(mc13xxx, "%s-ts");
> -
> - ? ? ? if (pdata->flags & MC13XXX_USE_LED) {
> - ? ? ? ? ? ? ? mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pdata->leds, sizeof(*pdata->leds));
> - ? ? ? }
> -
> - ? ? ? return 0;
> + ? ? ? return mc13xxx_common_probe(mc13xxx, pdata);
> ?}
>
> -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);
> + ? ? ? free_irq(mc13xxx->irq, mc13xxx);
>
> ? ? ? ?mfd_remove_devices(&spi->dev);
>
> @@ -819,18 +873,100 @@ static struct spi_driver mc13xxx_driver = {
> ? ? ? ? ? ? ? ?.bus = &spi_bus_type,
> ? ? ? ? ? ? ? ?.owner = THIS_MODULE,
> ? ? ? ?},
> - ? ? ? .probe = mc13xxx_probe,
> - ? ? ? .remove = __devexit_p(mc13xxx_remove),
> + ? ? ? .probe = mc13xxx_spi_probe,
> + ? ? ? .remove = __devexit_p(mc13xxx_spi_remove),
> +};
> +
> +static int mc13xxx_i2c_probe(struct i2c_client *client,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?const struct i2c_device_id* id)
> +{
> + ? ? ? struct mc13xxx *mc13xxx;
> + ? ? ? struct mc13xxx_platform_data *pdata = dev_get_platdata(&client->dev);
> + ? ? ? int ret;
> +
> + ? ? ? mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
> + ? ? ? if (!mc13xxx)
> + ? ? ? ? ? ? ? return -ENOMEM;
> +
> + ? ? ? dev_set_drvdata(&client->dev, mc13xxx);
> + ? ? ? mc13xxx->pdev = &client->dev;
> + ? ? ? mc13xxx->client = client;
> + ? ? ? mc13xxx->read_dev = mc13xxx_i2c_reg_read;
> + ? ? ? mc13xxx->write_dev = mc13xxx_i2c_reg_write;
> + ? ? ? mc13xxx->irq = client->irq;
> +
> + ? ? ? mutex_init(&mc13xxx->lock);
> + ? ? ? mc13xxx_lock(mc13xxx);
> +
> + ? ? ? ret = mc13xxx_identify(mc13xxx, 0);
> + ? ? ? if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
> + ? ? ? ? ? ? ? goto err_revision;
> +
> + ? ? ? /* mask all irqs */
> + ? ? ? ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? goto err_mask;
> +
> + ? ? ? ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? goto err_mask;
> +
> + ? ? ? ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread,
> + ? ? ? ? ? ? ? ? ? ? ? IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
> +
> + ? ? ? if (ret) {
> +err_mask:
> +err_revision:
Why two labels here?
Also, if ret == 0, the lock will not be released.
> + ? ? ? ? ? ? ? mutex_unlock(&mc13xxx->lock);
> + ? ? ? ? ? ? ? kfree(mc13xxx);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? return mc13xxx_common_probe(mc13xxx,pdata);
> +}
> +
> +static int __devexit mc13xxx_i2c_remove(struct i2c_client *client)
> +{
> + ? ? ? struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev);
> +
> + ? ? ? free_irq(mc13xxx->irq, mc13xxx);
> +
> + ? ? ? mfd_remove_devices(&client->dev);
> +
> + ? ? ? kfree(mc13xxx);
> +
> + ? ? ? return 0;
> +}
> +
> +static const struct i2c_device_id mc13xxx_i2c_idtable[] = {
> + ? ? ? { "mc13892", MC13XXX_ID_MC13892},
> + ? ? ? { }
you may want to remove empty '{}'
> +};
> +
> +static struct i2c_driver mc13xxx_i2c_driver = {
> + ? ? ? .driver = {
> + ? ? ? ? ? ? ? .owner = THIS_MODULE,
> + ? ? ? ? ? ? ? .name = "mc13xxx-i2c"
> + ? ? ? },
> + ? ? ? .id_table = mc13xxx_i2c_idtable,
> + ? ? ? .probe = mc13xxx_i2c_probe,
> + ? ? ? .remove = __devexit_p(mc13xxx_i2c_remove),
> ?};
>
> ?static int __init mc13xxx_init(void)
> ?{
> - ? ? ? return spi_register_driver(&mc13xxx_driver);
> + ? ? ? int i2cret;
> + ? ? ? int spiret;
> + ? ? ? i2cret = i2c_add_driver(&mc13xxx_i2c_driver);
> + ? ? ? spiret = spi_register_driver(&mc13xxx_driver);
> +
> + ? ? ? return (i2cret == 0) && (spiret == 0);
> ?}
> ?subsys_initcall(mc13xxx_init);
>
> ?static void __exit mc13xxx_exit(void)
> ?{
> + ? ? ? i2c_del_driver(&mc13xxx_i2c_driver);
> ? ? ? ?spi_unregister_driver(&mc13xxx_driver);
> ?}
> ?module_exit(mc13xxx_exit);
> --
> 1.7.1
>
>

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-08  6:24     ` Yong Shen
@ 2010-12-08  8:07       ` Marc Reilly
  2010-12-08 10:42         ` Uwe Kleine-König
  0 siblings, 1 reply; 21+ messages in thread
From: Marc Reilly @ 2010-12-08  8:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Yong,

> It's better to use git format-patch to gernerate patch for review, by
> which you can add some commit information and s-o-b stuff.

I've submitted a (slightly) better patch earlier today. (although this was 
generated via format-patch, I forgot the sob.). 

My main hope was to get some indication that I was progressing along the right 
path.

> Please see inline comments.
Thanks, replies also in-line.

snip...

> > +               if (usespi) {
> > +                       const struct spi_device_id *devid =
> > +                               spi_get_device_id(mc13xxx->spidev);
> > +                       if (!devid || devid->driver_data !=
> > mc13xxx->icid) +                               dev_warn(mc13xxx->pdev,
> > "device id doesn't " +                                              
> > "match auto detection!\n"); +               } else {
> > +                       /* TODO */
> 
> todo what? remove this or add real code here.
> 

I wasn't immediately sure of what the equivalent way to do this via the i2c 
subsystem is. I'm not sure how useful it would be anyway, so I'll leave it out 
in future.

snip ...

> > +       mutex_init(&mc13xxx->lock);
> > +       mc13xxx_lock(mc13xxx);
> > +
> > +       ret = mc13xxx_identify(mc13xxx, 0);
> > +       if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
> > +               goto err_revision;
> > +
> > +       /* mask all irqs */
> > +       ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
> > +       if (ret)
> > +               goto err_mask;
> > +
> > +       ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
> > +       if (ret)
> > +               goto err_mask;
> > +
> > +       ret = request_threaded_irq(mc13xxx->irq, NULL,
> > mc13xxx_irq_thread, +                       IRQF_ONESHOT |
> > IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); +
> > +       if (ret) {
> > +err_mask:
> 
> > +err_revision:
> Why two labels here?

Copied from existing code. 

> Also, if ret == 0, the lock will not be released.

The lock is released in mc13xxx_common_probe. 
Yes, it would be better in this function, before common_probe is called.

> 
> > +               mutex_unlock(&mc13xxx->lock);
> > +               kfree(mc13xxx);
> > +               return ret;
> > +       }
> > +
> > +       return mc13xxx_common_probe(mc13xxx,pdata);
> > +}
> > +
> > +static int __devexit mc13xxx_i2c_remove(struct i2c_client *client)
> > +{
> > +       struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev);
> > +
> > +       free_irq(mc13xxx->irq, mc13xxx);
> > +
> > +       mfd_remove_devices(&client->dev);
> > +
> > +       kfree(mc13xxx);
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct i2c_device_id mc13xxx_i2c_idtable[] = {
> > +       { "mc13892", MC13XXX_ID_MC13892},
> > +       { }
> 
> you may want to remove empty '{}'

Again, mimicking the existing spi device table.

> 
> > +};
> > +
> > +static struct i2c_driver mc13xxx_i2c_driver = {
> > +       .driver = {
> > +               .owner = THIS_MODULE,
> > +               .name = "mc13xxx-i2c"
> > +       },
> > +       .id_table = mc13xxx_i2c_idtable,
> > +       .probe = mc13xxx_i2c_probe,
> > +       .remove = __devexit_p(mc13xxx_i2c_remove),
> >  };
> > 
> >  static int __init mc13xxx_init(void)
> >  {
> > -       return spi_register_driver(&mc13xxx_driver);
> > +       int i2cret;
> > +       int spiret;
> > +       i2cret = i2c_add_driver(&mc13xxx_i2c_driver);
> > +       spiret = spi_register_driver(&mc13xxx_driver);
> > +
> > +       return (i2cret == 0) && (spiret == 0);

For the record, I missed this, its fixed in my later patch. Return should be 0 
if both are successful.

Cheers,
Marc

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

* [PATCH] Added i2c support for mc13xxx-core
  2010-12-08  8:07       ` Marc Reilly
@ 2010-12-08 10:42         ` Uwe Kleine-König
  0 siblings, 0 replies; 21+ messages in thread
From: Uwe Kleine-König @ 2010-12-08 10:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Wed, Dec 08, 2010 at 07:07:55PM +1100, Marc Reilly wrote:
> Hi Yong,
> 
> > It's better to use git format-patch to gernerate patch for review, by
> > which you can add some commit information and s-o-b stuff.
> 
> I've submitted a (slightly) better patch earlier today. (although this was 
> generated via format-patch, I forgot the sob.). 
> 
> My main hope was to get some indication that I was progressing along the right 
> path.
> 
> > Please see inline comments.
> Thanks, replies also in-line.
> 
> snip...
> 
> > > +               if (usespi) {
> > > +                       const struct spi_device_id *devid =
> > > +                               spi_get_device_id(mc13xxx->spidev);
> > > +                       if (!devid || devid->driver_data !=
> > > mc13xxx->icid) +                               dev_warn(mc13xxx->pdev,
> > > "device id doesn't " +                                              
> > > "match auto detection!\n"); +               } else {
> > > +                       /* TODO */
> > 
> > todo what? remove this or add real code here.
> > 
> 
> I wasn't immediately sure of what the equivalent way to do this via the i2c 
> subsystem is. I'm not sure how useful it would be anyway, so I'll leave it out 
> in future.
I think this is OK to post the patch with TODO for review if you don't
know what to do (maybe specify a question here, then though).  For a
final patch that should be fixed of course.

> 
> snip ...
> 
> > > +       mutex_init(&mc13xxx->lock);
> > > +       mc13xxx_lock(mc13xxx);
> > > +
> > > +       ret = mc13xxx_identify(mc13xxx, 0);
> > > +       if (ret || (mc13xxx->icid == MC13XXX_ID_INVALID))
> > > +               goto err_revision;
> > > +
> > > +       /* mask all irqs */
> > > +       ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
> > > +       if (ret)
> > > +               goto err_mask;
> > > +
> > > +       ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
> > > +       if (ret)
> > > +               goto err_mask;
> > > +
> > > +       ret = request_threaded_irq(mc13xxx->irq, NULL,
> > > mc13xxx_irq_thread, +                       IRQF_ONESHOT |
> > > IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); +
> > > +       if (ret) {
> > > +err_mask:
> > 
> > > +err_revision:
> > Why two labels here?
> 
> Copied from existing code. 
I consider this to be OK, too (actually it's my code, so it would be
surprising if not ...)  There are two different errors that just share
the place the goto should point to.  Technically a single name would do
it, but I learned that for one the code is easier to verify with useful
label names and sometimes when code needs to be reshuffled the patch
becomes slightly less intrusive.

> > Also, if ret == 0, the lock will not be released.
> 
> The lock is released in mc13xxx_common_probe. 
> Yes, it would be better in this function, before common_probe is called.
ack

> 
> > 
> > > +               mutex_unlock(&mc13xxx->lock);
> > > +               kfree(mc13xxx);
> > > +               return ret;
> > > +       }
> > > +
> > > +       return mc13xxx_common_probe(mc13xxx,pdata);
> > > +}
> > > +
> > > +static int __devexit mc13xxx_i2c_remove(struct i2c_client *client)
> > > +{
> > > +       struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev);
> > > +
> > > +       free_irq(mc13xxx->irq, mc13xxx);
> > > +
> > > +       mfd_remove_devices(&client->dev);
> > > +
> > > +       kfree(mc13xxx);
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +static const struct i2c_device_id mc13xxx_i2c_idtable[] = {
> > > +       { "mc13892", MC13XXX_ID_MC13892},
> > > +       { }
> > 
> > you may want to remove empty '{}'
> 
> Again, mimicking the existing spi device table.
This must not go away, as it's the sentinel to mark the end of the
array.

Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

end of thread, other threads:[~2010-12-08 10:42 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-12-06  6:25 [PATCH] support PMIC mc13892 yong.shen at freescale.com
2010-12-06  7:22 ` Uwe Kleine-König
2010-12-07  2:41   ` Yong Shen
2010-12-07  7:57   ` Yong Shen
2010-12-07  8:02     ` Uwe Kleine-König
2010-12-06 10:40 ` David Jander
2010-12-07  2:50   ` Yong Shen
2010-12-06 10:55 ` Arnaud Patard (Rtp)
2010-12-06 11:42   ` Alberto Panizzo
2010-12-06 11:55     ` Arnaud Patard (Rtp)
2010-12-06 13:12       ` Alberto Panizzo
2010-12-07  2:52   ` Yong Shen
2010-12-06 21:54 ` Marc Reilly
2010-12-07  7:14   ` [PATCH] Added i2c support for mc13xxx-core Marc Reilly
2010-12-07  8:32     ` Yong Shen
2010-12-07 10:09       ` Marc Reilly
2010-12-08  6:24     ` Yong Shen
2010-12-08  8:07       ` Marc Reilly
2010-12-08 10:42         ` Uwe Kleine-König
2010-12-07  7:23   ` Marc Reilly
2010-12-07  7:23   ` Marc Reilly

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.