[PATCH 1/4] mfd: update i2c driver for max8925
Samuel Ortiz
sameo at linux.intel.com
Fri Jan 29 14:54:07 EST 2010
Hi Haojian,
On Mon, Jan 25, 2010 at 06:07:08AM -0500, Haojian Zhuang wrote:
> static inline int max8925_read_device(struct i2c_client *i2c,
> int reg, int bytes, void *dest)
> {
> - unsigned char data;
> - unsigned char *buf;
> int ret;
>
> - buf = kzalloc(bytes + 1, GFP_KERNEL);
> - if (!buf)
> - return -ENOMEM;
> -
> - data = (unsigned char)reg;
> - ret = i2c_master_send(i2c, &data, 1);
> - if (ret < 0)
> - return ret;
> -
> - ret = i2c_master_recv(i2c, buf, bytes + 1);
> - if (ret < 0)
> - return ret;
> - memcpy(dest, buf, bytes);
> - return 0;
> + if (bytes > 1)
> + ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest);
> + else {
> + ret = i2c_smbus_read_byte_data(i2c, reg);
> + if (ret < 0)
> + return ret;
> + *(unsigned char *)dest = (unsigned char)ret;
> + }
> + return ret;
Your read_device routine looks much better now :)
> @@ -142,28 +138,56 @@ static int __devinit max8925_probe(struct
> i2c_client *client,
> const struct i2c_device_id *id)
> {
> struct max8925_platform_data *pdata = client->dev.platform_data;
> - struct max8925_chip *chip;
> + struct i2c_board_info rtc_info, adc_info;
> + const unsigned short addr_rtc[] = {
> + RTC_I2C_ADDR,
> + I2C_CLIENT_END,
> + };
> + const unsigned short addr_adc[] = {
> + ADC_I2C_ADDR,
> + I2C_CLIENT_END,
> + };
If you know the devices adress, why do you call i2c_new_probed_device()
instead of i2c_new_device() ?
> + static struct max8925_chip *chip;
> + static int init_gpm = 0, init_adc = 0, init_rtc = 0, count = 0;
Those static here are not looking good at all...
> + if (!init_gpm) {
> + init_gpm = 1;
> + chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
> + if (chip == NULL)
> + return -ENOMEM;
> + chip->i2c = client;
> + chip->dev = &client->dev;
> + i2c_set_clientdata(client, chip);
> + dev_set_drvdata(chip->dev, chip);
> + mutex_init(&chip->io_lock);
> + }
> + if (!init_rtc) {
> + init_rtc = 1;
> + memset(&rtc_info, 0, sizeof(struct i2c_board_info));
> + strlcpy(rtc_info.type, "max8925", I2C_NAME_SIZE);
> + rtc_info.platform_data = chip->i2c->dev.platform_data;
> + chip->rtc = i2c_new_probed_device(chip->i2c->adapter,
> + &rtc_info, addr_rtc);
> + i2c_set_clientdata(chip->rtc, chip);
> + } else if (!init_adc) {
> + init_adc = 1;
> + memset(&adc_info, 0, sizeof(struct i2c_board_info));
> + strlcpy(adc_info.type, "max8925", I2C_NAME_SIZE);
> + adc_info.platform_data = chip->i2c->dev.platform_data;
> + if (pdata->tsc_irq > 0)
> + adc_info.irq = pdata->tsc_irq;
> + chip->adc = i2c_new_probed_device(chip->i2c->adapter,
> + &adc_info, addr_adc);
> + i2c_set_clientdata(chip->adc, chip);
> + }
> + /* Initialize max8925 until all of three I2C clients are ready */
> + if (++count == 3)
> + max8925_device_init(chip, pdata);
This has to be rewritten, but first let me try to understand something: You
need the max9825 core to have pointers to the other i2c devices because of how
it handles IRQs right ? In your max9825 irq handler you need to be able to
access the rtc and the adc devices, right ? And then on yourrtc and power
drivers, you actually only access the max8925 core i2c registers ?
I would appreciate if most of your answers to those questions could morph into
code comments to this probe routine.
Then, about the code design: Having your probe routine relying on those static
variable is not ok. If I undersand you correctly, what you trying to achieve
here is not calling max8925_device_init() before you actually have the core,
the i2c and the adc pointer setup ?
If that's so, why not simply use i2c_new_dummy() instead of having to handle
recursive calls of your probe routine ?
Cheers,
Samuel.
> return 0;
> }
> @@ -171,10 +195,23 @@ static int __devinit max8925_probe(struct
> i2c_client *client,
> static int __devexit max8925_remove(struct i2c_client *client)
> {
> struct max8925_chip *chip = i2c_get_clientdata(client);
> + static int init_gpm = 1, init_adc = 1, init_rtc = 1;
>
> - max8925_device_exit(chip);
> - i2c_set_clientdata(client, NULL);
> - kfree(chip);
> + if (client->addr == ADC_I2C_ADDR)
> + init_adc = 0;
> + else if (client->addr == RTC_I2C_ADDR)
> + init_rtc = 0;
> + else
> + init_gpm = 0;
> + if (!init_gpm && !init_rtc && !init_adc) {
> + max8925_device_exit(chip);
> + i2c_unregister_device(chip->adc);
> + i2c_unregister_device(chip->rtc);
> + i2c_set_clientdata(chip->adc, NULL);
> + i2c_set_clientdata(chip->rtc, NULL);
> + i2c_set_clientdata(chip->i2c, NULL);
> + kfree(chip);
> + }
> return 0;
> }
>
> --
> 1.5.6.5
--
Intel Open Source Technology Centre
http://oss.intel.com/
More information about the linux-arm-kernel
mailing list