All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hui Chun Ong <hui.chun.ong@ni.com>
To: "mika.westerberg@linux.intel.com"
	<mika.westerberg@linux.intel.com>,
	"rjw@rjwysocki.net" <rjw@rjwysocki.net>
Cc: "rpurdie@rpsys.net" <rpurdie@rpsys.net>,
	Julia Cartwright <julia.cartwright@ni.com>,
	"j.anaszewski@samsung.com" <j.anaszewski@samsung.com>,
	"linux-leds@vger.kernel.org" <linux-leds@vger.kernel.org>,
	Jonathan Hearn <jonathan.hearn@ni.com>,
	Brad Mouring <brad.mouring@ni.com>
Subject: Re: [PATCH] leds: Add user LED driver for NIC78bx device
Date: Tue, 25 Oct 2016 10:33:11 +0000	[thread overview]
Message-ID: <1477391577.2682.7.camel@ni.com> (raw)
In-Reply-To: <738565681.7bNtjkuhEA@vostro.rjw.lan>

On Fri, 2016-10-21 at 23:11 +0200, Rafael J. Wysocki wrote:
> On Friday, October 21, 2016 04:06:04 PM Mika Westerberg wrote:
> > 
> > On Fri, Oct 21, 2016 at 02:56:15PM +0200, Jacek Anaszewski wrote:
> > > 
> > > Hi Hui,
> > > 
> > > Thanks for the patch. I have few comments in the code below.
> > > 
> > > On 10/21/2016 08:33 AM, Hui Chun Ong wrote:
> > > > 
> > > > Add the driver to support User LEDs on PXI Embedded Controller.
> > > > 
> > > > Signed-off-by: Hui Chun Ong <hui.chun.ong@ni.com>
> > > > Signed-off-by: Brad Mouring <brad.mouring@ni.com>
> > > > ---
> > > >  drivers/leds/Kconfig       |  11 +++
> > > >  drivers/leds/Makefile      |   1 +
> > > >  drivers/leds/leds-ni78bx.c | 210
> > > > +++++++++++++++++++++++++++++++++++++++++++++
> > > >  3 files changed, 222 insertions(+)
> > > >  create mode 100644 drivers/leds/leds-ni78bx.c
> > > > 
> > > > diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> > > > index 7a628c6..5540795 100644
> > > > --- a/drivers/leds/Kconfig
> > > > +++ b/drivers/leds/Kconfig
> > > > @@ -659,6 +659,17 @@ config LEDS_MLXCPLD
> > > >  	  This option enabled support for the LEDs on the
> > > > Mellanox
> > > >  	  boards. Say Y to enabled these.
> > > > 
> > > > +config LEDS_NI78BX
> > > > +	tristate "LED support for NI PXI NIC78bx devices"
> > > > +	depends on LEDS_CLASS
> > > > +	depends on X86 && ACPI
> > > > +	help
> > > > +	  This option enables support for the User1 and User2
> > > > LEDs on NI
> > > > +	  PXI NIC78bx devices.
> > > > +
> > > > +	  To compile this driver as a module, choose M here:
> > > > the module
> > > > +	  will be called leds-ni78bx.
> > > > +
> > > >  comment "LED Triggers"
> > > >  source "drivers/leds/trigger/Kconfig"
> > > > 
> > > > diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> > > > index 3965070..9758d1e 100644
> > > > --- a/drivers/leds/Makefile
> > > > +++ b/drivers/leds/Makefile
> > > > @@ -71,6 +71,7 @@ obj-$(CONFIG_LEDS_IS31FL319X)		
> > > > += leds-is31fl319x.o
> > > >  obj-$(CONFIG_LEDS_IS31FL32XX)		+= leds-
> > > > is31fl32xx.o
> > > >  obj-$(CONFIG_LEDS_PM8058)		+= leds-pm8058.o
> > > >  obj-$(CONFIG_LEDS_MLXCPLD)		+= leds-mlxcpld.o
> > > > +obj-$(CONFIG_LEDS_NI78BX)		+= leds-ni78bx.o
> > > > 
> > > >  # LED SPI Drivers
> > > >  obj-$(CONFIG_LEDS_DAC124S085)		+= leds-
> > > > dac124s085.o
> > > > diff --git a/drivers/leds/leds-ni78bx.c b/drivers/leds/leds-
> > > > ni78bx.c
> > > > new file mode 100644
> > > > index 0000000..3da4675
> > > > --- /dev/null
> > > > +++ b/drivers/leds/leds-ni78bx.c
> > > > @@ -0,0 +1,210 @@
> > > > +/*
> > > > + * Copyright (C) 2016 National Instruments Corp.
> > > > + *
> > > > + * This program is free software; you can redistribute it
> > > > and/or modify
> > > > + * it under the terms of the GNU General Public License as
> > > > published by
> > > > + * the Free Software Foundation; either version 2 of the
> > > > License, or
> > > > + * (at your option) any later version.
> > > > + *
> > > > + * This program is distributed in the hope that it will be
> > > > useful,
> > > > + * but WITHOUT ANY WARRANTY; without even the implied warranty
> > > > of
> > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> > > > the
> > > > + * GNU General Public License for more details.
> > > > + */
> > > > +
> > > > +#include <linux/acpi.h>
> > > > +#include <linux/leds.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/mutex.h>
> > > > +
> > > > +#define USER1_LED_MASK		0x3
> > > > +#define USER1_GREEN_LED		BIT(0)
> > > > +#define USER1_YELLOW_LED	BIT(1)
> > > > +
> > > > +#define USER2_LED_MASK		0xC
> > > > +#define USER2_GREEN_LED		BIT(2)
> > > > +#define USER2_YELLOW_LED	BIT(3)
> > > > +
> > > > +#define LOCK_REG_OFFSET		1
> > > > +#define LOCK_VALUE		0xA5
> > > > +#define UNLOCK_VALUE		0x5A
> > > Please add NIC78BX namespacing prefix to these macros.
> > > 
> > > > 
> > > > +
> > > > +#define USER_LED_IO_SIZE	2
> > > > +
> > > > +static u16 io_base;
> > > > +static DEFINE_MUTEX(led_lock);
> > > Don't define static variables but instead create a struct that
> > > will aggregate them and allocate it dynamically.
> > > 
> > > > 
> > > > +
> > > > +struct ni78bx_led {
> > > > +	u8 bit;
> > > > +	u8 mask;
> > > > +	struct led_classdev cdev;
> > > > +};
> > > > +
> > > > +static inline struct ni78bx_led *to_ni78bx_led(struct
> > > > led_classdev *cdev)
> > > > +{
> > > > +	return container_of(cdev, struct ni78bx_led, cdev);
> > > > +}
> > > > +
> > > > +static void ni78bx_brightness_set(struct led_classdev *cdev,
> > > > +				  enum led_brightness
> > > > brightness)
> > > > +{
> > > > +	struct ni78bx_led *nled = to_ni78bx_led(cdev);
> > > > +	u8 value;
> > > > +
> > > > +	mutex_lock(&led_lock);
> > > You can use spin_lock_irqsave() instead, since we are not going
> > > to sleep
> > > while accessing memory mapped registers.
> > > 
> > > Note that in the opposite case you would have to use
> > > brightness_set_blocking op.
> > > 
> > > > 
> > > > +
> > > > +	value = inb(io_base);
> > > > +
> > > > +	if (brightness) {
> > > > +		value &= ~nled->mask;
> > > > +		value |= nled->bit;
> > > > +	} else {
> > > > +		value &= ~nled->bit;
> > > > +	}
> > > > +
> > > > +	outb(value, io_base);
> > > > +	mutex_unlock(&led_lock);
> > > > +}
> > > > +
> > > > +static enum led_brightness ni78bx_brightness_get(struct
> > > > led_classdev *cdev)
> > > > +{
> > > > +	struct ni78bx_led *nled = to_ni78bx_led(cdev);
> > > > +	u8 value;
> > > > +
> > > > +	mutex_lock(&led_lock);
> > > > +	value = inb(io_base);
> > > > +	mutex_unlock(&led_lock);
> > > > +
> > > > +	return (value & nled->bit) ? 1 : LED_OFF;
> > > > +}
> > > > +
> > > > +static struct ni78bx_led ni78bx_leds[] = {
> > > > +	{
> > > > +		.bit = USER1_GREEN_LED,
> > > > +		.mask = USER1_LED_MASK,
> > > > +		.cdev = {
> > > > +			.name = "nilrt:green:user1",
> > > > +			.max_brightness = 1,
> > > > +			.brightness_set =
> > > > ni78bx_brightness_set,
> > > > +			.brightness_get =
> > > > ni78bx_brightness_get,
> > > > +		}
> > > > +	},
> > > > +	{
> > > > +		.bit = USER1_YELLOW_LED,
> > > > +		.mask = USER1_LED_MASK,
> > > > +		.cdev = {
> > > > +			.name = "nilrt:yellow:user1",
> > > > +			.max_brightness = 1,
> > > > +			.brightness_set =
> > > > ni78bx_brightness_set,
> > > > +			.brightness_get =
> > > > ni78bx_brightness_get,
> > > > +		}
> > > > +	},
> > > > +	{
> > > > +		.bit = USER2_GREEN_LED,
> > > > +		.mask = USER2_LED_MASK,
> > > > +		.cdev = {
> > > > +			.name = "nilrt:green:user2",
> > > > +			.max_brightness = 1,
> > > > +			.brightness_set =
> > > > ni78bx_brightness_set,
> > > > +			.brightness_get =
> > > > ni78bx_brightness_get,
> > > > +		}
> > > > +	},
> > > > +	{
> > > > +		.bit = USER2_YELLOW_LED,
> > > > +		.mask = USER2_LED_MASK,
> > > > +		.cdev = {
> > > > +			.name = "nilrt:yellow:user2",
> > > > +			.max_brightness = 1,
> > > > +			.brightness_set =
> > > > ni78bx_brightness_set,
> > > > +			.brightness_get =
> > > > ni78bx_brightness_get,
> > > > +		}
> > > > +	}
> > > > +};
> > > > +
> > > > +static acpi_status
> > > > +ni78bx_resources(struct acpi_resource *res, void *data)
> > > > +{
> > > > +	struct acpi_device *led = data;
> > > > +	u16 io_size;
> > > > +
> > > > +	switch (res->type) {
> > > > +	case ACPI_RESOURCE_TYPE_IO:
> > > > +		if (io_base != 0) {
> > > > +			dev_err(&led->dev, "too many IO
> > > > resources\n");
> > > > +			return AE_ERROR;
> > > > +		}
> > > > +
> > > > +		io_base = res->data.io.minimum;
> > > > +		io_size = res->data.io.address_length;
> > > > +
> > > > +		if (io_size < USER_LED_IO_SIZE) {
> > > > +			dev_err(&led->dev, "memory region too
> > > > small\n");
> > > > +			return AE_ERROR;
> > > > +		}
> > > > +
> > > > +		if (!devm_request_region(&led->dev, io_base,
> > > > io_size,
> > > > +					 KBUILD_MODNAME)) {
> > > > +			dev_err(&led->dev, "failed to get
> > > > memory region\n");
> > > > +			return AE_ERROR;
> > > > +		}
> > > > +
> > > > +		return AE_OK;
> > > > +
> > > > +	default:
> > > > +		/* Ignore unsupported resources */
> > > > +		return AE_OK;
> > > > +	}
> > > > +}
> > > > +
> > > > +static int ni78bx_remove(struct acpi_device *pdev)
> > > > +{
> > > > +	/* Lock LED register */
> > > > +	outb(LOCK_VALUE, io_base + LOCK_REG_OFFSET);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int ni78bx_add(struct acpi_device *pdev)
> > > > +{
> > > > +	int ret, i;
> > > > +	acpi_status status;
> > > > +
> > > > +	status = acpi_walk_resources(pdev->handle,
> > > > METHOD_NAME__CRS,
> > > > +				     ni78bx_resources, pdev);
> > > > +
> > > > +	if (ACPI_FAILURE(status) || io_base == 0)
> > > > +		return -ENODEV;
> > > > +
> > > > +	/* Unlock LED register */
> > > > +	outb(UNLOCK_VALUE, io_base + LOCK_REG_OFFSET);
> > > > +
> > > > +	for (i = 0; i < ARRAY_SIZE(ni78bx_leds); i++) {
> > > > +		ret = devm_led_classdev_register(&pdev->dev,
> > > > +						 &ni78bx_leds[
> > > > i].cdev);
> > > > +		if (ret)
> > > > +			return ret;
> > > > +	}
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +
> > > > +static const struct acpi_device_id led_device_ids[] = {
> > > > +	{"NIC78B3", 0},
> > > > +	{"", 0},
> > > CC also ACPI maintainers.
> > > 
> > > > 
> > > > +};
> > > > +MODULE_DEVICE_TABLE(acpi, led_device_ids);
> > > > +
> > > > +static struct acpi_driver led_acpi_driver = {
> > I think you want to have a platform driver here instead.
> Ah, thanks for the heads-up Mika!
> 
> As a rule, struct acpi_driver can only be used by things in
> drivers/acpi/.
> 
> If you think you need it *anyway*, the patch must be CCed to linux-
> acpi and
> it is unlikely to be approved unless you have a very good reason to
> use
> struct acpi_driver and very convincing arguments to support that.
> 
> Thanks,
> Rafael
> 
I'll explore using struct platform_driver. Thanks for your review
feedback.

rgds
Hui Chun

  reply	other threads:[~2016-10-25 14:09 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20161021063441eucas1p221cdc9bd704f03ad367df8cf59fa35e6@eucas1p2.samsung.com>
2016-10-21  6:33 ` [PATCH] leds: Add user LED driver for NIC78bx device Hui Chun Ong
2016-10-21 12:56   ` Jacek Anaszewski
2016-10-21 13:06     ` Mika Westerberg
2016-10-21 21:11       ` Rafael J. Wysocki
2016-10-25 10:33         ` Hui Chun Ong [this message]
2016-10-21 21:33     ` Julia Cartwright
2016-10-23 14:12       ` Jacek Anaszewski
2016-10-25 10:07         ` Hui Chun Ong

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=1477391577.2682.7.camel@ni.com \
    --to=hui.chun.ong@ni.com \
    --cc=brad.mouring@ni.com \
    --cc=j.anaszewski@samsung.com \
    --cc=jonathan.hearn@ni.com \
    --cc=julia.cartwright@ni.com \
    --cc=linux-leds@vger.kernel.org \
    --cc=mika.westerberg@linux.intel.com \
    --cc=rjw@rjwysocki.net \
    --cc=rpurdie@rpsys.net \
    /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.