From: Samuel Ortiz <sameo@linux.intel.com>
To: Mike Frysinger <vapier@gentoo.org>
Cc: linux-kernel@vger.kernel.org,
uclinux-dist-devel@blackfin.uclinux.org,
Michael Hennerich <michael.hennerich@analog.com>,
Bryan Wu <cooloney@kernel.org>
Subject: Re: [PATCH v2] mfd: ADP5520 Multifunction LCD Backlight and Keypad Input Device Driver
Date: Thu, 1 Oct 2009 16:09:49 +0200 [thread overview]
Message-ID: <20091001140948.GD10199@sortiz.org> (raw)
In-Reply-To: <1253682664-27040-1-git-send-email-vapier@gentoo.org>
Hi Mike,
Some comments on this patch:
On Wed, Sep 23, 2009 at 01:11:04AM -0400, Mike Frysinger wrote:
> From: Michael Hennerich <michael.hennerich@analog.com>
>
> Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs
>
> Subdevs:
> LCD Backlight : drivers/video/backlight/adp5520_bl
> LEDs : drivers/led/leds-adp5520
> GPIO : drivers/gpio/adp5520-gpio (ADP5520 only)
> Keys : drivers/input/keyboard/adp5520-keys (ADP5520 only)
>
> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
> Signed-off-by: Bryan Wu <cooloney@kernel.org>
> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
> ---
> v2
> - fix return type of irq handler
> - fix unbalanced paren in BL_CTRL_VAL() macro
>
> drivers/mfd/Kconfig | 10 ++
> drivers/mfd/Makefile | 1 +
> drivers/mfd/adp5520.c | 371 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/adp5520.h | 303 +++++++++++++++++++++++++++++++++++
> 4 files changed, 685 insertions(+), 0 deletions(-)
> create mode 100644 drivers/mfd/adp5520.c
> create mode 100644 include/linux/mfd/adp5520.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 570be13..34e8595 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -160,6 +160,16 @@ config PMIC_DA903X
> individual components like LCD backlight, voltage regulators,
> LEDs and battery-charger under the corresponding menus.
>
> +config PMIC_ADP5520
> + bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
> + depends on I2C=y
> + help
> + Say yes here to add support for Analog Devices AD5520 and ADP5501,
> + Multifunction Power Management IC. This includes
> + the I2C driver and the core APIs _only_, you have to select
> + individual components like LCD backlight, LEDs, GPIOs and Kepad
> + under the corresponding menus.
> +
> config MFD_WM8400
> tristate "Support Wolfson Microelectronics WM8400"
> select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index f3b277b..a42248e 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -50,3 +50,4 @@ obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
> obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
> obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
> obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
> +obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
> diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
> new file mode 100644
> index 0000000..1083626
> --- /dev/null
> +++ b/drivers/mfd/adp5520.c
> @@ -0,0 +1,371 @@
> +/*
> + * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs
> + * LCD Backlight: drivers/video/backlight/adp5520_bl
> + * LEDs : drivers/led/leds-adp5520
> + * GPIO : drivers/gpio/adp5520-gpio (ADP5520 only)
> + * Keys : drivers/input/keyboard/adp5520-keys (ADP5520 only)
> + *
> + * Copyright 2009 Analog Devices Inc.
> + *
> + * Derived from da903x:
> + * Copyright (C) 2008 Compulab, Ltd.
> + * Mike Rapoport <mike@compulab.co.il>
> + *
> + * Copyright (C) 2006-2008 Marvell International Ltd.
> + * Eric Miao <eric.miao@marvell.com>
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/workqueue.h>
> +#include <linux/i2c.h>
> +
> +#include <linux/mfd/adp5520.h>
> +
> +struct adp5520_chip {
> + struct i2c_client *client;
> + struct device *dev;
> + struct mutex lock;
> + struct work_struct irq_work;
> + struct blocking_notifier_head notifier_list;
> + int irq;
> +};
> +
> +static int __adp5520_read(struct i2c_client *client,
> + int reg, uint8_t *val)
> +{
> + int ret;
> +
> + ret = i2c_smbus_read_byte_data(client, reg);
> + if (ret < 0) {
> + dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
> + return ret;
> + }
> +
> + *val = (uint8_t)ret;
> + return 0;
> +}
> +
> +static int __adp5520_write(struct i2c_client *client,
> + int reg, uint8_t val)
> +{
> + int ret;
> +
> + ret = i2c_smbus_write_byte_data(client, reg, val);
> + if (ret < 0) {
> + dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
> + val, reg);
> + return ret;
> + }
> + return 0;
> +}
> +
> +int __adp5520_ack_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
> +{
> + struct adp5520_chip *chip = i2c_get_clientdata(client);
> + uint8_t reg_val;
> + int ret;
> +
> + mutex_lock(&chip->lock);
> +
> + ret = __adp5520_read(client, reg, ®_val);
> +
> + if (!ret) {
> + reg_val |= bit_mask;
> + ret = __adp5520_write(client, reg, reg_val);
> + }
> +
> + mutex_unlock(&chip->lock);
> + return ret;
> +}
> +
> +int adp5520_write(struct device *dev, int reg, uint8_t val)
> +{
> + return __adp5520_write(to_i2c_client(dev), reg, val);
> +}
> +EXPORT_SYMBOL_GPL(adp5520_write);
> +
> +int adp5520_read(struct device *dev, int reg, uint8_t *val)
> +{
> + return __adp5520_read(to_i2c_client(dev), reg, val);
> +}
> +EXPORT_SYMBOL_GPL(adp5520_read);
> +
> +int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask)
> +{
> + struct adp5520_chip *chip = dev_get_drvdata(dev);
> + uint8_t reg_val;
> + int ret;
> +
> + mutex_lock(&chip->lock);
> +
> + ret = __adp5520_read(chip->client, reg, ®_val);
> +
> + if (!ret && ((reg_val & bit_mask) == 0)) {
> + reg_val |= bit_mask;
> + ret = __adp5520_write(chip->client, reg, reg_val);
> + }
> +
> + mutex_unlock(&chip->lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(adp5520_set_bits);
> +
> +int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
> +{
> + struct adp5520_chip *chip = dev_get_drvdata(dev);
> + uint8_t reg_val;
> + int ret;
> +
> + mutex_lock(&chip->lock);
> +
> + ret = __adp5520_read(chip->client, reg, ®_val);
> +
> + if (!ret && (reg_val & bit_mask)) {
> + reg_val &= ~bit_mask;
> + ret = __adp5520_write(chip->client, reg, reg_val);
> + }
> +
> + mutex_unlock(&chip->lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(adp5520_clr_bits);
> +
> +int adp5520_register_notifier(struct device *dev, struct notifier_block *nb,
> + unsigned int events)
> +{
> + struct adp5520_chip *chip = dev_get_drvdata(dev);
> +
> + if (chip->irq) {
> + adp5520_set_bits(chip->dev, INTERRUPT_ENABLE,
> + events & (KP_IEN | KR_IEN | OVP_IEN | CMPR_IEN));
> +
> + return blocking_notifier_chain_register(&chip->notifier_list,
> + nb);
> + }
> +
> + return -ENODEV;
> +}
> +EXPORT_SYMBOL_GPL(adp5520_register_notifier);
> +
> +int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb,
> + unsigned int events)
> +{
> + struct adp5520_chip *chip = dev_get_drvdata(dev);
> +
> + adp5520_clr_bits(chip->dev, INTERRUPT_ENABLE,
> + events & (KP_IEN | KR_IEN | OVP_IEN | CMPR_IEN));
> +
> + return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
> +}
> +EXPORT_SYMBOL_GPL(adp5520_unregister_notifier);
> +
> +static void adp5520_irq_work(struct work_struct *work)
> +{
> + struct adp5520_chip *chip =
> + container_of(work, struct adp5520_chip, irq_work);
> + unsigned int events;
> + uint8_t reg_val;
> + int ret;
> +
> + ret = __adp5520_read(chip->client, MODE_STATUS, ®_val);
> + if (ret)
> + goto out;
> +
> + events = reg_val & (OVP_INT | CMPR_INT | GPI_INT | KR_INT | KP_INT);
> +
> + blocking_notifier_call_chain(&chip->notifier_list, events, NULL);
> + /* ACK, Sticky bits are W1C */
> + __adp5520_ack_bits(chip->client, MODE_STATUS, events);
> +
> +out:
> + enable_irq(chip->client->irq);
> +}
> +
> +static irqreturn_t adp5520_irq_handler(int irq, void *data)
> +{
> + struct adp5520_chip *chip = data;
> +
> + disable_irq_nosync(irq);
> + schedule_work(&chip->irq_work);
Have you considered using a threaded irq handler here ?
> + return IRQ_HANDLED;
> +}
> +
> +static int __remove_subdev(struct device *dev, void *unused)
> +{
> + platform_device_unregister(to_platform_device(dev));
> + return 0;
> +}
> +
> +static int adp5520_remove_subdevs(struct adp5520_chip *chip)
> +{
> + return device_for_each_child(chip->dev, NULL, __remove_subdev);
> +}
> +
> +static int __devinit adp5520_add_subdevs(struct adp5520_chip *chip,
> + struct adp5520_platform_data *pdata)
> +{
> + struct adp5520_subdev_info *subdev;
> + struct platform_device *pdev;
> + int i, ret = 0;
> +
> + for (i = 0; i < pdata->num_subdevs; i++) {
> + subdev = &pdata->subdevs[i];
> +
> + pdev = platform_device_alloc(subdev->name, subdev->id);
> +
> + pdev->dev.parent = chip->dev;
> + pdev->dev.platform_data = subdev->platform_data;
> +
> + ret = platform_device_add(pdev);
> + if (ret)
> + goto failed;
> + }
> + return 0;
Here I would expect the MFD core driver to know about all the potential
subdevices and add them in that routine, and not take the subdevices list from
the platform definition.
I realize da903x has the same issue btw.
Also, please note that you could use the mfd-core API for adding devices, but
that's just optional.
Cheers,
Samuel.
--
Intel Open Source Technology Centre
http://oss.intel.com/
next prev parent reply other threads:[~2009-10-01 14:08 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-17 18:27 [PATCH] mfd: ADP5520 Multifunction LCD Backlight and Keypad Input Device Driver Mike Frysinger
2009-09-23 5:11 ` [PATCH v2] " Mike Frysinger
2009-09-29 21:04 ` [Uclinux-dist-devel] " Mike Frysinger
2009-09-29 21:14 ` Andrew Morton
2009-09-29 21:19 ` Mike Frysinger
2009-09-29 21:31 ` Samuel Ortiz
2009-09-29 21:19 ` Andrew Morton
2009-09-29 21:57 ` Hennerich, Michael
2009-10-01 14:09 ` Samuel Ortiz [this message]
2009-10-02 9:38 ` Hennerich, Michael
2009-10-02 13:15 ` Samuel Ortiz
2009-10-02 14:39 ` Hennerich, Michael
2009-10-02 13:48 ` [Uclinux-dist-devel] [PATCH v2] mfd: ADP5520 Multifunction LCDBacklight " Hennerich, Michael
2009-10-02 14:05 ` Samuel Ortiz
2009-10-02 14:27 ` Mark Brown
2009-10-02 14:37 ` [Uclinux-dist-devel] [PATCH v2] mfd: ADP5520 MultifunctionLCDBacklight " Hennerich, Michael
2009-10-02 14:38 ` Mark Brown
2009-10-02 15:24 ` [Uclinux-dist-devel] [PATCH v2] mfd: ADP5520MultifunctionLCDBacklight " Hennerich, Michael
2009-10-06 7:44 ` [PATCH v3] mfd: ADP5520 Multifunction LCD Backlight " Mike Frysinger
2009-10-06 11:55 ` Mark Brown
2009-10-06 12:23 ` [PATCH v3] mfd: ADP5520 Multifunction LCD Backlight and KeypadInput " Hennerich, Michael
2009-10-06 12:36 ` Mark Brown
2009-10-06 12:55 ` Hennerich, Michael
2009-10-06 13:58 ` Mark Brown
2009-10-06 14:32 ` Hennerich, Michael
2009-10-06 14:48 ` Mark Brown
2009-10-06 15:05 ` Hennerich, Michael
2009-10-06 16:05 ` Mark Brown
2009-10-07 8:50 ` Hennerich, Michael
2009-10-07 10:06 ` Mark Brown
2009-10-07 12:11 ` Hennerich, Michael
2009-10-07 13:03 ` Mark Brown
2009-10-07 13:01 ` Hennerich, Michael
2009-10-07 13:19 ` Mark Brown
2009-10-07 13:35 ` Hennerich, Michael
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=20091001140948.GD10199@sortiz.org \
--to=sameo@linux.intel.com \
--cc=cooloney@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.hennerich@analog.com \
--cc=uclinux-dist-devel@blackfin.uclinux.org \
--cc=vapier@gentoo.org \
/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.