All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anton Vorontsov <anton.vorontsov@linaro.org>
To: "Kim, Milo" <Milo.Kim@ti.com>
Cc: "sameo@linux.intel.com" <sameo@linux.intel.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Jonathan Cameron <jic23@kernel.org>
Subject: Re: [PATCH v3 2/3] power_supply: add new lp8788 charger driver
Date: Wed, 22 Aug 2012 22:54:12 -0700	[thread overview]
Message-ID: <20120823055412.GB4849@lizard> (raw)
In-Reply-To: <A874F61F95741C4A9BA573A70FE3998F41EEFC3E@DQHE02.ent.ti.com>

On Tue, Aug 14, 2012 at 02:32:50AM +0000, Kim, Milo wrote:
> Patch v3.

Thanks for the driver! It looks great, mostly cosmetic comments
down below.

> (a) use irq domain for handling charger interrupts
> (b) use scaled adc value rather than raw value
>     : replace iio_read_channel_raw() with iio_read_channel_scale()
> (c) clean up charger-platform-data code
> (d) remove goto statement in _probe()
> (e) name change : from lp8788_unregister_psy() to lp8788_psy_unregister()

Only changelog? No description for the driver? Nothing exciting to
tell us about the hardware, e.g. why it's so great? :-)

> Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com>
> ---
[...]
> @@ -0,0 +1,785 @@
> +/*
> + * TI LP8788 MFD - battery charger driver
> + *
> + * Copyright 2012 Texas Instruments
> + *
> + * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
> + *
> + * 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/err.h>
> +#include <linux/iio/consumer.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqdomain.h>
> +#include <linux/mfd/lp8788.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +/* register address */
> +#define LP8788_CHG_STATUS		0x07
> +#define LP8788_CHG_IDCIN		0x13
> +#define LP8788_CHG_IBATT		0x14
> +#define LP8788_CHG_VTERM		0x15
> +#define LP8788_CHG_EOC			0x16
> +
> +/* mask/shift bits */
> +#define LP8788_CHG_INPUT_STATE_M	0x03	/* Addr 07h */
> +#define LP8788_CHG_STATE_M		0x3C
> +#define LP8788_CHG_STATE_S		2
> +#define LP8788_NO_BATT_M		BIT(6)
> +#define LP8788_BAD_BATT_M		BIT(7)
> +#define LP8788_CHG_IBATT_M		0x1F	/* Addr 14h */
> +#define LP8788_CHG_VTERM_M		0x0F	/* Addr 15h */
> +#define LP8788_CHG_EOC_LEVEL_M		0x30	/* Addr 16h */
> +#define LP8788_CHG_EOC_LEVEL_S		4
> +#define LP8788_CHG_EOC_TIME_M		0x0E
> +#define LP8788_CHG_EOC_TIME_S		1
> +#define LP8788_CHG_EOC_MODE_M		BIT(0)
> +
> +#define CHARGER_NAME			"charger"
> +#define BATTERY_NAME			"main_batt"
> +
> +#define LP8788_CHG_START		0x11
> +#define LP8788_CHG_END			0x1C
> +
> +#define BUF_SIZE			40

This is in the global namespace, although not exported, true.

Anyways, seems way too generic. I'd prepend it with LP8788_, or
at least LP_ for short.

> +#define LP8788_ISEL_MAX			23
> +#define LP8788_ISEL_STEP		50
> +#define LP8788_VTERM_MIN		4100
> +#define LP8788_VTERM_STEP		25
> +#define MAX_BATT_CAPACITY		100
> +#define MAX_CHG_IRQS			11

ditto.

> +
> +enum lp8788_charging_state {
> +	OFF,
> +	WARM_UP,
> +	LOW_INPUT = 0x3,
> +	PRECHARGE,
> +	CC,
> +	CV,

ditto.

> +	MAINTENANCE,
> +	BATTERY_FAULT,
> +	SYSTEM_SUPPORT = 0xC,
> +	HIGH_CURRENT = 0xF,
> +	MAX_CHG_STATE,
> +};
> +
> +enum lp8788_charger_adc_sel {
> +	VBATT,
> +	BATT_TEMP,
> +	NUM_CHG_ADC,
> +};
> +
> +enum lp8788_charger_input_state {
> +	SYSTEM_SUPPLY = 1,
> +	FULL_FUNCTION,

ditto ditto..

> +};
> +
> +/*
> + * struct lp8788_chg_irq
> + * @which        : lp8788 interrupt id
> + * @virq         : Linux IRQ number from irq_domain
> + */
> +struct lp8788_chg_irq {
> +	enum lp8788_int_id which;
> +	int virq;
> +};
[...]
> +static inline bool lp8788_is_valid_charger_register(u8 addr)
> +{
> +	return (addr >= LP8788_CHG_START && addr <= LP8788_CHG_END);

No need for the outermost parenthesis.

> +}
> +
> +static int lp8788_update_charger_params(struct lp8788_charger *pchg)
> +{
> +	struct lp8788 *lp = pchg->lp;
> +	struct lp8788_charger_platform_data *pdata = pchg->pdata;
> +	struct lp8788_chg_param *param;
> +	int i, ret;

One declaration per line, please. I.e.

int i;
int ret;

> +
> +	if (!pdata || !pdata->chg_params) {
> +		dev_info(lp->dev, "skip updating charger parameters\n");
> +		return 0;
> +	}
[...]
> +static ssize_t lp8788_show_eoc_time(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct lp8788_charger *pchg = dev_get_drvdata(dev);
> +	char *stime[] = { "400ms", "5min", "10min", "15min",
> +			"20min", "25min", "30min" "No timeout" };
> +	u8 val;
> +
> +	lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
> +	val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S;
> +
> +	return scnprintf(buf, BUF_SIZE, "End Of Charge Time: %s\n", stime[val]);
> +}
> +
> +static ssize_t lp8788_show_eoc_level(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct lp8788_charger *pchg = dev_get_drvdata(dev);
> +	char *abs_level[] = { "25mA", "49mA", "75mA", "98mA" };
> +	char *relative_level[] = { "5%", "10%", "15%", "20%" };
> +	char *level;
> +	u8 val, mode;

One declaration per line please, i.e.

u8 val;
u8 mode;

> +
> +	lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
> +
> +	mode = val & LP8788_CHG_EOC_MODE_M;
> +	val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S;
> +	level = mode ? abs_level[val] : relative_level[val];
> +
> +	return scnprintf(buf, BUF_SIZE, "End Of Charge Level: %s\n", level);
> +}
> +
> +static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);
> +static DEVICE_ATTR(idcin, S_IRUSR, lp8788_show_idcin, NULL);
> +static DEVICE_ATTR(ibatt, S_IRUSR, lp8788_show_ibatt, NULL);
> +static DEVICE_ATTR(vterm, S_IRUSR, lp8788_show_vterm, NULL);
> +static DEVICE_ATTR(eoc_time, S_IRUSR, lp8788_show_eoc_time, NULL);
> +static DEVICE_ATTR(eoc_level, S_IRUSR, lp8788_show_eoc_level, NULL);
> +
> +static struct attribute *lp8788_charger_attr[] = {
> +	&dev_attr_charger_status.attr,
> +	&dev_attr_idcin.attr,
> +	&dev_attr_ibatt.attr,
> +	&dev_attr_vterm.attr,
> +	&dev_attr_eoc_time.attr,
> +	&dev_attr_eoc_level.attr,

Are you sure you want to have the driver-specific properties?
I.e., maybe some of them generic enough to them to the standard
POWER_SUPPLY_PROP_* set?

At least 'charging current' seems generic enough...

> +	NULL,
> +};
> +
> +static const struct attribute_group lp8788_attr_group = {
> +	.attrs = lp8788_charger_attr,
> +};
> +
> +static __devinit int lp8788_charger_probe(struct platform_device *pdev)
> +{
> +	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
> +	struct lp8788_charger *pchg;
> +	int ret;
> +
> +	pchg = devm_kzalloc(lp->dev, sizeof(struct lp8788_charger), GFP_KERNEL);
> +	if (!pchg)
> +		return -ENOMEM;
> +
> +	pchg->lp = lp;
> +	pchg->pdata = lp->pdata ? lp->pdata->chg_pdata : NULL;
> +	platform_set_drvdata(pdev, pchg);
> +
> +	ret = lp8788_update_charger_params(pchg);
> +	if (ret)
> +		return ret;
> +
> +	lp8788_setup_adc_channel(pchg);
> +
> +	ret = lp8788_psy_register(pdev, pchg);
> +	if (ret)
> +		return ret;
> +
> +	ret = sysfs_create_group(&pdev->dev.kobj, &lp8788_attr_group);
> +	if (ret) {
> +		lp8788_psy_unregister(pchg);
> +		return ret;
> +	}
> +
> +	ret = lp8788_irq_register(pdev, pchg);
> +	if (ret)
> +		dev_warn(lp->dev, "failed to register charger irq: %d\n", ret);
> +
> +	return 0;
> +}
> +
> +static int __devexit lp8788_charger_remove(struct platform_device *pdev)
> +{
> +	struct lp8788_charger *pchg = platform_get_drvdata(pdev);
> +
> +	if (pchg->charger_work.func)
> +		flush_work_sync(&pchg->charger_work);

You need to flush the work after freeing irqs, otherwise irq might
reschedule it again.

> +	lp8788_irq_unregister(pdev, pchg);

This will probably blow up if you _probe failed to register irq.
To fix this, you probably want to set pchg->num_irqs to 0 if
irq_register() failed.

> +	sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group);
> +	lp8788_psy_unregister(pchg);
> +	lp8788_release_adc_channel(pchg);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver lp8788_charger_driver = {
> +	.probe = lp8788_charger_probe,
> +	.remove = __devexit_p(lp8788_charger_remove),
> +	.driver = {
> +		.name = LP8788_DEV_CHARGER,
> +		.owner = THIS_MODULE,
> +	},
> +};
> +module_platform_driver(lp8788_charger_driver);
> +
> +MODULE_DESCRIPTION("TI LP8788 Charger Driver");
> +MODULE_AUTHOR("Milo Kim");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:lp8788-charger");

Thanks!

Anton.

  reply	other threads:[~2012-08-23  5:56 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-14  2:32 [PATCH v3 2/3] power_supply: add new lp8788 charger driver Kim, Milo
2012-08-23  5:54 ` Anton Vorontsov [this message]
2012-09-05 10:47   ` Kim, Milo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120823055412.GB4849@lizard \
    --to=anton.vorontsov@linaro.org \
    --cc=Milo.Kim@ti.com \
    --cc=jic23@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sameo@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.