[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(>a01_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