[PATCH 1/2] I2C: Convert PCF50606 to I2C device

Jonas Bonn jonas.bonn at gmail.com
Fri Oct 3 12:51:18 CEST 2008


This chip is a regular I2C device and does not really need to be set up
as a platform device.  This patch thus changes the driver definition and
converts the I2C bits to the new-style I2C interface at the same time.

Signed-off-by: Jonas Bonn <jonas.bonn at gmail.com>
---
 drivers/i2c/chips/pcf50606.c |  204 ++++++++++++++----------------------------
 1 files changed, 67 insertions(+), 137 deletions(-)

diff --git a/drivers/i2c/chips/pcf50606.c b/drivers/i2c/chips/pcf50606.c
index 97089da..9260766 100644
--- a/drivers/i2c/chips/pcf50606.c
+++ b/drivers/i2c/chips/pcf50606.c
@@ -69,10 +69,6 @@
  * Static data / structures
  ***********************************************************************/
 
-static unsigned short normal_i2c[] = { 0x08, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD_1(pcf50606);
-
 #define PCF50606_B_CHG_FAST	0	/* Charger Fast allowed */
 #define PCF50606_B_CHG_PRESENT	1	/* Charger present */
 #define PCF50606_B_CHG_FOK	2	/* Fast OK for battery */
@@ -105,8 +101,9 @@ enum pcf50606_suspend_states {
 	PCF50606_SS_COMPLETED_RESUME,
 };
 
+/* This data structure gets assigned as clientdata to the I2C device */
 struct pcf50606_data {
-	struct i2c_client client;
+	struct i2c_client* client;
 	struct pcf50606_platform_data *pdata;
 	struct backlight_device *backlight;
 	struct mutex lock;
@@ -172,10 +169,10 @@ static inline int __reg_write(struct pcf50606_data *pcf, u_int8_t reg,
 			      u_int8_t val)
 {
 	if (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND) {
-		dev_err(&pcf->client.dev, "__reg_write while suspended.\n");
+		dev_err(&pcf->client->dev, "__reg_write while suspended.\n");
 		dump_stack();
 	}
-	return i2c_smbus_write_byte_data(&pcf->client, reg, val);
+	return i2c_smbus_write_byte_data(pcf->client, reg, val);
 }
 
 static int reg_write(struct pcf50606_data *pcf, u_int8_t reg, u_int8_t val)
@@ -194,10 +191,10 @@ static inline int32_t __reg_read(struct pcf50606_data *pcf, u_int8_t reg)
 	int32_t ret;
 
 	if (pcf->suspend_state == PCF50606_SS_COMPLETED_SUSPEND) {
-		dev_err(&pcf->client.dev, "__reg_read while suspended.\n");
+		dev_err(&pcf->client->dev, "__reg_read while suspended.\n");
 		dump_stack();
 	}
-	ret = i2c_smbus_read_byte_data(&pcf->client, reg);
+	ret = i2c_smbus_read_byte_data(pcf->client, reg);
 
 	return ret;
 }
@@ -256,7 +253,7 @@ static u_int16_t adc_read(struct pcf50606_data *pcf,  int channel,
 	u_int8_t adcs2, adcs1;
 	u_int16_t ret;
 
-	dev_dbg(&pcf->client.dev, "entering (pcf=%p, channel=%u, data2=%p)\n",
+	dev_dbg(&pcf->client->dev, "entering (pcf=%p, channel=%u, data2=%p)\n",
 		pcf, channel, data2);
 
 	channel &= PCF50606_ADCC2_ADCMUX_MASK;
@@ -281,7 +278,7 @@ static u_int16_t adc_read(struct pcf50606_data *pcf,  int channel,
 
 	mutex_unlock(&pcf->lock);
 
-	dev_dbg(&pcf->client.dev, "returning %u %u\n", ret,
+	dev_dbg(&pcf->client->dev, "returning %u %u\n", ret,
 		data2 ? *data2 : 0);
 
 	return ret;
@@ -443,7 +440,7 @@ int pcf50606_voltage_set(struct pcf50606_data *pcf,
 	u_int8_t regnr;
 	int rc;
 
-	dev_dbg(&pcf->client.dev, "pcf=%p, reg=%d, mvolts=%d\n", pcf, reg,
+	dev_dbg(&pcf->client->dev, "pcf=%p, reg=%d, mvolts=%d\n", pcf, reg,
 		millivolts);
 
 	if (reg >= __NUM_PCF50606_REGULATORS)
@@ -590,7 +587,7 @@ static void pcf50606_work(struct work_struct *work)
 	pcf->working = 1;
 
 	/* sanity */
-	if (!&pcf->client.dev)
+	if (!&pcf->client->dev)
 		goto bail;
 
 	/*
@@ -627,7 +624,7 @@ static void pcf50606_work(struct work_struct *work)
 		goto reschedule;
 
 	/* this is the case early in resume! Sanity check! */
-	if (i2c_get_clientdata(&pcf->client) == NULL)
+	if (i2c_get_clientdata(pcf->client) == NULL)
 		goto reschedule;
 
 	/*
@@ -637,7 +634,7 @@ static void pcf50606_work(struct work_struct *work)
 	 * because if you don't INT# gets stuck asserted forever after a
 	 * while
 	 */
-	ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50606_REG_INT1,
+	ret = i2c_smbus_read_i2c_block_data(pcf->client, PCF50606_REG_INT1,
 					    sizeof(pcfirq), pcfirq);
 	if (ret != sizeof(pcfirq)) {
 		DEBUGPC("Oh crap PMU IRQ register read failed %d\n", ret);
@@ -675,7 +672,7 @@ static void pcf50606_work(struct work_struct *work)
 			apm_queue_event(APM_POWER_STATUS_CHANGE);
 			pcf->flags |= PCF50606_F_CHG_PRESENT;
 			if (pcf->pdata->cb)
-				pcf->pdata->cb(&pcf->client.dev,
+				pcf->pdata->cb(&pcf->client->dev,
 						PCF50606_FEAT_MBC,
 						PMU_EVT_INSERT);
 		}
@@ -684,7 +681,7 @@ static void pcf50606_work(struct work_struct *work)
 	}
 
 
-	dev_dbg(&pcf->client.dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x:",
+	dev_dbg(&pcf->client->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x:",
 		pcfirq[0], pcfirq[1], pcfirq[2]);
 
 	if (pcfirq[0] & PCF50606_INT1_ONKEYF) {
@@ -774,7 +771,7 @@ static void pcf50606_work(struct work_struct *work)
 		apm_queue_event(APM_POWER_STATUS_CHANGE);
 		pcf->flags |= PCF50606_F_CHG_PRESENT;
 		if (pcf->pdata->cb)
-			pcf->pdata->cb(&pcf->client.dev,
+			pcf->pdata->cb(&pcf->client->dev,
 				       PCF50606_FEAT_MBC, PMU_EVT_INSERT);
 		/* FIXME: how to signal this to userspace */
 	}
@@ -785,7 +782,7 @@ static void pcf50606_work(struct work_struct *work)
 		apm_queue_event(APM_POWER_STATUS_CHANGE);
 		pcf->flags &= ~(PCF50606_F_CHG_MASK|PCF50606_F_CHG_PRESENT);
 		if (pcf->pdata->cb)
-			pcf->pdata->cb(&pcf->client.dev,
+			pcf->pdata->cb(&pcf->client->dev,
 				       PCF50606_FEAT_MBC, PMU_EVT_INSERT);
 		/* FIXME: how signal this to userspace */
 	}
@@ -836,14 +833,14 @@ static void pcf50606_work(struct work_struct *work)
 		/* Accessory insertion detected */
 		DEBUGPC("ACDINS ");
 		if (pcf->pdata->cb)
-			pcf->pdata->cb(&pcf->client.dev,
+			pcf->pdata->cb(&pcf->client->dev,
 				       PCF50606_FEAT_ACD, PMU_EVT_INSERT);
 	}
 	if (pcfirq[2] & PCF50606_INT3_ACDREM) {
 		/* Accessory removal detected */
 		DEBUGPC("ACDREM ");
 		if (pcf->pdata->cb)
-			pcf->pdata->cb(&pcf->client.dev,
+			pcf->pdata->cb(&pcf->client->dev,
 				       PCF50606_FEAT_ACD, PMU_EVT_REMOVE);
 	}
 	/* FIXME: TSCPRES */
@@ -896,7 +893,7 @@ static void pcf50606_work(struct work_struct *work)
 bail:
 	pcf->working = 0;
 	input_sync(pcf->input_dev);
-	put_device(&pcf->client.dev);
+	put_device(&pcf->client->dev);
 	mutex_unlock(&pcf->working_lock);
 
 	return;
@@ -906,10 +903,10 @@ reschedule:
 	if ((pcf->suspend_state != PCF50606_SS_STARTING_SUSPEND) &&
 	    (pcf->suspend_state != PCF50606_SS_COMPLETED_SUSPEND)) {
 		msleep(10);
-		dev_info(&pcf->client.dev, "rescheduling interrupt service\n");
+		dev_info(&pcf->client->dev, "rescheduling interrupt service\n");
 	}
 	if (!schedule_work(&pcf->work))
-		dev_err(&pcf->client.dev, "int service reschedule failed\n");
+		dev_err(&pcf->client->dev, "int service reschedule failed\n");
 
 	/* we don't put the device here, hold it for next time */
 	mutex_unlock(&pcf->working_lock);
@@ -919,11 +916,11 @@ static irqreturn_t pcf50606_irq(int irq, void *_pcf)
 {
 	struct pcf50606_data *pcf = _pcf;
 
-	dev_dbg(&pcf->client.dev, "entering(irq=%u, pcf=%p): scheduling work\n",
+	dev_dbg(&pcf->client->dev, "entering(irq=%u, pcf=%p): scheduling work\n",
 		irq, _pcf);
-	get_device(&pcf->client.dev);
+	get_device(&pcf->client->dev);
 	if (!schedule_work(&pcf->work) && !pcf->working)
-		dev_err(&pcf->client.dev, "pcf irq work already queued.\n");
+		dev_err(&pcf->client->dev, "pcf irq work already queued.\n");
 
 	return IRQ_HANDLED;
 }
@@ -1733,23 +1730,15 @@ static void populate_sysfs_group(struct pcf50606_data *pcf)
 	}
 }
 
-static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
+static int pcf50606_i2c_probe(struct i2c_client *i2c_client,
+			      const struct i2c_device_id *id)
 {
-	struct i2c_client *new_client;
+	/* FIXME: Detection needed */
 	struct pcf50606_data *data;
 	int err = 0;
 	int irq;
 
-	if (!pcf50606_pdev) {
-		printk(KERN_ERR "pcf50606: driver needs a platform_device!\n");
-		return -EIO;
-	}
-
-	irq = platform_get_irq(pcf50606_pdev, 0);
-	if (irq < 0) {
-		dev_err(&pcf50606_pdev->dev, "no irq in platform resources!\n");
-		return -EIO;
-	}
+	irq = i2c_client->irq;
 
 	/* At the moment, we only support one PCF50606 in a system */
 	if (pcf50606_global) {
@@ -1768,32 +1757,21 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
 	data->irq = irq;
 	data->working = 0;
 	data->onkey_seconds = -1;
-	data->pdata = pcf50606_pdev->dev.platform_data;
-
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	new_client->adapter = adapter;
-	new_client->driver = &pcf50606_driver;
-	new_client->flags = 0;
-	strlcpy(new_client->name, "pcf50606", I2C_NAME_SIZE);
+	data->pdata = i2c_client->dev.platform_data;
+	
+	data->client = i2c_client;
+	i2c_set_clientdata(i2c_client, data);
 
 	/* now we try to detect the chip */
-
-	/* register with i2c core */
-	err = i2c_attach_client(new_client);
-	if (err) {
-		dev_err(&new_client->dev,
-			"error during i2c_attach_client()\n");
-		goto exit_free;
-	}
+	// FIXME: Detect chip????
+	/* */
 
 	populate_sysfs_group(data);
 
-	err = sysfs_create_group(&new_client->dev.kobj, &pcf_attr_group);
+	err = sysfs_create_group(&i2c_client->dev.kobj, &pcf_attr_group);
 	if (err) {
-		dev_err(&new_client->dev, "error creating sysfs group\n");
-		goto exit_detach;
+		dev_err(&i2c_client->dev, "error creating sysfs group\n");
+		goto exit_free;
 	}
 
 	/* create virtual charger 'device' */
@@ -1831,13 +1809,14 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
 		goto exit_input;
 
 	if (enable_irq_wake(irq) < 0)
-		dev_err(&new_client->dev, "IRQ %u cannot be enabled as wake-up"
+		dev_err(&i2c_client->dev, "IRQ %u cannot be enabled as wake-up"
 			"source in this hardware revision!", irq);
 
+	/* FIXME: We need to ditch this global */
 	pcf50606_global = data;
 
 	if (data->pdata->used_features & PCF50606_FEAT_RTC) {
-		data->rtc = rtc_device_register("pcf50606", &new_client->dev,
+		data->rtc = rtc_device_register("pcf50606", &i2c_client->dev,
 						&pcf50606_rtc_ops, THIS_MODULE);
 		if (IS_ERR(data->rtc)) {
 			err = PTR_ERR(data->rtc);
@@ -1848,7 +1827,7 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
 	if (data->pdata->used_features & PCF50606_FEAT_WDT) {
 		err = misc_register(&pcf50606_wdt_miscdev);
 		if (err) {
-			dev_err(&new_client->dev, "cannot register miscdev on "
+			dev_err(&i2c_client->dev, "cannot register miscdev on "
 			       "minor=%d (%d)\n", WATCHDOG_MINOR, err);
 			goto exit_rtc;
 		}
@@ -1863,7 +1842,7 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
 
 	if (data->pdata->used_features & PCF50606_FEAT_PWM_BL) {
 		data->backlight = backlight_device_register("pcf50606-bl",
-							    &new_client->dev,
+							    &i2c_client->dev,
 							    data,
 							    &pcf50606bl_ops);
 		if (!data->backlight)
@@ -1879,12 +1858,12 @@ static int pcf50606_detect(struct i2c_adapter *adapter, int address, int kind)
 
 #ifdef CONFIG_MACH_NEO1973_GTA01
 	if (machine_is_neo1973_gta01()) {
-		gta01_pm_gps_dev.dev.parent = &new_client->dev;
+		gta01_pm_gps_dev.dev.parent = &i2c_client->dev;
 		switch (system_rev) {
 		case GTA01Bv2_SYSTEM_REV:
 		case GTA01Bv3_SYSTEM_REV:
 		case GTA01Bv4_SYSTEM_REV:
-			gta01_pm_bt_dev.dev.parent = &new_client->dev;
+			gta01_pm_bt_dev.dev.parent = &i2c_client->dev;
 			platform_device_register(&gta01_pm_bt_dev);
 			break;
 		}
@@ -1920,22 +1899,17 @@ exit_input:
 	pm_power_off = NULL;
 	input_unregister_device(data->input_dev);
 exit_sysfs:
-	sysfs_remove_group(&new_client->dev.kobj, &pcf_attr_group);
-exit_detach:
-	i2c_detach_client(new_client);
+	sysfs_remove_group(&i2c_client->dev.kobj, &pcf_attr_group);
 exit_free:
 	kfree(data);
 	return err;
-}
 
-static int pcf50606_attach_adapter(struct i2c_adapter *adapter)
-{
-	return i2c_probe(adapter, &addr_data, &pcf50606_detect);
+	return 0;
 }
 
-static int pcf50606_detach_client(struct i2c_client *client)
+static int pcf50606_i2c_remove(struct i2c_client *i2c_client)
 {
-	struct pcf50606_data *pcf = i2c_get_clientdata(client);
+	struct pcf50606_data *pcf = i2c_get_clientdata(i2c_client);
 
 	apm_get_power_status = NULL;
 	input_unregister_device(pcf->input_dev);
@@ -1951,7 +1925,7 @@ static int pcf50606_detach_client(struct i2c_client *client)
 
 	free_irq(pcf->irq, pcf);
 
-	sysfs_remove_group(&client->dev.kobj, &pcf_attr_group);
+	sysfs_remove_group(&i2c_client->dev.kobj, &pcf_attr_group);
 
 	pm_power_off = NULL;
 
@@ -1970,9 +1944,8 @@ static int pcf50606_detach_client(struct i2c_client *client)
 #define INT3M_RESUMERS	(PCF50606_INT3_LOWBAT | \
 			 PCF50606_INT3_HIGHTMP | \
 			 PCF50606_INT3_ACDINS)
-static int pcf50606_suspend(struct device *dev, pm_message_t state)
+static int pcf50606_i2c_suspend(struct i2c_client* client, pm_message_t state)
 {
-	struct i2c_client *client = to_i2c_client(dev);
 	struct pcf50606_data *pcf = i2c_get_clientdata(client);
 	int i;
 
@@ -2021,7 +1994,7 @@ static int pcf50606_suspend(struct device *dev, pm_message_t state)
 			if (i == PCF50606_REGULATOR_IOREG)
 				continue;
 
-			dev_dbg(dev, "disabling pcf50606 regulator %u\n", i);
+			dev_dbg(&client->dev, "disabling pcf50606 regulator %u\n", i);
 			/* we cannot use pcf50606_onoff_set() because we're
 			 * already under the mutex */
 			tmp = __reg_read(pcf, regulator_registers[i]);
@@ -2044,9 +2017,8 @@ static int pcf50606_suspend(struct device *dev, pm_message_t state)
 	return 0;
 }
 
-static int pcf50606_resume(struct device *dev)
+static int pcf50606_i2c_resume(struct i2c_client* client)
 {
-	struct i2c_client *client = to_i2c_client(dev);
 	struct pcf50606_data *pcf = i2c_get_clientdata(client);
 
 	mutex_lock(&pcf->lock);
@@ -2080,85 +2052,43 @@ static int pcf50606_resume(struct device *dev)
 	/* Call PCF work function; this fixes an issue on the gta01 where
 	 * the power button "goes away" if it is used to wake the device.
 	 */
-	get_device(&pcf->client.dev);
+	get_device(&pcf->client->dev);
 	pcf50606_work(&pcf->work);
 
 	return 0;
 }
-#else
-#define pcf50606_suspend NULL
-#define pcf50606_resume NULL
 #endif
 
-static struct i2c_driver pcf50606_driver = {
-	.driver = {
-		.name	 = "pcf50606",
-		.suspend = pcf50606_suspend,
-		.resume	 = pcf50606_resume,
-	},
-	.id		= I2C_DRIVERID_PCF50606,
-	.attach_adapter	= pcf50606_attach_adapter,
-	.detach_client	= pcf50606_detach_client,
+static const struct i2c_device_id pcf50606_i2c_id[] = {
+	{ "pcf50606", 0}
 };
 
-/* platform driver, since i2c devices don't have platform_data */
-static int __init pcf50606_plat_probe(struct platform_device *pdev)
-{
-	struct pcf50606_platform_data *pdata = pdev->dev.platform_data;
-
-	if (!pdata)
-		return -ENODEV;
-
-	pcf50606_pdev = pdev;
-
-	return 0;
-}
-
-static int pcf50606_plat_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-/* We have this purely to capture an early indication that we are coming out
- * of suspend, before our device resume got called; async interrupt service is
- * interested in this.
- */
-
-static int pcf50606_plat_resume(struct platform_device *pdev)
-{
-	/* i2c_get_clientdata(to_i2c_client(&pdev->dev)) returns NULL at this
-	 * early resume time so we have to use pcf50606_global
-	 */
-	pcf50606_global->suspend_state = PCF50606_SS_RESUMING_BUT_NOT_US_YET;
-
-	return 0;
-}
-
-static struct platform_driver pcf50606_plat_driver = {
-	.probe	= pcf50606_plat_probe,
-	.remove	= pcf50606_plat_remove,
-	.resume_early = pcf50606_plat_resume,
+static struct i2c_driver pcf50606_driver = {
 	.driver = {
-		.owner	= THIS_MODULE,
-		.name 	= "pcf50606",
+		.name	 = "pcf50606",
 	},
+	.id_table	= pcf50606_i2c_id,
+	.probe		= pcf50606_i2c_probe,
+	.remove		= pcf50606_i2c_remove,
+#ifdef CONFIG_PM
+	.suspend 	= pcf50606_i2c_suspend,
+	.resume		= pcf50606_i2c_resume
+#endif /* CONFIG_PM */
+//	.class		= ???
 };
 
 static int __init pcf50606_init(void)
 {
 	int rc;
 
-	rc = platform_driver_register(&pcf50606_plat_driver);
-	if (!rc)
-		rc = i2c_add_driver(&pcf50606_driver);
+	rc = i2c_add_driver(&pcf50606_driver);
 
 	return rc;
 }
 
-static void pcf50606_exit(void)
+static void __exit pcf50606_exit(void)
 {
 	i2c_del_driver(&pcf50606_driver);
-	platform_driver_unregister(&pcf50606_plat_driver);
 }
 
 MODULE_DESCRIPTION("I2C chip driver for NXP PCF50606 power management unit");
-- 
1.5.4.3




More information about the openmoko-kernel mailing list