Re: [PATCH] drivers: regulator: add Maxim 8998 driver

From: Kyungmin Park
Date: Fri Jun 11 2010 - 08:49:08 EST


On Fri, Jun 11, 2010 at 7:58 PM, Mark Brown
<broonie@xxxxxxxxxxxxxxxxxxxxxxxxxxx> wrote:
> On Fri, Jun 11, 2010 at 09:02:45AM +0200, Marek Szyprowski wrote:
>
>> This patch adds voltage regulator driver for Maxim 8998 chip. This chip
>> is used on Samsung Aquila and GONI boards.
>
> Overall this looks pretty good - some comments below, though.
>
> A few things in the code make it look like the driver should be using
> the MFD framework - there's references in here for things like a battery
> charger which should be being supported via the power subsystem, for
> example.

Exactly, also it supports the RTC. Okay try to re-organize the PMIC drivers.

>
>> +     ret = i2c_smbus_read_byte_data(client, reg);
>> +     if (ret < 0)
>> +             return -EIO;
>
> It probably makes more sense to pass back the actual error you got from
> the I2C subsystem here.

Will fix it.

>
>> +static void max8998_cache_register_init(struct i2c_client *client)
>> +{
>> +     u8 value;
>> +     int ret;
>> +
>> +     ret = max8998_i2c_read(client, MAX8998_REG_STATUS1, &value);
>> +     if (ret)
>> +             return;
>> +     ret = max8998_i2c_read(client, MAX8998_REG_STATUS2, &value);
>> +     if (ret)
>> +             return;
>
> Should these registers really be cached at all?  They're not used but
> the name and the fact that you read them dynamically makes
>
> Also, it looks like you're initialising things like the voltage settings
> and regulator enables from the cache rather than from the chip - this
> seems like it'll cause problems if the bootloader or similar has done
> something to the chip prior to the driver taking control.  For PMICs and
> regulators I'd generally expect to see the driver initialise itself from
> the chip rather than fixed defaults.
>
>> +static const int ldo23_voltage_map[] = {
>> +      800,  850,  900,  950, 1000,
>> +     1050, 1100, 1150, 1200, 1250,
>> +     1300,
>
> I may have missed something in these tables but they all look like
> simple functions of the register value - perhaps they could be replaced
> with calculations?

Good idea, create the generic voltage map something like this

int generic_get_voltage_map(base, step, index)
where base is 800, step is 50, and actual index.

Before call the generic_get_voltage_map() we should check the index.

>
>> +static int max8998_get_ldo(struct regulator_dev *rdev)
>> +{
>> +     return rdev_get_id(rdev);
>> +}
>
> Probably worth shoving an inline in there, though I'm not sure if the
> function is really adding anything.
>
>> +     value = max8998_read_reg(max8998, reg);
>> +     value |= (1 << shift);
>> +     ret = max8998_write_reg(max8998, reg, value);
>
> This is racy - there's nothing preventing another thread coming in and
> running the same code so you get something like:
>
>        reg_read(1)
>        reg_read(2)
>        reg_write(1)
>        reg_write(2)
>
> You could fix this with an atomic max8998_update_bits() function.
>
>> +static int max8998_set_voltage(struct regulator_dev *rdev,
>> +                             int min_uV, int max_uV)
>> +{
>> +     struct max8998_data *max8998 = rdev_get_drvdata(rdev);
>> +     int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
>> +     int ldo = max8998_get_ldo(rdev);
>> +     const int *vol_map = ldo_voltage_map[ldo];
>> +     int reg, shift = -1, mask, value, ret;
>> +     int i;
>> +
>> +     for (i = 0; i < vol_map[i]; i++) {
>> +             if (vol_map[i] >= min_vol)
>
> This vol_map[] checking is pretty obscure...  Are you sure the check
> you're using in the for loop shouldn't be based on the table size for
> the voltage map rather than on the values in the table?
>
>> +                     break;
>> +     }
>> +
>> +     if (!vol_map[i] || vol_map[i] > max_vol)
>> +             return -EINVAL;
>
> Your voltage maps aren't null terminated so the check for vol_map[i]
> doesn't do what you think it does - you should be checking to see if you
> fell off the end of the arary, not to see if you have a zero value.
>
>> +static irqreturn_t max8998_ono_irq(int irq, void *data)
>> +{
>> +     return IRQ_HANDLED;
>> +}
>
> This needs at least a comment explaining why you don't need to do
> anything for the interrupt.

We just remove it. it's unused function actually.

>
>> +     if (gpio_is_valid(max8998->ono_pin)) {
>> +             ret = gpio_request(max8998->ono_pin, "MAX8998 nONO");
>> +             if (ret)
>> +                     goto out_ono;
>> +             irq = gpio_to_irq(max8998->ono_pin);
>> +             ret = request_irq(irq, max8998_ono_irq,
>> +                             IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
>> +                             "max8998 nPower", max8998);
>> +             if (ret) {
>> +                     dev_err(&client->dev, "Can't get interrupt pin\n");
>> +                     goto out_ono_irq;
>> +             }
>> +
>> +             /* enable wakeup source for power button */
>> +             set_irq_wake(irq, 1);
>> +             max8998->ono_irq = irq;
>> +     }
>
> Should this not just be specified as an IRQ?  The gpio API doesn't
> appear to be being used at all by the driver.

Okay we will check it.

>
>> +     i2c_set_clientdata(client, max8998);
>> +
>> +     max8998_cache_register_init(client);
>
> I'd expect the cache initialisation to be done before the regulators are
> initialised so that the regulator API can use the cache while it does
> the setup.  This will improve performance on startup.

Thank you,
Kyungmin Park
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/