linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500
@ 2020-08-30 18:53 Dmitry Osipenko
  2020-08-30 18:53 ` [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding Dmitry Osipenko
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Dmitry Osipenko @ 2020-08-30 18:53 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Thierry Reding, Jonathan Hunter,
	Pavel Machek, Dan Murphy, Sebastian Reichel, Lubomir Rintel,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel

Hello!

This series adds support for the Embedded Controller which is found on
Acer Iconia Tab A500 (Android tablet device).

The Embedded Controller is ENE KB930 and it's running firmware customized
for the A500. The firmware interface may be reused by some other sibling
Acer tablets, although none of those tablets are supported in upstream yet.
Please review and apply, thanks in advance!

Changelog:

v2: - Factored out KB930 device-tree binding into a separate file, like it
      was suggested by Lubomir Rintel.

    - Switched to use regmap API like it was suggested by Lubomir Rintel.

    - Added patch "regmap: Use flexible sleep" which allows not to hog
      CPU while LED is switching state.

    - Corrected MODULE_LICENSE to use "GPL" in all patches.

    - Corrected MFD driver Kconfig entry like it was suggested by
      Lubomir Rintel, it now depends on I2C.

    - Switched to use I2C probe_new() in the MFD driver.

    - Renamed the global pm_off variable, like it was suggested by
      Lubomir Rintel and Lee Jones.

    - Dropped serial number from the battery driver because I realized
      that it's not a battery serial, but a device serial.

    - Battery driver now uses dev_err_probe(), like it was suggested by
      Sebastian Reichel.

    - Dropped legacy LED_ON usage from the LED driver and renamed the
      LEDs, like it was suggested by Pavel Machek. I also checked whether
      LED-name customization via device-tree could be needed by other
      potentially compatible devices and it shouldn't be needed, anyways it
      won't be difficult to extend the code even if I'm wrong.

Dmitry Osipenko (6):
  dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  regmap: Use flexible sleep
  mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500
  power: supply: Add battery gauge driver for Acer Iconia Tab A500
  leds: Add driver for Acer Iconia Tab A500
  ARM: tegra: acer-a500: Add Embedded Controller

 .../devicetree/bindings/mfd/ene-kb930.yaml    |  66 ++++
 .../boot/dts/tegra20-acer-a500-picasso.dts    |  17 +
 drivers/base/regmap/regmap.c                  |   4 +-
 drivers/leds/Kconfig                          |   7 +
 drivers/leds/Makefile                         |   1 +
 drivers/leds/leds-acer-a500.c                 | 130 ++++++++
 drivers/mfd/Kconfig                           |  12 +
 drivers/mfd/Makefile                          |   1 +
 drivers/mfd/acer-ec-a500.c                    | 203 ++++++++++++
 drivers/power/supply/Kconfig                  |   6 +
 drivers/power/supply/Makefile                 |   1 +
 drivers/power/supply/acer_a500_battery.c      | 297 ++++++++++++++++++
 12 files changed, 743 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml
 create mode 100644 drivers/leds/leds-acer-a500.c
 create mode 100644 drivers/mfd/acer-ec-a500.c
 create mode 100644 drivers/power/supply/acer_a500_battery.c

-- 
2.27.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
@ 2020-08-30 18:53 ` Dmitry Osipenko
  2020-09-03 16:10   ` Rob Herring
  2020-08-30 18:53 ` [PATCH v2 2/6] regmap: Use flexible sleep Dmitry Osipenko
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Dmitry Osipenko @ 2020-08-30 18:53 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Thierry Reding, Jonathan Hunter,
	Pavel Machek, Dan Murphy, Sebastian Reichel, Lubomir Rintel,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel

Add binding document for the ENE KB930 Embedded Controller.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 .../devicetree/bindings/mfd/ene-kb930.yaml    | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml

diff --git a/Documentation/devicetree/bindings/mfd/ene-kb930.yaml b/Documentation/devicetree/bindings/mfd/ene-kb930.yaml
new file mode 100644
index 000000000000..635c8966ca22
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/ene-kb930.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/ene-kb930.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ENE KB930 Embedded Controller bindings
+
+description: |
+  This binding describes the ENE KB930 Embedded Controller attached to an
+  I2C bus.
+
+maintainers:
+  - Dmitry Osipenko <digetx@gmail.com>
+
+properties:
+  compatible:
+    items:
+      - enum:
+        - acer,a500-iconia-ec # Acer A500 Iconia tablet device
+      - enum:
+        - ene,kb930
+  reg:
+    maxItems: 1
+
+  monitored-battery: true
+  power-supplies: true
+  system-power-controller: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    battery: battery-cell {
+      compatible = "simple-battery";
+      charge-full-design-microamp-hours = <3260000>;
+      energy-full-design-microwatt-hours = <24000000>;
+      operating-range-celsius = <0 40>;
+    };
+
+    mains: ac-adapter {
+      compatible = "gpio-charger";
+      charger-type = "mains";
+      gpios = <&gpio 125 0>;
+    };
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      embedded-controller@58 {
+        compatible = "acer,a500-iconia-ec", "ene,kb930";
+        reg = <0x58>;
+
+        system-power-controller;
+
+        monitored-battery = <&battery>;
+        power-supplies = <&mains>;
+      };
+    };
+
+...
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/6] regmap: Use flexible sleep
  2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
  2020-08-30 18:53 ` [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding Dmitry Osipenko
@ 2020-08-30 18:53 ` Dmitry Osipenko
       [not found]   ` <CGME20200902124731eucas1p13716070977dbef39d09147bb71e050f6@eucas1p1.samsung.com>
  2020-08-30 18:53 ` [PATCH v2 3/6] mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500 Dmitry Osipenko
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Dmitry Osipenko @ 2020-08-30 18:53 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Thierry Reding, Jonathan Hunter,
	Pavel Machek, Dan Murphy, Sebastian Reichel, Lubomir Rintel,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel

The multi-reg write function uses udelay(), which is a busy-loop based
delaying function that is not suitable for a long delays. Hence let's
replace the udelay() with fsleep(), which is flexible sleep function that
selects best delay function based on the delay-time.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/base/regmap/regmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index e93700af7e6e..a417cb1a11dc 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2231,7 +2231,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
 					return ret;
 
 				if (regs[i].delay_us)
-					udelay(regs[i].delay_us);
+					fsleep(regs[i].delay_us);
 
 				base += n;
 				n = 0;
@@ -2268,7 +2268,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
 				return ret;
 
 			if (regs[i].delay_us)
-				udelay(regs[i].delay_us);
+				fsleep(regs[i].delay_us);
 		}
 		return 0;
 	}
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 3/6] mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500
  2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
  2020-08-30 18:53 ` [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding Dmitry Osipenko
  2020-08-30 18:53 ` [PATCH v2 2/6] regmap: Use flexible sleep Dmitry Osipenko
@ 2020-08-30 18:53 ` Dmitry Osipenko
  2020-08-30 18:53 ` [PATCH v2 4/6] power: supply: Add battery gauge driver for " Dmitry Osipenko
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Dmitry Osipenko @ 2020-08-30 18:53 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Thierry Reding, Jonathan Hunter,
	Pavel Machek, Dan Murphy, Sebastian Reichel, Lubomir Rintel,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel

Acer Iconia Tab A500 is an Android tablet device, it has ENE KB930
Embedded Controller which provides battery-gauge, LED, GPIO and some
other functions. The EC uses firmware that is specifically customized
for Acer A500. This patch adds MFD driver for the Embedded Controller
which allows to power-off / reboot the A500 device, it also provides
a common register read/write API that will be used by the sub-devices.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mfd/Kconfig        |  12 +++
 drivers/mfd/Makefile       |   1 +
 drivers/mfd/acer-ec-a500.c | 203 +++++++++++++++++++++++++++++++++++++
 3 files changed, 216 insertions(+)
 create mode 100644 drivers/mfd/acer-ec-a500.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ecd791ad5e8f..7a0f4952c76e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2062,6 +2062,18 @@ config MFD_KHADAS_MCU
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config MFD_ACER_A500_EC
+	tristate "Embedded Controller driver for Acer Iconia Tab A500"
+	depends on I2C
+	depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
+	select MFD_CORE
+	select REGMAP
+	help
+	  Support for Acer Iconia Tab A500 Embedded Controller.
+
+	  The controller itself is ENE KB930, it is running firmware
+	  customized for the specific needs of the Acer A500 hardware.
+
 menu "Multimedia Capabilities Port drivers"
 	depends on ARCH_SA1100
 
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index dd2cc7be7eaa..f6652fb33b7a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -262,6 +262,7 @@ obj-$(CONFIG_MFD_ROHM_BD71828)	+= rohm-bd71828.o
 obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
 obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
 obj-$(CONFIG_MFD_KHADAS_MCU) 	+= khadas-mcu.o
+obj-$(CONFIG_MFD_ACER_A500_EC)	+= acer-ec-a500.o
 
 obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
 
diff --git a/drivers/mfd/acer-ec-a500.c b/drivers/mfd/acer-ec-a500.c
new file mode 100644
index 000000000000..2785a6d9bcc4
--- /dev/null
+++ b/drivers/mfd/acer-ec-a500.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MFD driver for Acer Iconia Tab A500 Embedded Controller.
+ *
+ * Copyright 2020 GRATE-driver project.
+ *
+ * Based on downstream driver from Acer Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/reboot.h>
+
+#define A500_EC_I2C_ERR_TIMEOUT		500
+#define A500_EC_POWER_CMD_TIMEOUT	1000
+
+enum {
+	REG_CURRENT_NOW = 0x03,
+	REG_SHUTDOWN = 0x52,
+	REG_WARM_REBOOT = 0x54,
+	REG_COLD_REBOOT = 0x55,
+};
+
+static struct i2c_client *a500_ec_client_pm_off;
+
+static int a500_ec_read(void *context, const void *reg_buf, size_t reg_size,
+			void *val_buf, size_t val_sizel)
+{
+	struct i2c_client *client = context;
+	unsigned int reg, retries = 5;
+	u16 *ret_val = val_buf;
+	s32 ret = 0;
+
+	if (reg_size != 1 || val_sizel != 2)
+		return -EOPNOTSUPP;
+
+	reg = *(u8 *)reg_buf;
+
+	while (retries-- > 0) {
+		ret = i2c_smbus_read_word_data(client, reg);
+		if (ret >= 0)
+			break;
+
+		msleep(A500_EC_I2C_ERR_TIMEOUT);
+	}
+
+	if (ret < 0) {
+		dev_err(&client->dev, "read 0x%x failed: %d\n", reg, ret);
+		return ret;
+	}
+
+	*ret_val = ret;
+
+	if (reg == REG_CURRENT_NOW)
+		fsleep(10000);
+
+	return 0;
+}
+
+static int a500_ec_write(void *context, const void *data, size_t count)
+{
+	struct i2c_client *client = context;
+	unsigned int reg, val, retries = 5;
+	s32 ret = 0;
+
+	if (count != 3)
+		return -EOPNOTSUPP;
+
+	reg = *(u8  *)(data + 0);
+	val = *(u16 *)(data + 1);
+
+	while (retries-- > 0) {
+		ret = i2c_smbus_write_word_data(client, reg, val);
+		if (ret >= 0)
+			break;
+
+		msleep(A500_EC_I2C_ERR_TIMEOUT);
+	}
+
+	if (ret < 0) {
+		dev_err(&client->dev, "write 0x%x failed: %d\n", reg, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config a500_ec_regmap_config = {
+	.name = "KB930",
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = 0xff,
+};
+
+static const struct regmap_bus a500_ec_regmap_bus = {
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
+	.write = a500_ec_write,
+	.read = a500_ec_read,
+	.max_raw_read = 2,
+};
+
+static void a500_ec_poweroff(void)
+{
+	i2c_smbus_write_word_data(a500_ec_client_pm_off, REG_SHUTDOWN, 0);
+
+	mdelay(A500_EC_POWER_CMD_TIMEOUT);
+}
+
+static int a500_ec_restart_notify(struct notifier_block *this,
+				  unsigned long reboot_mode, void *data)
+{
+	if (reboot_mode == REBOOT_WARM)
+		i2c_smbus_write_word_data(a500_ec_client_pm_off,
+					  REG_WARM_REBOOT, 0);
+	else
+		i2c_smbus_write_word_data(a500_ec_client_pm_off,
+					  REG_COLD_REBOOT, 1);
+
+	mdelay(A500_EC_POWER_CMD_TIMEOUT);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block a500_ec_restart_handler = {
+	.notifier_call = a500_ec_restart_notify,
+	.priority = 200,
+};
+
+static const struct mfd_cell a500_ec_cells[] = {
+	{ .name = "acer-a500-iconia-battery", },
+	{ .name = "acer-a500-iconia-leds", },
+};
+
+static int a500_ec_probe(struct i2c_client *client)
+{
+	struct regmap *rmap;
+	int err;
+
+	rmap = devm_regmap_init(&client->dev, &a500_ec_regmap_bus,
+				client, &a500_ec_regmap_config);
+	if (IS_ERR(rmap))
+		return PTR_ERR(rmap);
+
+	/* register battery and LED sub-devices */
+	err = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,
+				   a500_ec_cells, ARRAY_SIZE(a500_ec_cells),
+				   NULL, 0, NULL);
+	if (err) {
+		dev_err(&client->dev, "failed to add sub-devices: %d\n", err);
+		return err;
+	}
+
+	/* set up power management functions */
+	if (of_device_is_system_power_controller(client->dev.of_node)) {
+		a500_ec_client_pm_off = client;
+
+		err = register_restart_handler(&a500_ec_restart_handler);
+		if (err)
+			return err;
+
+		if (!pm_power_off)
+			pm_power_off = a500_ec_poweroff;
+	}
+
+	return 0;
+}
+
+static int a500_ec_remove(struct i2c_client *client)
+{
+	if (of_device_is_system_power_controller(client->dev.of_node)) {
+		if (pm_power_off == a500_ec_poweroff)
+			pm_power_off = NULL;
+
+		unregister_restart_handler(&a500_ec_restart_handler);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id a500_ec_match[] = {
+	{ .compatible = "acer,a500-iconia-ec" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, a500_ec_match);
+
+static struct i2c_driver a500_ec_driver = {
+	.driver = {
+		.name = "acer-a500-embedded-controller",
+		.of_match_table = a500_ec_match,
+	},
+	.probe_new = a500_ec_probe,
+	.remove = a500_ec_remove,
+};
+module_i2c_driver(a500_ec_driver);
+
+MODULE_DESCRIPTION("Acer Iconia Tab A500 Embedded Controller driver");
+MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
+MODULE_LICENSE("GPL");
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 4/6] power: supply: Add battery gauge driver for Acer Iconia Tab A500
  2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
                   ` (2 preceding siblings ...)
  2020-08-30 18:53 ` [PATCH v2 3/6] mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500 Dmitry Osipenko
@ 2020-08-30 18:53 ` Dmitry Osipenko
  2020-08-30 18:53 ` [PATCH v2 5/6] leds: Add " Dmitry Osipenko
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Dmitry Osipenko @ 2020-08-30 18:53 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Thierry Reding, Jonathan Hunter,
	Pavel Machek, Dan Murphy, Sebastian Reichel, Lubomir Rintel,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel

This patch adds battery gauge driver for Acer Iconia Tab A500 device.
The battery gauge function is provided via the Embedded Controller,
which is found on the Acer A500.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/power/supply/Kconfig             |   6 +
 drivers/power/supply/Makefile            |   1 +
 drivers/power/supply/acer_a500_battery.c | 297 +++++++++++++++++++++++
 3 files changed, 304 insertions(+)
 create mode 100644 drivers/power/supply/acer_a500_battery.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index d1ccf17df42e..3daf0e359964 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -752,4 +752,10 @@ config CHARGER_WILCO
 	  information can be found in
 	  Documentation/ABI/testing/sysfs-class-power-wilco
 
+config BATTERY_ACER_A500
+	tristate "Acer Iconia Tab A500 battery driver"
+	depends on MFD_ACER_A500_EC
+	help
+	  Say Y to include support for Acer Iconia Tab A500 battery fuel gauge.
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index b3c694a65114..08a5b49e2936 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -96,3 +96,4 @@ obj-$(CONFIG_CHARGER_UCS1002)	+= ucs1002_power.o
 obj-$(CONFIG_CHARGER_BD70528)	+= bd70528-charger.o
 obj-$(CONFIG_CHARGER_BD99954)	+= bd99954-charger.o
 obj-$(CONFIG_CHARGER_WILCO)	+= wilco-charger.o
+obj-$(CONFIG_BATTERY_ACER_A500)	+= acer_a500_battery.o
diff --git a/drivers/power/supply/acer_a500_battery.c b/drivers/power/supply/acer_a500_battery.c
new file mode 100644
index 000000000000..93135933c8af
--- /dev/null
+++ b/drivers/power/supply/acer_a500_battery.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Battery driver for Acer Iconia Tab A500.
+ *
+ * Copyright 2020 GRATE-driver project.
+ *
+ * Based on downstream driver from Acer Inc.
+ * Based on NVIDIA Gas Gauge driver for SBS Compliant Batteries.
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+enum {
+	REG_CAPACITY,
+	REG_VOLTAGE,
+	REG_CURRENT,
+	REG_DESIGN_CAPACITY,
+	REG_TEMPERATURE,
+};
+
+#define EC_DATA(_reg, _psp) {			\
+	.psp = POWER_SUPPLY_PROP_ ## _psp,	\
+	.reg = _reg,				\
+}
+
+static const struct battery_register {
+	enum power_supply_property psp;
+	unsigned int reg;
+} ec_data[] = {
+	[REG_CAPACITY]		= EC_DATA(0x00, CAPACITY),
+	[REG_VOLTAGE]		= EC_DATA(0x01, VOLTAGE_NOW),
+	[REG_CURRENT]		= EC_DATA(0x03, CURRENT_NOW),
+	[REG_DESIGN_CAPACITY]	= EC_DATA(0x08, CHARGE_FULL_DESIGN),
+	[REG_TEMPERATURE]	= EC_DATA(0x0a, TEMP),
+};
+
+static const enum power_supply_property a500_battery_properties[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+struct a500_battery {
+	struct delayed_work poll_work;
+	struct power_supply *psy;
+	struct regmap *rmap;
+	unsigned int capacity;
+};
+
+static bool a500_battery_update_capacity(struct a500_battery *bat)
+{
+	unsigned int capacity;
+	int err;
+
+	err = regmap_read(bat->rmap, ec_data[REG_CAPACITY].reg, &capacity);
+	if (err)
+		return false;
+
+	/* capacity can be >100% even if max value is 100% */
+	capacity = min(capacity, 100u);
+
+	if (bat->capacity != capacity) {
+		bat->capacity = capacity;
+		return true;
+	}
+
+	return false;
+}
+
+static int a500_battery_get_status(struct a500_battery *bat)
+{
+	if (bat->capacity < 100) {
+		if (power_supply_am_i_supplied(bat->psy))
+			return POWER_SUPPLY_STATUS_CHARGING;
+		else
+			return POWER_SUPPLY_STATUS_DISCHARGING;
+	}
+
+	return POWER_SUPPLY_STATUS_FULL;
+}
+
+static void a500_battery_unit_adjustment(struct device *dev,
+					 enum power_supply_property psp,
+					 union power_supply_propval *val)
+{
+	const unsigned int base_unit_conversion = 1000;
+	const unsigned int temp_kelvin_to_celsius = 2731;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval *= base_unit_conversion;
+		break;
+
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval -= temp_kelvin_to_celsius;
+		break;
+
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = !!val->intval;
+		break;
+
+	default:
+		dev_dbg(dev,
+			"%s: no need for unit conversion %d\n", __func__, psp);
+	}
+}
+
+static int a500_battery_get_ec_data_index(struct device *dev,
+					  enum power_supply_property psp)
+{
+	unsigned int i;
+
+	/*
+	 * DESIGN_CAPACITY register always returns a non-zero value if
+	 * battery is connected and zero if disconnected, hence we'll use
+	 * it for judging the battery presence.
+	 */
+	if (psp == POWER_SUPPLY_PROP_PRESENT)
+		psp = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+
+	for (i = 0; i < ARRAY_SIZE(ec_data); i++)
+		if (psp == ec_data[i].psp)
+			return i;
+
+	dev_dbg(dev, "%s: invalid property %u\n", __func__, psp);
+
+	return -EINVAL;
+}
+
+static int a500_battery_get_property(struct power_supply *psy,
+				     enum power_supply_property psp,
+				     union power_supply_propval *val)
+{
+	struct a500_battery *bat = power_supply_get_drvdata(psy);
+	struct device *dev = psy->dev.parent;
+	int ret = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = a500_battery_get_status(bat);
+		break;
+
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+
+	case POWER_SUPPLY_PROP_CAPACITY:
+		a500_battery_update_capacity(bat);
+		val->intval = bat->capacity;
+		break;
+
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+	case POWER_SUPPLY_PROP_PRESENT:
+	case POWER_SUPPLY_PROP_TEMP:
+		ret = a500_battery_get_ec_data_index(dev, psp);
+		if (ret < 0)
+			break;
+
+		ret = regmap_read(bat->rmap, ec_data[ret].reg, &val->intval);
+		break;
+
+	default:
+		dev_err(dev, "%s: invalid property %u\n", __func__, psp);
+		return -EINVAL;
+	}
+
+	if (!ret) {
+		/* convert units to match requirements of power supply class */
+		a500_battery_unit_adjustment(dev, psp, val);
+	}
+
+	dev_dbg(dev, "%s: property = %d, value = %x\n",
+		__func__, psp, val->intval);
+
+	/* return NODATA for properties if battery not presents */
+	if (ret)
+		return -ENODATA;
+
+	return 0;
+}
+
+static void a500_battery_poll_work(struct work_struct *work)
+{
+	struct a500_battery *bat;
+	bool capacity_changed;
+
+	bat = container_of(work, struct a500_battery, poll_work.work);
+	capacity_changed = a500_battery_update_capacity(bat);
+
+	if (capacity_changed)
+		power_supply_changed(bat->psy);
+
+	/* continuously send uevent notification */
+	schedule_delayed_work(&bat->poll_work, 30 * HZ);
+}
+
+static const struct power_supply_desc a500_battery_desc = {
+	.name = "ec-battery",
+	.type = POWER_SUPPLY_TYPE_BATTERY,
+	.properties = a500_battery_properties,
+	.get_property = a500_battery_get_property,
+	.num_properties = ARRAY_SIZE(a500_battery_properties),
+	.external_power_changed = power_supply_changed,
+};
+
+static int a500_battery_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct a500_battery *bat;
+
+	bat = devm_kzalloc(&pdev->dev, sizeof(*bat), GFP_KERNEL);
+	if (!bat)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, bat);
+
+	psy_cfg.of_node = pdev->dev.parent->of_node;
+	psy_cfg.drv_data = bat;
+
+	bat->rmap = dev_get_regmap(pdev->dev.parent, "KB930");
+	if (!bat->rmap)
+		return -EINVAL;
+
+	bat->psy = devm_power_supply_register_no_ws(&pdev->dev,
+						    &a500_battery_desc,
+						    &psy_cfg);
+	if (IS_ERR(bat->psy))
+		return dev_err_probe(&pdev->dev, PTR_ERR(bat->psy),
+				     "failed to register battery\n");
+
+	INIT_DELAYED_WORK(&bat->poll_work, a500_battery_poll_work);
+	schedule_delayed_work(&bat->poll_work, HZ);
+
+	return 0;
+}
+
+static int a500_battery_remove(struct platform_device *pdev)
+{
+	struct a500_battery *bat = dev_get_drvdata(&pdev->dev);
+
+	cancel_delayed_work_sync(&bat->poll_work);
+
+	return 0;
+}
+
+static int __maybe_unused a500_battery_suspend(struct device *dev)
+{
+	struct a500_battery *bat = dev_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&bat->poll_work);
+
+	return 0;
+}
+
+static int __maybe_unused a500_battery_resume(struct device *dev)
+{
+	struct a500_battery *bat = dev_get_drvdata(dev);
+
+	schedule_delayed_work(&bat->poll_work, HZ);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(a500_battery_pm_ops,
+			 a500_battery_suspend, a500_battery_resume);
+
+static struct platform_driver a500_battery_driver = {
+	.driver = {
+		.name = "acer-a500-iconia-battery",
+		.pm = &a500_battery_pm_ops,
+	},
+	.probe = a500_battery_probe,
+	.remove = a500_battery_remove,
+};
+module_platform_driver(a500_battery_driver);
+
+MODULE_DESCRIPTION("Battery gauge driver for Acer Iconia Tab A500");
+MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
+MODULE_ALIAS("platform:acer-a500-iconia-battery");
+MODULE_LICENSE("GPL");
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 5/6] leds: Add driver for Acer Iconia Tab A500
  2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
                   ` (3 preceding siblings ...)
  2020-08-30 18:53 ` [PATCH v2 4/6] power: supply: Add battery gauge driver for " Dmitry Osipenko
@ 2020-08-30 18:53 ` Dmitry Osipenko
  2020-08-30 18:53 ` [PATCH v2 6/6] ARM: tegra: acer-a500: Add Embedded Controller Dmitry Osipenko
  2020-09-01 14:50 ` [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Mark Brown
  6 siblings, 0 replies; 15+ messages in thread
From: Dmitry Osipenko @ 2020-08-30 18:53 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Thierry Reding, Jonathan Hunter,
	Pavel Machek, Dan Murphy, Sebastian Reichel, Lubomir Rintel,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel

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 | 130 ++++++++++++++++++++++++++++++++++
 3 files changed, 138 insertions(+)
 create mode 100644 drivers/leds/leds-acer-a500.c

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..790238cebfb5
--- /dev/null
+++ b/drivers/leds/leds-acer-a500.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define A500_EC_LED_DELAY_USEC	(100 * 1000)
+
+enum {
+	REG_RESET_LEDS = 0x40,
+	REG_POWER_LED_ON = 0x42,
+	REG_CHARGE_LED_ON = 0x43,
+	REG_ANDROID_LEDS_OFF = 0x5a,
+};
+
+struct a500_ec_led {
+	struct led_classdev cdev;
+	struct a500_ec_led *other;
+	const struct reg_sequence *enable_seq;
+	struct regmap *rmap;
+};
+
+static const struct reg_sequence a500_ec_leds_reset_seq[] = {
+	REG_SEQ(REG_RESET_LEDS, 0x0, A500_EC_LED_DELAY_USEC),
+	REG_SEQ(REG_ANDROID_LEDS_OFF, 0x0, A500_EC_LED_DELAY_USEC),
+};
+
+static const struct reg_sequence a500_ec_white_led_enable_seq[] = {
+	REG_SEQ(REG_POWER_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
+};
+
+static const struct reg_sequence a500_ec_orange_led_enable_seq[] = {
+	REG_SEQ(REG_CHARGE_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
+};
+
+static int a500_ec_led_brightness_set(struct led_classdev *led_cdev,
+				      enum led_brightness value)
+{
+	struct a500_ec_led *led = container_of(led_cdev, struct a500_ec_led,
+					       cdev);
+	struct reg_sequence control_seq[2];
+	unsigned int num_regs = 1;
+
+	if (value) {
+		control_seq[0] = led->enable_seq[0];
+	} else {
+		/*
+		 * There is no separate controls which can disable LEDs
+		 * individually, there is only RESET_LEDS command that turns
+		 * off both LEDs.
+		 *
+		 * RESET_LEDS turns off both LEDs, thus restore other LED if
+		 * it's turned ON.
+		 */
+		if (led->other->cdev.brightness)
+			num_regs = 2;
+
+		control_seq[0] = a500_ec_leds_reset_seq[0];
+		control_seq[1] = led->other->enable_seq[0];
+	}
+
+	return regmap_multi_reg_write(led->rmap, control_seq, num_regs);
+}
+
+static int a500_ec_leds_probe(struct platform_device *pdev)
+{
+	struct a500_ec_led *white_led, *orange_led;
+	struct regmap *rmap;
+	int err;
+
+	rmap = dev_get_regmap(pdev->dev.parent, "KB930");
+	if (!rmap)
+		return -EINVAL;
+
+	/* reset and turn off LEDs */
+	regmap_multi_reg_write(rmap, a500_ec_leds_reset_seq, 2);
+
+	white_led = devm_kzalloc(&pdev->dev, sizeof(*white_led), GFP_KERNEL);
+	if (!white_led)
+		return -ENOMEM;
+
+	white_led->cdev.name = "power:white";
+	white_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
+	white_led->cdev.flags = LED_CORE_SUSPENDRESUME;
+	white_led->cdev.max_brightness = 1;
+	white_led->enable_seq = a500_ec_white_led_enable_seq;
+	white_led->rmap = rmap;
+
+	orange_led = devm_kzalloc(&pdev->dev, sizeof(*orange_led), GFP_KERNEL);
+	if (!orange_led)
+		return -ENOMEM;
+
+	orange_led->cdev.name = "power:orange";
+	orange_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
+	orange_led->cdev.flags = LED_CORE_SUSPENDRESUME;
+	orange_led->cdev.max_brightness = 1;
+	orange_led->enable_seq = a500_ec_orange_led_enable_seq;
+	orange_led->rmap = rmap;
+
+	white_led->other = orange_led;
+	orange_led->other = 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");
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 6/6] ARM: tegra: acer-a500: Add Embedded Controller
  2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
                   ` (4 preceding siblings ...)
  2020-08-30 18:53 ` [PATCH v2 5/6] leds: Add " Dmitry Osipenko
@ 2020-08-30 18:53 ` Dmitry Osipenko
  2020-09-01 14:50 ` [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Mark Brown
  6 siblings, 0 replies; 15+ messages in thread
From: Dmitry Osipenko @ 2020-08-30 18:53 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Thierry Reding, Jonathan Hunter,
	Pavel Machek, Dan Murphy, Sebastian Reichel, Lubomir Rintel,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel

This patch adds device-tree node for the Embedded Controller which is
found on the Picasso board. The Embedded Controller itself is ENE KB930,
it provides functions like battery-gauge/LED/GPIO/etc and it uses firmware
that is specifically customized for the Acer A500 device.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 arch/arm/boot/dts/tegra20-acer-a500-picasso.dts | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts
index 2d683c9a1a5d..f92712e4bd34 100644
--- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts
+++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts
@@ -502,6 +502,16 @@ panel_ddc: i2c@1 {
 			reg = <1>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+
+			embedded-controller@58 {
+				compatible = "acer,a500-iconia-ec", "ene,kb930";
+				reg = <0x58>;
+
+				system-power-controller;
+
+				monitored-battery = <&bat1010>;
+				power-supplies = <&mains>;
+			};
 		};
 	};
 
@@ -780,6 +790,13 @@ backlight: backlight {
 		default-brightness-level = <20>;
 	};
 
+	bat1010: battery-2s1p {
+		compatible = "simple-battery";
+		charge-full-design-microamp-hours = <3260000>;
+		energy-full-design-microwatt-hours = <24000000>;
+		operating-range-celsius = <0 40>;
+	};
+
 	/* PMIC has a built-in 32KHz oscillator which is used by PMC */
 	clk32k_in: clock@0 {
 		compatible = "fixed-clock";
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500
  2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
                   ` (5 preceding siblings ...)
  2020-08-30 18:53 ` [PATCH v2 6/6] ARM: tegra: acer-a500: Add Embedded Controller Dmitry Osipenko
@ 2020-09-01 14:50 ` Mark Brown
  6 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2020-09-01 14:50 UTC (permalink / raw)
  To: Pavel Machek, Jonathan Hunter, Sebastian Reichel, Dan Murphy,
	Lee Jones, Dmitry Osipenko, Lubomir Rintel, Thierry Reding,
	Rob Herring
  Cc: linux-pm, devicetree, linux-leds, linux-tegra, linux-kernel

On Sun, 30 Aug 2020 21:53:50 +0300, Dmitry Osipenko wrote:
> This series adds support for the Embedded Controller which is found on
> Acer Iconia Tab A500 (Android tablet device).
> 
> The Embedded Controller is ENE KB930 and it's running firmware customized
> for the A500. The firmware interface may be reused by some other sibling
> Acer tablets, although none of those tablets are supported in upstream yet.
> Please review and apply, thanks in advance!
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git for-next

Thanks!

[1/1] regmap: Use flexible sleep
      commit: 2b32d2f7ce0a54ce74a75f0d939b5ee063a05ec5

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/6] regmap: Use flexible sleep
       [not found]   ` <CGME20200902124731eucas1p13716070977dbef39d09147bb71e050f6@eucas1p1.samsung.com>
@ 2020-09-02 12:47     ` Marek Szyprowski
  2020-09-02 12:56       ` Dmitry Osipenko
  0 siblings, 1 reply; 15+ messages in thread
From: Marek Szyprowski @ 2020-09-02 12:47 UTC (permalink / raw)
  To: Dmitry Osipenko, Lee Jones, Rob Herring, Thierry Reding,
	Jonathan Hunter, Pavel Machek, Dan Murphy, Sebastian Reichel,
	Lubomir Rintel, Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel,
	linux-amlogic, Jerome Brunet, Neil Armstrong, Kevin Hilman

Hi Dmitry,

On 30.08.2020 20:53, Dmitry Osipenko wrote:
> The multi-reg write function uses udelay(), which is a busy-loop based
> delaying function that is not suitable for a long delays. Hence let's
> replace the udelay() with fsleep(), which is flexible sleep function that
> selects best delay function based on the delay-time.
>
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>

This patch landed in today's linux-next (20200902) as commit 
2b32d2f7ce0a. Sadly it breaks booting of ARM 64bit Amlogic S922X based 
Odroid N2 board. Here is the log:

BUG: scheduling while atomic: kworker/4:1/46/0x00000003
5 locks held by kworker/4:1/46:
  #0: ffff0000dfc06738 ((wq_completion)events){+.+.}-{0:0}, at: 
process_one_work+0x200/0x718
  #1: ffff80001320bdd0 (deferred_probe_work){+.+.}-{0:0}, at: 
process_one_work+0x200/0x718
  #2: ffff0000df4b6188 (&dev->mutex){....}-{3:3}, at: 
__device_attach+0x3c/0x150
  #3: ffff800012306e70 (enable_lock){+.+.}-{2:2}, at: 
clk_enable_lock+0x48/0x128
  #4: ffff0000de01c418 (syscon:110:(&syscon_config)->lock){+.+.}-{2:2}, 
at: regmap_lock_spinlock+0x14/0x28
Modules linked in:
CPU: 4 PID: 46 Comm: kworker/4:1 Not tainted 5.9.0-rc2+ #1570
Hardware name: Hardkernel ODROID-N2 (DT)
Workqueue: events deferred_probe_work_func
Call trace:
  dump_backtrace+0x0/0x1d0
  show_stack+0x14/0x20
  dump_stack+0xec/0x16c
  __schedule_bug+0x64/0x98
  __schedule+0x7e0/0x8a0
  schedule+0x78/0x118
  schedule_hrtimeout_range_clock+0x84/0x108
  schedule_hrtimeout_range+0x10/0x18
  usleep_range+0x88/0xb8
  _regmap_multi_reg_write+0x188/0x4e0
  regmap_multi_reg_write+0x38/0x58
  meson_clk_pll_init+0x80/0xd8
  meson_clk_pcie_pll_enable+0x48/0xd8
  clk_core_enable+0xc8/0x2b0
  clk_core_enable+0xa8/0x2b0
  clk_core_enable+0xa8/0x2b0
  clk_core_enable+0xa8/0x2b0
  clk_core_enable_lock+0x20/0x40
  clk_enable+0x14/0x28
  phy_g12a_usb3_pcie_probe+0x130/0x210
  platform_drv_probe+0x50/0xa8
  really_probe+0x110/0x400
  driver_probe_device+0x54/0xb8
  __device_attach_driver+0x90/0xc0
  bus_for_each_drv+0x70/0xc8
  __device_attach+0xec/0x150
  device_initial_probe+0x10/0x18
  bus_probe_device+0x94/0xa0
  deferred_probe_work_func+0x70/0xa8
  process_one_work+0x2a8/0x718
  worker_thread+0x48/0x460
  kthread+0x134/0x160
  ret_from_fork+0x10/0x1c
BUG: sleeping function called from invalid context at mm/slab.h:498
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 46, name: kworker/4:1
3 locks held by kworker/4:1/46:
  #0: ffff0000dfc06738 ((wq_completion)events){+.+.}-{0:0}, at: 
process_one_work+0x200/0x718
  #1: ffff80001320bdd0 (deferred_probe_work){+.+.}-{0:0}, at: 
process_one_work+0x200/0x718
  #2: ffff0000df4b6188 (&dev->mutex){....}-{3:3}, at: 
__device_attach+0x3c/0x150
CPU: 4 PID: 46 Comm: kworker/4:1 Tainted: G        W 5.9.0-rc2+ #1570
Hardware name: Hardkernel ODROID-N2 (DT)
Workqueue: events deferred_probe_work_func
Call trace:
  dump_backtrace+0x0/0x1d0
  show_stack+0x14/0x20
  dump_stack+0xec/0x16c
  ___might_sleep+0x1d4/0x1f8
  __might_sleep+0x4c/0x88
  slab_pre_alloc_hook.constprop.96+0xf4/0x138
  __kmalloc_node_track_caller+0x6c/0x288
  devres_alloc_node+0x54/0xc0
  devm_reset_control_array_get+0x34/0xc0
  phy_g12a_usb3_pcie_probe+0x148/0x210
  platform_drv_probe+0x50/0xa8
  really_probe+0x110/0x400
  driver_probe_device+0x54/0xb8
  __device_attach_driver+0x90/0xc0
  bus_for_each_drv+0x70/0xc8
  __device_attach+0xec/0x150
  device_initial_probe+0x10/0x18
  bus_probe_device+0x94/0xa0
  deferred_probe_work_func+0x70/0xa8
  process_one_work+0x2a8/0x718
  worker_thread+0x48/0x460
  kthread+0x134/0x160
  ret_from_fork+0x10/0x1c
------------[ cut here ]------------
kernel BUG at mm/vmalloc.c:2066!
Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
Modules linked in:
CPU: 4 PID: 46 Comm: kworker/4:1 Tainted: G        W 5.9.0-rc2+ #1570
Hardware name: Hardkernel ODROID-N2 (DT)
Workqueue: events deferred_probe_work_func
pstate: 00000005 (nzcv daif -PAN -UAO BTYPE=--)
pc : __get_vm_area_node+0x190/0x198
lr : get_vm_area_caller+0x34/0x40
sp : ffff80001320b9f0
x29: ffff80001320b9f0 x28: ffff8000124bf68d
x27: ffff0000e47ce005 x26: ffff0000e484a6a8
x25: 0000000000000009 x24: ffff80001220f000
x23: 0068000000000707 x22: ffff800010531544
x21: 0000000000000000 x20: 00000000ffe09000
x19: 0000000000001000 x18: ffffffffffffffff
x17: 0000000089f66c61 x16: 00000000b502d7d1
x15: ffff80001220fa48 x14: ffff0000de6df18a
x13: ffff0000de6df189 x12: 0000000000000030
x11: 0000000000000003 x10: ffff8000124f8c58
x9 : 0000000000000000 x8 : 00000000fffffffe
x7 : ffff800010531544 x6 : 0000000000000cc0
x5 : 00000000ffffffff x4 : fffffdffbfff0000
x3 : ffff800010000000 x2 : 0000000000000001
x1 : 0000000000000001 x0 : 0000000000001000
Call trace:
  __get_vm_area_node+0x190/0x198
  __ioremap_caller+0x68/0xe0
  __ioremap+0x38/0x40
  __devm_ioremap+0x7c/0xf8
  __devm_ioremap_resource+0xa8/0x160
  devm_ioremap_resource+0x10/0x18
  devm_platform_get_and_ioremap_resource+0x70/0x78
  devm_platform_ioremap_resource+0x10/0x18
  dwc3_meson_g12a_probe+0x60/0x518
  platform_drv_probe+0x50/0xa8
  really_probe+0x110/0x400
  driver_probe_device+0x54/0xb8
  __device_attach_driver+0x90/0xc0
  bus_for_each_drv+0x70/0xc8
  __device_attach+0xec/0x150
  device_initial_probe+0x10/0x18
  bus_probe_device+0x94/0xa0
  deferred_probe_work_func+0x70/0xa8
  process_one_work+0x2a8/0x718
  worker_thread+0x48/0x460
  kthread+0x134/0x160
  ret_from_fork+0x10/0x1c
Code: cb010000 11000400 17ffffe8 d503201f (d4210000)
---[ end trace b621320ae7bce6b7 ]---
Kernel panic - not syncing: Aiee, killing interrupt handler!
SMP: stopping secondary CPUs
Kernel Offset: disabled
CPU features: 0x0240002,20082004
Memory Limit: none
---[ end Kernel panic - not syncing: Aiee, killing interrupt handler! ]---

Reverting this commit on top of current linux-next fixes board booting.

> ---
>   drivers/base/regmap/regmap.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
> index e93700af7e6e..a417cb1a11dc 100644
> --- a/drivers/base/regmap/regmap.c
> +++ b/drivers/base/regmap/regmap.c
> @@ -2231,7 +2231,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
>   					return ret;
>   
>   				if (regs[i].delay_us)
> -					udelay(regs[i].delay_us);
> +					fsleep(regs[i].delay_us);
>   
>   				base += n;
>   				n = 0;
> @@ -2268,7 +2268,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
>   				return ret;
>   
>   			if (regs[i].delay_us)
> -				udelay(regs[i].delay_us);
> +				fsleep(regs[i].delay_us);
>   		}
>   		return 0;
>   	}

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/6] regmap: Use flexible sleep
  2020-09-02 12:47     ` Marek Szyprowski
@ 2020-09-02 12:56       ` Dmitry Osipenko
  0 siblings, 0 replies; 15+ messages in thread
From: Dmitry Osipenko @ 2020-09-02 12:56 UTC (permalink / raw)
  To: Marek Szyprowski, Lee Jones, Rob Herring, Thierry Reding,
	Jonathan Hunter, Pavel Machek, Dan Murphy, Sebastian Reichel,
	Lubomir Rintel, Mark Brown
  Cc: devicetree, linux-tegra, linux-leds, linux-pm, linux-kernel,
	linux-amlogic, Jerome Brunet, Neil Armstrong, Kevin Hilman

02.09.2020 15:47, Marek Szyprowski пишет:
> Hi Dmitry,
> 
> On 30.08.2020 20:53, Dmitry Osipenko wrote:
>> The multi-reg write function uses udelay(), which is a busy-loop based
>> delaying function that is not suitable for a long delays. Hence let's
>> replace the udelay() with fsleep(), which is flexible sleep function that
>> selects best delay function based on the delay-time.
>>
>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> 
> This patch landed in today's linux-next (20200902) as commit 
> 2b32d2f7ce0a. Sadly it breaks booting of ARM 64bit Amlogic S922X based 
> Odroid N2 board. Here is the log:

Hello, Marek! Thank you for the feedback! I missed that remap supports
different types of locking, I'll make a another patch to fix this problem.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  2020-08-30 18:53 ` [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding Dmitry Osipenko
@ 2020-09-03 16:10   ` Rob Herring
  2020-09-04 12:07     ` Dmitry Osipenko
  0 siblings, 1 reply; 15+ messages in thread
From: Rob Herring @ 2020-09-03 16:10 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Pavel Machek, Lubomir Rintel, Mark Brown, devicetree,
	linux-kernel, Jonathan Hunter, Lee Jones, linux-leds,
	linux-tegra, Dan Murphy, Rob Herring, Thierry Reding,
	Sebastian Reichel, linux-pm

On Sun, 30 Aug 2020 21:53:51 +0300, Dmitry Osipenko wrote:
> Add binding document for the ENE KB930 Embedded Controller.
> 
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
>  .../devicetree/bindings/mfd/ene-kb930.yaml    | 66 +++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml
> 


My bot found errors running 'make dt_binding_check' on your patch:

/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/ene-kb930.example.dt.yaml: battery-cell: 'operating-range-celsius' does not match any of the regexes: '^ocv-capacity-table-[0-9]+$', 'pinctrl-[0-9]+'
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/power/supply/battery.yaml


See https://patchwork.ozlabs.org/patch/1354004

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure dt-schema is up to date:

pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  2020-09-03 16:10   ` Rob Herring
@ 2020-09-04 12:07     ` Dmitry Osipenko
  2020-09-04 15:40       ` Rob Herring
  0 siblings, 1 reply; 15+ messages in thread
From: Dmitry Osipenko @ 2020-09-04 12:07 UTC (permalink / raw)
  To: Rob Herring
  Cc: Pavel Machek, Lubomir Rintel, Mark Brown, devicetree,
	linux-kernel, Jonathan Hunter, Lee Jones, linux-leds,
	linux-tegra, Dan Murphy, Rob Herring, Thierry Reding,
	Sebastian Reichel, linux-pm

03.09.2020 19:10, Rob Herring пишет:
> On Sun, 30 Aug 2020 21:53:51 +0300, Dmitry Osipenko wrote:
>> Add binding document for the ENE KB930 Embedded Controller.
>>
>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
>> ---
>>  .../devicetree/bindings/mfd/ene-kb930.yaml    | 66 +++++++++++++++++++
>>  1 file changed, 66 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml
>>
> 
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/ene-kb930.example.dt.yaml: battery-cell: 'operating-range-celsius' does not match any of the regexes: '^ocv-capacity-table-[0-9]+$', 'pinctrl-[0-9]+'
> 	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/power/supply/battery.yaml
> 
> 
> See https://patchwork.ozlabs.org/patch/1354004
> 
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure dt-schema is up to date:
> 
> pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
> 
> Please check and re-submit.
> 

Apparently bot uses outdated kernel.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  2020-09-04 12:07     ` Dmitry Osipenko
@ 2020-09-04 15:40       ` Rob Herring
  2020-09-04 15:54         ` Dmitry Osipenko
  0 siblings, 1 reply; 15+ messages in thread
From: Rob Herring @ 2020-09-04 15:40 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Pavel Machek, Lubomir Rintel, Mark Brown, devicetree,
	linux-kernel, Jonathan Hunter, Lee Jones, Linux LED Subsystem,
	linux-tegra, Dan Murphy, Thierry Reding, Sebastian Reichel,
	open list:THERMAL

On Fri, Sep 4, 2020 at 6:07 AM Dmitry Osipenko <digetx@gmail.com> wrote:
>
> 03.09.2020 19:10, Rob Herring пишет:
> > On Sun, 30 Aug 2020 21:53:51 +0300, Dmitry Osipenko wrote:
> >> Add binding document for the ENE KB930 Embedded Controller.
> >>
> >> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> >> ---
> >>  .../devicetree/bindings/mfd/ene-kb930.yaml    | 66 +++++++++++++++++++
> >>  1 file changed, 66 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml
> >>
> >
> >
> > My bot found errors running 'make dt_binding_check' on your patch:
> >
> > /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/ene-kb930.example.dt.yaml: battery-cell: 'operating-range-celsius' does not match any of the regexes: '^ocv-capacity-table-[0-9]+$', 'pinctrl-[0-9]+'
> >       From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/power/supply/battery.yaml
> >
> >
> > See https://patchwork.ozlabs.org/patch/1354004
> >
> > If you already ran 'make dt_binding_check' and didn't see the above
> > error(s), then make sure dt-schema is up to date:
> >
> > pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
> >
> > Please check and re-submit.
> >
>
> Apparently bot uses outdated kernel.

It's on v5.9-rc2. The scripts don't know your base/dependencies and
neither did I because you didn't mention anything here. I do review
the errors before spamming people.

Rob

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  2020-09-04 15:40       ` Rob Herring
@ 2020-09-04 15:54         ` Dmitry Osipenko
  2020-09-08 17:09           ` Rob Herring
  0 siblings, 1 reply; 15+ messages in thread
From: Dmitry Osipenko @ 2020-09-04 15:54 UTC (permalink / raw)
  To: Rob Herring
  Cc: Pavel Machek, Lubomir Rintel, Mark Brown, devicetree,
	linux-kernel, Jonathan Hunter, Lee Jones, Linux LED Subsystem,
	linux-tegra, Dan Murphy, Thierry Reding, Sebastian Reichel,
	open list:THERMAL

04.09.2020 18:40, Rob Herring пишет:
> On Fri, Sep 4, 2020 at 6:07 AM Dmitry Osipenko <digetx@gmail.com> wrote:
>>
>> 03.09.2020 19:10, Rob Herring пишет:
>>> On Sun, 30 Aug 2020 21:53:51 +0300, Dmitry Osipenko wrote:
>>>> Add binding document for the ENE KB930 Embedded Controller.
>>>>
>>>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
>>>> ---
>>>>  .../devicetree/bindings/mfd/ene-kb930.yaml    | 66 +++++++++++++++++++
>>>>  1 file changed, 66 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml
>>>>
>>>
>>>
>>> My bot found errors running 'make dt_binding_check' on your patch:
>>>
>>> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/ene-kb930.example.dt.yaml: battery-cell: 'operating-range-celsius' does not match any of the regexes: '^ocv-capacity-table-[0-9]+$', 'pinctrl-[0-9]+'
>>>       From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/power/supply/battery.yaml
>>>
>>>
>>> See https://patchwork.ozlabs.org/patch/1354004
>>>
>>> If you already ran 'make dt_binding_check' and didn't see the above
>>> error(s), then make sure dt-schema is up to date:
>>>
>>> pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
>>>
>>> Please check and re-submit.
>>>
>>
>> Apparently bot uses outdated kernel.
> 
> It's on v5.9-rc2. The scripts don't know your base/dependencies and
> neither did I because you didn't mention anything here. I do review
> the errors before spamming people.

The patches are based on the linux-next, hence nothing special here. My
expectation is that the bot should use the linux-next as well in order
to prevent such warnings. Is there any reason to why bot not using
linux-next?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  2020-09-04 15:54         ` Dmitry Osipenko
@ 2020-09-08 17:09           ` Rob Herring
  0 siblings, 0 replies; 15+ messages in thread
From: Rob Herring @ 2020-09-08 17:09 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Pavel Machek, Lubomir Rintel, Mark Brown, devicetree,
	linux-kernel, Jonathan Hunter, Lee Jones, Linux LED Subsystem,
	linux-tegra, Dan Murphy, Thierry Reding, Sebastian Reichel,
	open list:THERMAL

On Fri, Sep 4, 2020 at 9:54 AM Dmitry Osipenko <digetx@gmail.com> wrote:
>
> 04.09.2020 18:40, Rob Herring пишет:
> > On Fri, Sep 4, 2020 at 6:07 AM Dmitry Osipenko <digetx@gmail.com> wrote:
> >>
> >> 03.09.2020 19:10, Rob Herring пишет:
> >>> On Sun, 30 Aug 2020 21:53:51 +0300, Dmitry Osipenko wrote:
> >>>> Add binding document for the ENE KB930 Embedded Controller.
> >>>>
> >>>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> >>>> ---
> >>>>  .../devicetree/bindings/mfd/ene-kb930.yaml    | 66 +++++++++++++++++++
> >>>>  1 file changed, 66 insertions(+)
> >>>>  create mode 100644 Documentation/devicetree/bindings/mfd/ene-kb930.yaml
> >>>>
> >>>
> >>>
> >>> My bot found errors running 'make dt_binding_check' on your patch:
> >>>
> >>> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/ene-kb930.example.dt.yaml: battery-cell: 'operating-range-celsius' does not match any of the regexes: '^ocv-capacity-table-[0-9]+$', 'pinctrl-[0-9]+'
> >>>       From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/power/supply/battery.yaml
> >>>
> >>>
> >>> See https://patchwork.ozlabs.org/patch/1354004
> >>>
> >>> If you already ran 'make dt_binding_check' and didn't see the above
> >>> error(s), then make sure dt-schema is up to date:
> >>>
> >>> pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
> >>>
> >>> Please check and re-submit.
> >>>
> >>
> >> Apparently bot uses outdated kernel.
> >
> > It's on v5.9-rc2. The scripts don't know your base/dependencies and
> > neither did I because you didn't mention anything here. I do review
> > the errors before spamming people.
>
> The patches are based on the linux-next, hence nothing special here. My
> expectation is that the bot should use the linux-next as well in order
> to prevent such warnings. Is there any reason to why bot not using
> linux-next?

What the bot uses is not the issue. The issue is not stating what your
dependencies are. linux-next is not a stable base. No patches to be
applied should be based on linux-next because there's no maintainer
that can take them if you consider anything in linux-next could be a
dependency. Of course, you're probably just dependent on one
maintainer's tree usually, but whose tree? Am I supposed to figure
that out?

linux-next is frequently broken with respect to binding checks, so it
really doesn't work for the bot. I need a known good base.

Rob

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-09-08 17:10 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-30 18:53 [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Dmitry Osipenko
2020-08-30 18:53 ` [PATCH v2 1/6] dt-bindings: mfd: Add ENE KB930 Embedded Controller binding Dmitry Osipenko
2020-09-03 16:10   ` Rob Herring
2020-09-04 12:07     ` Dmitry Osipenko
2020-09-04 15:40       ` Rob Herring
2020-09-04 15:54         ` Dmitry Osipenko
2020-09-08 17:09           ` Rob Herring
2020-08-30 18:53 ` [PATCH v2 2/6] regmap: Use flexible sleep Dmitry Osipenko
     [not found]   ` <CGME20200902124731eucas1p13716070977dbef39d09147bb71e050f6@eucas1p1.samsung.com>
2020-09-02 12:47     ` Marek Szyprowski
2020-09-02 12:56       ` Dmitry Osipenko
2020-08-30 18:53 ` [PATCH v2 3/6] mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500 Dmitry Osipenko
2020-08-30 18:53 ` [PATCH v2 4/6] power: supply: Add battery gauge driver for " Dmitry Osipenko
2020-08-30 18:53 ` [PATCH v2 5/6] leds: Add " Dmitry Osipenko
2020-08-30 18:53 ` [PATCH v2 6/6] ARM: tegra: acer-a500: Add Embedded Controller Dmitry Osipenko
2020-09-01 14:50 ` [PATCH v2 0/6] Introduce Embedded Controller driver for Acer A500 Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).