public inbox for linux-i2c@vger.kernel.org
 help / color / mirror / Atom feed
From: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
To: David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
Cc: Linux I2C <linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [patch 2.6.27-rc7] i2c: smbalert# support
Date: Wed, 19 Nov 2008 14:57:12 +0100	[thread overview]
Message-ID: <20081119145712.1abaa63f@hyperion.delvare> (raw)
In-Reply-To: <200811181401.34809.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>

Hi David,

(Dropping the lm-sensors list.)

On Tue, 18 Nov 2008 14:01:34 -0800, David Brownell wrote:
> On Tuesday 18 November 2008, Jean Delvare wrote:
> > I guess it's about time that I review this patch and merge it. Is this
> > still the latest version of your code, or do you have anything more
> > recent?
> 
> I don't recall changing any functionality in a long time.
> But I've appended the current patch version, just in case.
> 
> But I did looking at Intel's adapter hardware (i2c-i801)
> and noticing that at least ICH8 -- and probably many older
> versions -- can support SMBus alert IRQs in a way that's
> very compatible with the approach I took.
> 
> - Dave
> 
> 
> ======== SNIP SNIP SNIP!
> From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> 
> Infrastructure supporting SMBALERT# interrupts and the related SMBus
> protocols.  These are defined as "optional" by the SMBus spec.
> 
>  - The i2c_adapter now includes a work_struct doing the work of talking
>    to the Alert Response Address until nobody responds any more (and
>    hence the IRQ is no longer asserted).  Follows SMBus 2.0 not 1.1;
>    there seems to be no point in trying to handle ten-bit addresses.
> 
>  - Some of the ways that work_struct could be driven:
> 
>      * Adapter driver provides an IRQ, which is bound to a handler
>        which schedules that work_struct (using keventd for now).
>        NOTE:  it's nicest if this is edge triggered, but the code
>        should handle level triggered IRQs too.
> 
>      * Adapter driver schedules that work struct itself, maybe even
>        on a workqueue of its own.  It asks the core to set it up by
>        setting i2c_adapter.do_setup_alert ... SMBALERT# could be a
>        subcase of the adapter's normal interrupt handler.  (Or, some
>        boards may want to use polling.)
> 
>  - The "i2c-gpio" driver now handles an optional named resource for
>    that SMBus alert signal.  Named since, when this is substituted
>    for a misbehaving "native" driver, positional ids should be left
>    alone.  (It might be better to put this logic into i2c core, to
>    apply whenever the i2c_adapter.dev.parent is a platform device.)
> 
>  - There's a new driver method used to report that a given device has
>    issued an alert. Its parameter includes the one bit of information
>    provided by the device in its alert response message.
> 
> The IRQ driven code path is always enabled, if it's available.

Overall it looks good to me. Review:

> Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> ---
>  drivers/i2c/busses/i2c-gpio.c |   10 ++
>  drivers/i2c/i2c-core.c        |  155 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/i2c.h           |   14 +++
>  3 files changed, 179 insertions(+)
> 
> --- a/drivers/i2c/busses/i2c-gpio.c
> +++ b/drivers/i2c/busses/i2c-gpio.c
> @@ -82,6 +82,7 @@ static int __devinit i2c_gpio_probe(stru
>  	struct i2c_gpio_platform_data *pdata;
>  	struct i2c_algo_bit_data *bit_data;
>  	struct i2c_adapter *adap;
> +	struct resource *smbalert;
>  	int ret;
>  
>  	pdata = pdev->dev.platform_data;
> @@ -143,6 +144,15 @@ static int __devinit i2c_gpio_probe(stru
>  	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
>  	adap->dev.parent = &pdev->dev;
>  
> +	smbalert = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
> +			"smbalert#");
> +	if (smbalert) {
> +		adap->irq = smbalert->start;
> +		if ((IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)
> +				& smbalert->flags)
> +			adap->alert_edge_triggered = 1;
> +	}
> +
>  	/*
>  	 * If "dev->id" is negative we consider it as zero.
>  	 * The reason to do so is to avoid sysfs names that only make
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -32,6 +32,8 @@
>  #include <linux/platform_device.h>
>  #include <linux/mutex.h>
>  #include <linux/completion.h>
> +#include <linux/interrupt.h>
> +
>  #include <linux/hardirq.h>
>  #include <linux/irqflags.h>
>  #include <asm/uaccess.h>
> @@ -404,6 +406,117 @@ static struct class i2c_adapter_class = 
>  	.dev_attrs		= i2c_adapter_attrs,
>  };
>  
> +struct alert_data {
> +	unsigned short	addr;
> +	bool		flag;
> +};
> +
> +/* If this is the alerting device, notify its driver. */
> +static int i2c_do_alert(struct device *dev, void *addrp)
> +{
> +	struct i2c_client	*client = i2c_verify_client(dev);
> +	struct alert_data	*data = addrp;
> +
> +	if (!client || client->addr != data->addr)
> +		return 0;
> +	if (client->flags & I2C_CLIENT_TEN)
> +		return 0;
> +
> +	/* Drivers should either disable alerts, or provide at least
> +	 * a minimal handler.  Lock so client->driver won't change.
> +	 */
> +	down(&dev->sem);
> +	if (client->driver) {
> +		if (client->driver->alert)
> +			client->driver->alert(client, data->flag);
> +		else
> +			dev_warn(&client->dev, "no driver alert()!\n");
> +	} else
> +		dev_dbg(&client->dev, "alert with no driver\n");
> +	up(&dev->sem);
> +
> +	/* Stop iterating after we find the device. */
> +	return -EBUSY;
> +}
> +
> +/*
> + * The alert IRQ handler needs to hand work off to a task which can issue
> + * SMBus calls, because those sleeping calls can't be made in IRQ context.
> + */
> +static void smbus_alert(struct work_struct *work)
> +{
> +	struct i2c_adapter	*bus;
> +
> +	bus = container_of(work, struct i2c_adapter, alert);
> +	for (;;) {
> +		s32			status;
> +		struct alert_data	data;
> +
> +		/* Devices with pending alerts reply in address order, low
> +		 * to high, because of slave transmit arbitration.  After
> +		 * responding, an SMBus device stops asserting SMBALERT#.
> +		 *
> +		 * NOTE that SMBus 2.0 reserves 10-bit addresess for future
> +		 * use.  We neither handle them, nor try to use PEC here.
> +		 */
> +		status = i2c_smbus_read_byte(bus->ara);
> +		if (status < 0)
> +			break;
> +
> +		data.flag = (status & 1) != 0;

This is equivalent to just "status & 1".

> +		data.addr = status >> 1;
> +		dev_dbg(&bus->dev, "SMBALERT# %s from dev 0x%02x\n",
> +				data.flag ? "true" : "false", data.addr);

The flag is really only a data bit, it has no true/false meaning, so
presenting it that way is confusing. Please display it as 0/1 instead.

> +
> +		/* Notify driver for the device which issued the alert. */
> +		device_for_each_child(&bus->dev, &data, i2c_do_alert);
> +	}
> +
> +	/* We handled all alerts; reenable level-triggered IRQs. */
> +	if (!bus->alert_edge_triggered)
> +		enable_irq(bus->irq);
> +}
> +
> +static irqreturn_t smbus_irq(int irq, void *adap)
> +{
> +	struct i2c_adapter	*bus = adap;
> +
> +	/* Disable level-triggered IRQs until we handle them. */
> +	if (!bus->alert_edge_triggered)
> +		disable_irq_nosync(irq);
> +
> +	schedule_work(&bus->alert);
> +	return IRQ_HANDLED;
> +}
> +
> +static int smbalert_probe(struct i2c_client *c, const struct i2c_device_id *id)
> +{
> +	return 0;
> +}
> +
> +static int smbalert_remove(struct i2c_client *c)
> +{
> +	return 0;
> +}

Please reuse dummy_probe() and dummy_remove(), there's no point in
duplicating these empty functions.

> +
> +static const struct i2c_device_id smbalert_ids[] = {
> +	{ "smbus_alert", 0, },
> +	{ /* LIST END */ }
> +};
> +
> +static struct i2c_driver smbalert_driver = {
> +	.driver = {
> +		.name	= "smbus_alert",
> +	},
> +	.probe		= smbalert_probe,
> +	.remove		= smbalert_remove,
> +	.id_table	= smbalert_ids,
> +};

Or even better... get rid of smbalert_driver altogether and add
{ "smbus_alert", 0 } to dummy_driver instead. This will simplify the
bookkeeping a lot.

> +
> +static const struct i2c_board_info ara_board_info = {
> +	I2C_BOARD_INFO("smbus_alert", 0x0c),
> +};
> +
>  static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
>  {
>  	struct i2c_devinfo	*devinfo;
> @@ -448,6 +561,9 @@ static int i2c_register_adapter(struct i
>  	mutex_init(&adap->clist_lock);
>  	INIT_LIST_HEAD(&adap->clients);
>  
> +	/* Setup SMBALERT# infrastructure. */
> +	INIT_WORK(&adap->alert, smbus_alert);
> +
>  	mutex_lock(&core_lock);
>  
>  	/* Add the adapter to the driver core.
> @@ -466,6 +582,33 @@ static int i2c_register_adapter(struct i
>  	if (res)
>  		goto out_list;
>  
> +	/* If we'll be handling SMBus alerts, register the alert responder
> +	 * address so that nobody else can accidentally claim it.
> +	 * Handling can be done either through our IRQ handler, or by the
> +	 * adapter (from its handler, periodic polling, or whatever).
> +	 *
> +	 * NOTE that if we manage the IRQ, we *MUST* know if it's level or
> +	 * edge triggered in order to hand it to the workqueue correctly.
> +	 * If triggering the alert seems to wedge the system, you probably
> +	 * should have said it's level triggered.
> +	 */
> +	if (adap->irq > 0 || adap->do_setup_alert)
> +		adap->ara = i2c_new_device(adap, &ara_board_info);
> +
> +	if (adap->irq > 0 && adap->ara) {
> +		res = devm_request_irq(&adap->dev, adap->irq, smbus_irq,
> +				0, "smbus_alert", adap);
> +		if (res == 0) {
> +			dev_info(&adap->dev,
> +				"supports SMBALERT#, %s trigger\n",
> +				adap->alert_edge_triggered
> +					? "edge" : "level");
> +			adap->has_alert_irq = 1;
> +		} else
> +			res = 0;
> +

Extra blank line.

> +	}
> +
>  	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
>  
>  	/* create pre-declared device nodes for new-style drivers */
> @@ -651,6 +794,12 @@ int i2c_del_adapter(struct i2c_adapter *
>  		}
>  	}
>  
> +	if (adap->has_alert_irq) {
> +		devm_free_irq(&adap->dev, adap->irq, adap);
> +		adap->has_alert_irq = 0;
> +	}
> +	cancel_work_sync(&adap->alert);
> +
>  	/* clean up the sysfs representation */
>  	init_completion(&adap->dev_released);
>  	device_unregister(&adap->dev);
> @@ -970,12 +1119,17 @@ static int __init i2c_init(void)
>  	retval = class_register(&i2c_adapter_class);
>  	if (retval)
>  		goto bus_err;
> +	retval = i2c_add_driver(&smbalert_driver);
> +	if (retval)
> +		goto alert_err;
>  	retval = i2c_add_driver(&dummy_driver);
>  	if (retval)
>  		goto class_err;
>  	return 0;
>  
>  class_err:
> +	i2c_del_driver(&smbalert_driver);
> +alert_err:
>  	class_unregister(&i2c_adapter_class);
>  bus_err:
>  	bus_unregister(&i2c_bus_type);
> @@ -986,6 +1140,7 @@ static void __exit i2c_exit(void)
>  {
>  	i2c_del_driver(&dummy_driver);
>  	class_unregister(&i2c_adapter_class);
> +	i2c_del_driver(&smbalert_driver);
>  	bus_unregister(&i2c_bus_type);
>  }
>  
> --- a/include/linux/i2c.h
> +++ b/include/linux/i2c.h
> @@ -34,6 +34,7 @@
>  #include <linux/device.h>	/* for struct device */
>  #include <linux/sched.h>	/* for completion */
>  #include <linux/mutex.h>
> +#include <linux/workqueue.h>
>  
>  extern struct bus_type i2c_bus_type;
>  
> @@ -165,6 +166,11 @@ struct i2c_driver {
>  	int (*suspend)(struct i2c_client *, pm_message_t mesg);
>  	int (*resume)(struct i2c_client *);
>  
> +	/* SMBus alert protocol support.  The alert response's low bit
> +	 * is the event flag (e.g. exceeding upper vs lower limit).
> +	 */
> +	void (*alert)(struct i2c_client *, bool flag);
> +
>  	/* a ioctl like command that can be used to perform specific functions
>  	 * with the device.
>  	 */
> @@ -369,6 +375,14 @@ struct i2c_adapter {
>  	struct list_head clients;	/* DEPRECATED */
>  	char name[48];
>  	struct completion dev_released;
> +
> +	/* SMBALERT# support */
> +	unsigned		do_setup_alert:1;
> +	unsigned		has_alert_irq:1;
> +	unsigned		alert_edge_triggered:1;
> +	int			irq;
> +	struct i2c_client	*ara;
> +	struct work_struct	alert;
>  };
>  #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)

It would be nice to have kernel doc for all these new struct members.

I also would like you to document the new API, either in
Documentation/i2c or Documentation/DocBook/kernel-api.tmpl, as you
prefer. This new API is not trivial and there's only one example in the
kernel tree at the moment (i2c-gpio) so driver authors will need
detailed information on how to add support for SMBus alert in their bus
and chip drivers.

As a side note, I tried to add support for SMBus alert to the
i2c-parport driver, but I can't get it to work. I'll post my patch
later today in case someone has an idea what I am doing wrong.

Thanks,
-- 
Jean Delvare

  parent reply	other threads:[~2008-11-19 13:57 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <200804161434.54335.laurentp@cse-semaphore.com>
     [not found] ` <20080416153043.02f89554@hyperion.delvare>
     [not found]   ` <200804161027.49943.david-b@pacbell.net>
     [not found]     ` <200804161027.49943.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-05-02 11:10       ` [patch 2.6.25-git] i2c: smbalert# support David Brownell
     [not found]         ` <200805020410.44723.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-05-05  5:56           ` [patch 2.6.265-rc1] " David Brownell
     [not found]             ` <200805042256.49252.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-09-23 22:32               ` [patch 2.6.27-rc7] " David Brownell
     [not found]                 ` <200809231532.40083.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-09-26  1:07                   ` [lm-sensors] " Trent Piepho
     [not found]                     ` <Pine.LNX.4.64.0809251728130.7680-3bmvVOk6DZ+DGx/iekXGtrjh7zpefjiS@public.gmane.org>
2008-09-26  2:01                       ` David Brownell
     [not found]                         ` <200809251902.00201.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-09-27  0:29                           ` Trent Piepho
     [not found]                             ` <Pine.LNX.4.64.0809261652040.7680-3bmvVOk6DZ+DGx/iekXGtrjh7zpefjiS@public.gmane.org>
2008-10-17 19:04                               ` David Brownell
     [not found]                                 ` <200810171204.54448.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-10-17 20:43                                   ` Trent Piepho
2008-11-18  8:15                   ` Jean Delvare
     [not found]                     ` <20081118091546.421d6b78-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-18 22:01                       ` David Brownell
     [not found]                         ` <200811181401.34809.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-11-19  9:51                           ` [lm-sensors] " Trent Piepho
     [not found]                             ` <Pine.LNX.4.64.0811190140510.11673-3bmvVOk6DZ+DGx/iekXGtrjh7zpefjiS@public.gmane.org>
2008-11-19 15:16                               ` Jean Delvare
     [not found]                                 ` <20081119161632.2d0bde9e-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-20 22:00                                   ` Trent Piepho
     [not found]                                     ` <Pine.LNX.4.64.0811201354310.11673-3bmvVOk6DZ+DGx/iekXGtrjh7zpefjiS@public.gmane.org>
2008-11-20 22:56                                       ` David Brownell
     [not found]                                         ` <200811201456.36551.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-11-22  0:55                                           ` Trent Piepho
     [not found]                                             ` <Pine.LNX.4.64.0811211621340.18022-3bmvVOk6DZ+DGx/iekXGtrjh7zpefjiS@public.gmane.org>
2008-11-22  2:58                                               ` David Brownell
2008-11-21  8:42                                       ` Jean Delvare
     [not found]                                         ` <20081121094218.34ecd82a-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-22  6:04                                           ` Trent Piepho
     [not found]                                             ` <Pine.LNX.4.64.0811212122370.18022-3bmvVOk6DZ+DGx/iekXGtrjh7zpefjiS@public.gmane.org>
2008-11-22 10:13                                               ` Jean Delvare
     [not found]                                                 ` <20081122111340.0bfc2c05-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-22 20:28                                                   ` Trent Piepho
     [not found]                                                     ` <Pine.LNX.4.64.0811221055470.18022-3bmvVOk6DZ+DGx/iekXGtrjh7zpefjiS@public.gmane.org>
2008-11-23 21:45                                                       ` Jean Delvare
2008-11-19 13:57                           ` Jean Delvare [this message]
     [not found]                             ` <20081119145712.1abaa63f-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-19 18:08                               ` David Brownell
2008-11-21 14:18                           ` Jean Delvare
     [not found]                             ` <20081121151808.324ca78c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-21 16:24                               ` David Brownell
     [not found]                                 ` <200811210824.55601.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-11-21 19:22                                   ` Jean Delvare
     [not found]                                     ` <20081121202223.0261fb9c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-21 21:54                                       ` David Brownell
     [not found]                                         ` <200811211354.51501.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2008-11-22  9:03                                           ` Jean Delvare
     [not found]                                             ` <20081122100344.61cf42b7-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-11-22  9:48                                               ` David Brownell

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=20081119145712.1abaa63f@hyperion.delvare \
    --to=khali-puyad+kwke1g9huczpvpmw@public.gmane.org \
    --cc=david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org \
    --cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox