Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c574cf6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull LED updates from Bryan Wu:
 "I just found merge window is open and I'm quite busy and almost forget
  to send out this pull request.  Thanks Russell and Alexandre ping me
  about this.

  So basically we got some clean up and leds-pwm fixing patches from
  Russell"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds:
  leds: Remove duplicated OOM message for individual driver
  drivers/leds: Replace __get_cpu_var use through this_cpu_ptr
  leds: lp55xx: add DT bindings for LP55231
  leds: 88pm860x: Fix missing refcount decrement for parent of_node
  leds: 88pm860x: Use of_get_child_by_name
  leds: leds-pwm: add DT support for LEDs wired to supply
  leds: leds-pwm: implement PWM inversion
  leds: leds-pwm: convert OF parsing code to use led_pwm_add()
  leds: leds-pwm: provide a common function to setup a single led-pwm device
  leds: pca9685: Remove leds-pca9685 driver
  dell-led: add mic mute led interface
parents af76004c 0c9a03b6
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
Binding for TI/National Semiconductor LP55xx Led Drivers

Required properties:
- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562" or "ti,lp8501"
- compatible: one of
	national,lp5521
	national,lp5523
	ti,lp55231
	ti,lp5562
	ti,lp8501

- reg: I2C slave address
- clock-mode: Input clock mode, (0: automode, 1: internal, 2: external)

+2 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@ LED sub-node properties:
  For the pwms and pwm-names property please refer to:
  Documentation/devicetree/bindings/pwm/pwm.txt
- max-brightness : Maximum brightness possible for the LED
- active-low : (optional) For PWMs where the LED is wired to supply
  rather than ground.
- label :  (optional)
  see Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger :  (optional)
+0 −10
Original line number Diff line number Diff line
@@ -300,16 +300,6 @@ config LEDS_PCA963X
	  LED driver chip accessed via the I2C bus. Supported
	  devices include PCA9633 and PCA9634

config LEDS_PCA9685
	tristate "LED support for PCA9685 I2C chip"
	depends on LEDS_CLASS
	depends on I2C
	help
	  This option enables support for LEDs connected to the PCA9685
	  LED driver chip accessed via the I2C bus.
	  The PCA9685 offers 12-bit PWM (4095 levels of brightness) on
	  16 individual channels.

config LEDS_WM831X_STATUS
	tristate "LED support for status LEDs on WM831x PMICs"
	depends on LEDS_CLASS
+0 −1
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o
obj-$(CONFIG_LEDS_FSG)			+= leds-fsg.o
obj-$(CONFIG_LEDS_PCA955X)		+= leds-pca955x.o
obj-$(CONFIG_LEDS_PCA963X)		+= leds-pca963x.o
obj-$(CONFIG_LEDS_PCA9685)		+= leds-pca9685.o
obj-$(CONFIG_LEDS_DA903X)		+= leds-da903x.o
obj-$(CONFIG_LEDS_DA9052)		+= leds-da9052.o
obj-$(CONFIG_LEDS_WM831X_STATUS)	+= leds-wm831x-status.o
+164 −7
Original line number Diff line number Diff line
@@ -15,12 +15,15 @@
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/dell-led.h>

MODULE_AUTHOR("Louis Davis/Jim Dailey");
MODULE_DESCRIPTION("Dell LED Control Driver");
MODULE_LICENSE("GPL");

#define DELL_LED_BIOS_GUID "F6E4FE6E-909D-47cb-8BAB-C9F6F2F8D396"
#define DELL_APP_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);

/* Error Result Codes: */
@@ -39,6 +42,149 @@ MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);
#define CMD_LED_OFF	17
#define CMD_LED_BLINK	18

struct app_wmi_args {
	u16 class;
	u16 selector;
	u32 arg1;
	u32 arg2;
	u32 arg3;
	u32 arg4;
	u32 res1;
	u32 res2;
	u32 res3;
	u32 res4;
	char dummy[92];
};

#define GLOBAL_MIC_MUTE_ENABLE	0x364
#define GLOBAL_MIC_MUTE_DISABLE	0x365

struct dell_bios_data_token {
	u16 tokenid;
	u16 location;
	u16 value;
};

struct __attribute__ ((__packed__)) dell_bios_calling_interface {
	struct	dmi_header header;
	u16	cmd_io_addr;
	u8	cmd_io_code;
	u32	supported_cmds;
	struct	dell_bios_data_token damap[];
};

static struct dell_bios_data_token dell_mic_tokens[2];

static int dell_wmi_perform_query(struct app_wmi_args *args)
{
	struct app_wmi_args *bios_return;
	union acpi_object *obj;
	struct acpi_buffer input;
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
	acpi_status status;
	u32 rc = -EINVAL;

	input.length = 128;
	input.pointer = args;

	status = wmi_evaluate_method(DELL_APP_GUID, 0, 1, &input, &output);
	if (!ACPI_SUCCESS(status))
		goto err_out0;

	obj = output.pointer;
	if (!obj)
		goto err_out0;

	if (obj->type != ACPI_TYPE_BUFFER)
		goto err_out1;

	bios_return = (struct app_wmi_args *)obj->buffer.pointer;
	rc = bios_return->res1;
	if (rc)
		goto err_out1;

	memcpy(args, bios_return, sizeof(struct app_wmi_args));
	rc = 0;

 err_out1:
	kfree(obj);
 err_out0:
	return rc;
}

static void __init find_micmute_tokens(const struct dmi_header *dm, void *dummy)
{
	struct dell_bios_calling_interface *calling_interface;
	struct dell_bios_data_token *token;
	int token_size = sizeof(struct dell_bios_data_token);
	int i = 0;

	if (dm->type == 0xda && dm->length > 17) {
		calling_interface = container_of(dm,
				struct dell_bios_calling_interface, header);

		token = &calling_interface->damap[i];
		while (token->tokenid != 0xffff) {
			if (token->tokenid == GLOBAL_MIC_MUTE_DISABLE)
				memcpy(&dell_mic_tokens[0], token, token_size);
			else if (token->tokenid == GLOBAL_MIC_MUTE_ENABLE)
				memcpy(&dell_mic_tokens[1], token, token_size);

			i++;
			token = &calling_interface->damap[i];
		}
	}
}

static int dell_micmute_led_set(int state)
{
	struct app_wmi_args args;
	struct dell_bios_data_token *token;

	if (!wmi_has_guid(DELL_APP_GUID))
		return -ENODEV;

	if (state == 0 || state == 1)
		token = &dell_mic_tokens[state];
	else
		return -EINVAL;

	memset(&args, 0, sizeof(struct app_wmi_args));

	args.class = 1;
	args.arg1 = token->location;
	args.arg2 = token->value;

	dell_wmi_perform_query(&args);

	return state;
}

int dell_app_wmi_led_set(int whichled, int on)
{
	int state = 0;

	switch (whichled) {
	case DELL_LED_MICMUTE:
		state = dell_micmute_led_set(on);
		break;
	default:
		pr_warn("led type %x is not supported\n", whichled);
		break;
	}

	return state;
}
EXPORT_SYMBOL_GPL(dell_app_wmi_led_set);

static int __init dell_micmute_led_init(void)
{
	memset(dell_mic_tokens, 0, sizeof(struct dell_bios_data_token) * 2);
	dmi_walk(find_micmute_tokens, NULL);

	return 0;
}

struct bios_args {
	unsigned char length;
	unsigned char result_code;
@@ -181,21 +327,32 @@ static int __init dell_led_init(void)
{
	int error = 0;

	if (!wmi_has_guid(DELL_LED_BIOS_GUID))
	if (!wmi_has_guid(DELL_LED_BIOS_GUID) && !wmi_has_guid(DELL_APP_GUID))
		return -ENODEV;

	if (wmi_has_guid(DELL_APP_GUID))
		error = dell_micmute_led_init();

	if (wmi_has_guid(DELL_LED_BIOS_GUID)) {
		error = led_off();
		if (error != 0)
			return -ENODEV;

	return led_classdev_register(NULL, &dell_led);
		error = led_classdev_register(NULL, &dell_led);
	}

	return error;
}

static void __exit dell_led_exit(void)
{
	led_classdev_unregister(&dell_led);
	int error = 0;

	led_off();
	if (wmi_has_guid(DELL_LED_BIOS_GUID)) {
		error = led_off();
		if (error == 0)
			led_classdev_unregister(&dell_led);
	}
}

module_init(dell_led_init);
Loading