diff mbox series

[v1,3/6] leds: Add driver for Acer Iconia Tab A500

Message ID 20200823140846.19299-4-digetx@gmail.com (mailing list archive)
State Not Applicable, archived
Headers show
Series Introduce Embedded Controller driver for Acer A500 | expand

Commit Message

Dmitry Osipenko Aug. 23, 2020, 2:08 p.m. UTC
Acer Iconia Tab A500 is an Android tablet device which has two LEDs
embedded into the Power Button. Orange LED indicates "battery charging"
status and white LED indicates "wake-up/charge-done" status. The new LED
driver provides control over both LEDs to userspace.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/leds/Kconfig          |   7 ++
 drivers/leds/Makefile         |   1 +
 drivers/leds/leds-acer-a500.c | 121 ++++++++++++++++++++++++++++++++++
 3 files changed, 129 insertions(+)
 create mode 100644 drivers/leds/leds-acer-a500.c

Comments

Pavel Machek Aug. 23, 2020, 10:30 p.m. UTC | #1
Hi!

> Acer Iconia Tab A500 is an Android tablet device which has two LEDs
> embedded into the Power Button. Orange LED indicates "battery charging"
> status and white LED indicates "wake-up/charge-done" status. The new LED
> driver provides control over both LEDs to userspace.

> @@ -0,0 +1,121 @@
> +// SPDX-License-Identifier: GPL-2.0+

Nice.

> + * Copyright 2020 GRATE-driver project.

Probably untrue.


> +	white_led->cdev.name = "power-button-white";

"white:power"

> +	white_led->cdev.max_brightness = LED_ON;

= 1. (And you'll need other adjustments over the code).

> +	orange_led->cdev.name = "power-button-orange";

"orange:power" -- or what is this LED usually used for?

> +MODULE_LICENSE("GPL v2");

Should be "GPL"?
									Pavel
Pavel Machek Aug. 23, 2020, 10:34 p.m. UTC | #2
On Sun 2020-08-23 17:08:43, Dmitry Osipenko wrote:
> Acer Iconia Tab A500 is an Android tablet device which has two LEDs
> embedded into the Power Button. Orange LED indicates "battery charging"
> status and white LED indicates "wake-up/charge-done" status. The new LED
> driver provides control over both LEDs to userspace.

Hmm. If the ENE controller is similar to other devices, should it also
share LED driver?

And I guess the cdev names should be different based on info above (I
gave you wrong suggestions before)... and they probably should be
parsed from the device tree.

Best regards,
									Pavel
Dmitry Osipenko Aug. 24, 2020, 10:11 a.m. UTC | #3
24.08.2020 01:30, Pavel Machek пишет:
> Hi!

Hello, Pavel! Thank you very much for the review! I'll take into account
yours comments in the v2!

>> Acer Iconia Tab A500 is an Android tablet device which has two LEDs
>> embedded into the Power Button. Orange LED indicates "battery charging"
>> status and white LED indicates "wake-up/charge-done" status. The new LED
>> driver provides control over both LEDs to userspace.
> 
>> @@ -0,0 +1,121 @@
>> +// SPDX-License-Identifier: GPL-2.0+
> 
> Nice.
> 
>> + * Copyright 2020 GRATE-driver project.
> 
> Probably untrue.
> 
> 
>> +	white_led->cdev.name = "power-button-white";
> 
> "white:power"
> 
>> +	white_led->cdev.max_brightness = LED_ON;
> 
> = 1. (And you'll need other adjustments over the code).
> 
>> +	orange_led->cdev.name = "power-button-orange";
> 
> "orange:power" -- or what is this LED usually used for?
> 
>> +MODULE_LICENSE("GPL v2");
> 
> Should be "GPL"?

Yes, apparently it should be "GPL". I'll try to double-check it for the v2.

Thanks!
Dmitry Osipenko Aug. 24, 2020, 10:16 a.m. UTC | #4
24.08.2020 01:34, Pavel Machek пишет:
> On Sun 2020-08-23 17:08:43, Dmitry Osipenko wrote:
>> Acer Iconia Tab A500 is an Android tablet device which has two LEDs
>> embedded into the Power Button. Orange LED indicates "battery charging"
>> status and white LED indicates "wake-up/charge-done" status. The new LED
>> driver provides control over both LEDs to userspace.
> 
> Hmm. If the ENE controller is similar to other devices, should it also
> share LED driver?
> 
> And I guess the cdev names should be different based on info above (I
> gave you wrong suggestions before)... and they probably should be
> parsed from the device tree.

The ENE controller hardware is the same on all devices that use it, but
firmware isn't the same and apparently every vendor invents its own
thing in regards to the firmware because firmware features and interface
varies vastly from device to device. Hence, unfortunately, usually there
is very little compatibility even if devices come form the same vendor

AFAIK, the ENE controller provides some compatibility on x86 machines
via ACPI EC standard, but this doesn't apply to the ARM devices.

I know that Acer A200 should be able to re-use the A500 EC driver as-is,
but A200 is pretty much the same device as A500, so it's not surprising.
IIRC, A200 model only misses back camera in comparison to A500. Hence
there shouldn't be a need to parse the names from a device-tree, but
I'll try to double-check it to be sure.

Thanks!
Dmitry Osipenko Aug. 24, 2020, 11:38 a.m. UTC | #5
24.08.2020 01:30, Pavel Machek пишет:
>> +	orange_led->cdev.name = "power-button-orange";
> 
> "orange:power" -- or what is this LED usually used for?

The orange LED is supposed to indicate that battery is charging up.
diff mbox series

Patch

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 4f6464a169d5..4c39b53bcf1f 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -921,6 +921,13 @@  config LEDS_SGM3140
 	  This option enables support for the SGM3140 500mA Buck/Boost Charge
 	  Pump LED Driver.
 
+config LEDS_ACER_A500
+	tristate "Power button LED support for Acer Iconia Tab A500"
+	depends on LEDS_CLASS && MFD_ACER_A500_EC
+	help
+	  This option enables support for the Power Button LED of
+	  Acer Iconia Tab A500.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 778cb4bb8c52..73e603e1727e 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -10,6 +10,7 @@  obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
 # LED Platform Drivers (keep this sorted, M-| sort)
 obj-$(CONFIG_LEDS_88PM860X)		+= leds-88pm860x.o
 obj-$(CONFIG_LEDS_AAT1290)		+= leds-aat1290.o
+obj-$(CONFIG_LEDS_ACER_A500)		+= leds-acer-a500.o
 obj-$(CONFIG_LEDS_ADP5520)		+= leds-adp5520.o
 obj-$(CONFIG_LEDS_AN30259A)		+= leds-an30259a.o
 obj-$(CONFIG_LEDS_APU)			+= leds-apu.o
diff --git a/drivers/leds/leds-acer-a500.c b/drivers/leds/leds-acer-a500.c
new file mode 100644
index 000000000000..65e69a40a91a
--- /dev/null
+++ b/drivers/leds/leds-acer-a500.c
@@ -0,0 +1,121 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Power button LED driver for Acer Iconia Tab A500.
+ *
+ * Copyright 2020 GRATE-driver project.
+ */
+
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/acer-ec-a500.h>
+
+struct a500_ec_led {
+	struct led_classdev cdev;
+	struct a500_ec_led *other_led;
+	const struct a500_ec_cmd *cmd;
+};
+
+/*					cmd	delay ms */
+A500_EC_COMMAND(RESET_LEDS,		0x40,	100);
+A500_EC_COMMAND(POWER_LED_ON,		0x42,	100);
+A500_EC_COMMAND(CHARGE_LED_ON,		0x43,	100);
+A500_EC_COMMAND(ANDROID_LEDS_OFF,	0x5A,	100);
+
+static int a500_ec_led_brightness_set(struct led_classdev *led_cdev,
+				      enum led_brightness value)
+{
+	struct device *a500_ec_leds_dev = led_cdev->dev->parent;
+	struct a500_ec *ec_chip = dev_get_drvdata(a500_ec_leds_dev->parent);
+	struct a500_ec_led *led = container_of(led_cdev, struct a500_ec_led,
+					       cdev);
+	int ret;
+
+	a500_ec_lock(ec_chip);
+
+	if (value) {
+		ret = a500_ec_write_locked(ec_chip, led->cmd, 0);
+	} else {
+		/*
+		 * There is no separate controls which can disable LEDs
+		 * individually, there is only RESET_LEDS command that turns
+		 * off both LEDs.
+		 */
+		ret = a500_ec_write_locked(ec_chip, RESET_LEDS, 0);
+		if (ret)
+			goto unlock;
+
+		led = led->other_led;
+
+		/* RESET_LEDS turns off both LEDs, thus restore other LED */
+		if (led->cdev.brightness == LED_ON)
+			ret = a500_ec_write_locked(ec_chip, led->cmd, 0);
+	}
+
+unlock:
+	a500_ec_unlock(ec_chip);
+
+	return ret;
+}
+
+static int a500_ec_leds_probe(struct platform_device *pdev)
+{
+	struct a500_ec *ec_chip = dev_get_drvdata(pdev->dev.parent);
+	struct a500_ec_led *white_led, *orange_led;
+	int err;
+
+	/* reset and turn off all LEDs */
+	a500_ec_write(ec_chip, RESET_LEDS, 0);
+	a500_ec_write(ec_chip, ANDROID_LEDS_OFF, 0);
+
+	white_led = devm_kzalloc(&pdev->dev, sizeof(*white_led), GFP_KERNEL);
+	if (!white_led)
+		return -ENOMEM;
+
+	white_led->cdev.name = "power-button-white";
+	white_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
+	white_led->cdev.flags = LED_CORE_SUSPENDRESUME;
+	white_led->cdev.max_brightness = LED_ON;
+	white_led->cmd = &A500_EC_POWER_LED_ON;
+
+	orange_led = devm_kzalloc(&pdev->dev, sizeof(*orange_led), GFP_KERNEL);
+	if (!orange_led)
+		return -ENOMEM;
+
+	orange_led->cdev.name = "power-button-orange";
+	orange_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
+	orange_led->cdev.flags = LED_CORE_SUSPENDRESUME;
+	orange_led->cdev.max_brightness = LED_ON;
+	orange_led->cmd = &A500_EC_CHARGE_LED_ON;
+
+	white_led->other_led = orange_led;
+	orange_led->other_led = white_led;
+
+	err = devm_led_classdev_register(&pdev->dev, &white_led->cdev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register white LED\n");
+		return err;
+	}
+
+	err = devm_led_classdev_register(&pdev->dev, &orange_led->cdev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register orange LED\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static struct platform_driver a500_ec_leds_driver = {
+	.driver = {
+		.name = "acer-a500-iconia-leds",
+	},
+	.probe = a500_ec_leds_probe,
+};
+module_platform_driver(a500_ec_leds_driver);
+
+MODULE_DESCRIPTION("LED driver for Acer Iconia Tab A500 Power Button");
+MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
+MODULE_ALIAS("platform:acer-a500-iconia-leds");
+MODULE_LICENSE("GPL v2");