Re: [PATCH v4 2/2] leds: initial support for Turris Omnia LEDs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 15 Jul 2020 08:27:51 -0500
Dan Murphy <dmurphy@xxxxxx> wrote:

> Can this be built as a module?

Yes. But only if MC framework is compiled in. If MC framework is
compiled as module as well, this results in
  FATAL: modpost: GPL-incompatible module led-class-multicolor.ko uses
  GPL-only symbol 'led_set_brightness'

> > +struct omnia_led {
> > +	struct led_classdev_mc mc_cdev;
> > +	struct mc_subled subled_info[3];  
> nit. #define the 3 and use it here and when indicating the num_colors

Meh, ok


> > +#define to_omnia_led(l)		container_of(l, struct
> > omnia_led, mc_cdev)  
> Spacing look to be off here.

thx

> > +
> > +struct omnia_leds {
> > +	struct i2c_client *client;
> > +	struct mutex lock;
> > +	int nleds;  
> This does  not seem to be used anywhere except for during registering

Hmmm, I'll try to rewrite this

> > +	struct omnia_led leds[0];  
> Remove the 0 as this should be a flexible array

Thx

> > +	led_mc_calc_color_components(&led->mc_cdev, brightness);  
> 
> Do you need this in the lock as well?

You are right

> > +	led->subled_info[0].color_index = LED_COLOR_ID_RED;
> > +	led->subled_info[0].channel = 0;
> > +	led->subled_info[1].color_index = LED_COLOR_ID_GREEN;
> > +	led->subled_info[1].channel = 1;
> > +	led->subled_info[2].color_index = LED_COLOR_ID_BLUE;
> > +	led->subled_info[2].channel = 2;  
> 
> OK this is why you may want to have sub-nodes.  Where reg is the
> channel and color is the color.  Then you can do a for_each_child.

Rob says that it doesn't need to be in DT if the controller only
supports RGB LEDs. This controller is only in Turris Omnia which was
never made with another kind of LEDs. So I think it is pointless and
would only grow the DT and complicate the driver.

> > +	cdev->max_brightness = 255;  
> This is not needed.  It is defaulted to LED_FULL in led_class

This was discussed last year and resulted in LED_FULL being
declared obsolete in the header file.

> > +/*
> > + * On the front panel of the Turris Omnia router there is also a
> > button which can be used to control
> > + * the intensity of all the LEDs at once, so that if they are too
> > bright, user can dim them.
> > + * The microcontroller cycles between 8 levels of this global
> > brightness (from 100% to 0%), but this
> > + * setting can have any integer value between 0 and 100.
> > + * It is usable to be able to change this value from software, so
> > that it does not start at 100%  
> This does not make sense.

It does. The user changes the brightness of all 12 LEDs with the button
to his liking and wants to have the same setting after powering
the router on again.

> > + * after every power on and annoy the user.
> > + * We expose this setting via a sysfs attribute file called
> > "brightness". This file lives in the
> > + * device directory of the LED controller, not an individual LED,
> > so it should not confuse users.
> > + */  
> 
> Sorry if this has been discussed already
> 
> This seems a bit wonky.  You are overriding the brightness set by the 
> LED class.

I am not. Pressing the button does not change the brightness read from
the /sys/class/leds/<LED>/brightness file. This is different brightness,
it is above the classic brightnes in the PWM hierarchy in the
microcontroller. I discussed this with Pavel and he said we can call
this file brightness as well (since it is brightness of the whole
panel), and the file does not reside in /sys/class/leds/<LED> directory.

> Does this button have an interrupt to the processor or does it go to
> the micro controller?
> 
> Where is the current power on value stored?  If this is stored in the 
> micro maybe reading that value at power up and setting the brightness 
> would be better.
> 
> > +static ssize_t brightness_show(struct device *dev, struct
> > device_attribute *a, char *buf) +{
> > +	struct i2c_client *client = to_i2c_client(dev);
> > +	struct omnia_leds *leds = i2c_get_clientdata(client);
> > +	int ret;
> > +
> > +	mutex_lock(&leds->lock);
> > +	ret = i2c_smbus_read_byte_data(client,
> > CMD_LED_GET_BRIGHTNESS);
> > +	mutex_unlock(&leds->lock);
> > +
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", ret);
> > +}
> > +
> > +static ssize_t brightness_store(struct device *dev, struct
> > device_attribute *a, const char *buf,led = &leds->leds[leds->nleds];
> > +				size_t count)
> > +{
> > +	struct i2c_client *client = to_i2c_client(dev);
> > +	struct omnia_leds *leds = i2c_get_clientdata(client);
> > +	unsigned int brightness;
> > +	int ret;
> > +
> > +	if (sscanf(buf, "%u", &brightness) != 1)
> > +		return -EINVAL;
> > +
> > +	if (brightness > 100)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&leds->lock);
> > +	ret = i2c_smbus_write_byte_data(client,
> > CMD_LED_SET_BRIGHTNESS, (u8) brightness);
> > +	mutex_unlock(&leds->lock);
> > +
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	return count;
> > +}
> > +static DEVICE_ATTR_RW(brightness);
> > +
> > +static struct attribute *omnia_led_controller_attrs[] = {
> > +	&dev_attr_brightness.attr,
> > +	NULL,
> > +};
> > +ATTRIBUTE_GROUPS(omnia_led_controller);
> > +
> > +static int omnia_leds_probe(struct i2c_client *client,
> > +			    const struct i2c_device_id *id)
> > +{
> > +	struct device *dev = &client->dev;
> > +	struct device_node *np = dev->of_node, *child;
> > +	struct omnia_leds *leds;
> > +	int ret, count;
> > +
> > +	count = of_get_available_child_count(np);
> > +	if (!count) {
> > +		dev_err(dev, "LEDs are not defined in device
> > tree!\n");
> > +		return -ENODEV;
> > +	} else if (count > OMNIA_BOARD_LEDS) {
> > +		dev_err(dev, "Too many LEDs defined in device
> > tree!\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	leds = devm_kzalloc(dev, sizeof(*leds) + count *
> > sizeof(leds->leds[0]),
> > +			    GFP_KERNEL);  
> Use the macro struct_size(led, leds, count)

thx




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux