From: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
To: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>,
Greg Kroah-Hartman
<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>,
Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>,
Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Cc: Pantelis Antoniou
<pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
devicetree <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Subject: [RFC] misc: Add Allwinner Q8 tablet hardware manager
Date: Thu, 1 Sep 2016 21:08:20 +0200 [thread overview]
Message-ID: <20160901190820.21987-2-hdegoede@redhat.com> (raw)
In-Reply-To: <20160901190820.21987-1-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Allwinnner A13 / A23 / A33 based Q8 tablets are popular cheap 7" tablets
of which a new batch is produced every few weeks. Each batch uses a
different mix of touchscreen, accelerometer and wifi peripherals.
Given that each batch is different creating a devicetree for each variant
is not desirable. This commit adds a Q8 tablet hardware manager which
auto-detects the touchscreen and accelerometer so that a single generic
dts can be used for these tablets.
The wifi is connected to a discoverable bus (sdio or usb) and will be
autodetected by the mmc resp. usb subsystems.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
.../misc/allwinner,sunxi-q8-hardwaremgr.txt | 52 +++
drivers/misc/Kconfig | 12 +
drivers/misc/Makefile | 1 +
drivers/misc/q8-hardwaremgr.c | 512 +++++++++++++++++++++
4 files changed, 577 insertions(+)
create mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-q8-hardwaremgr.txt
create mode 100644 drivers/misc/q8-hardwaremgr.c
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-q8-hardwaremgr.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-q8-hardwaremgr.txt
new file mode 100644
index 0000000..f428bf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-q8-hardwaremgr.txt
@@ -0,0 +1,52 @@
+Q8 tablet hardware manager
+--------------------------
+
+Allwinnner A13 / A23 / A33 based Q8 tablets are popular cheap 7" tablets of
+which a new batch is produced every few weeks. Each batch uses a different
+mix of touchscreen, accelerometer and wifi peripherals.
+
+Given that each batch is different creating a devicetree for each variant is
+not desirable. The Q8 tablet hardware manager bindings are bindings for an os
+module which auto-detects the touchscreen so that a single
+generic dts can be used for these tablets.
+
+The wifi is connected to a discoverable bus and will be autodetected by the os.
+
+Required properties:
+ - compatible : "allwinner,sunxi-q8-hardwaremgr"
+ - touchscreen : phandle of a template touchscreen node, this must be a
+ child node of the touchscreen i2c bus
+
+Optional properties:
+ - touchscreen-supply : regulator phandle for the touchscreen vdd supply
+
+touschreen node required properties:
+ - interrupt-parent : phandle pointing to the interrupt controller
+ serving the touchscreen interrupt
+ - interrupts : interrupt specification for the touchscreen interrupt
+ - power-gpios : Specification for the pin connected to the touchscreen's
+ enable / wake pin. This needs to be driven high to
+ enable the touchscreen controller
+
+Example:
+
+/ {
+ hwmgr {
+ compatible = "allwinner,sunxi-q8-hardwaremgr";
+ touchscreen = <&touchscreen>;
+ touchscreen-supply = <®_ldo_io1>;
+ };
+};
+
+&i2c0 {
+ touchscreen: touchscreen@0 {
+ interrupt-parent = <&pio>;
+ interrupts = <1 5 IRQ_TYPE_EDGE_FALLING>; /* PB5 */
+ power-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ /*
+ * Enabled by sunxi-q8-hardwaremgr if it detects a
+ * known model touchscreen.
+ */
+ status = "disabled";
+ };
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a216b46..c3e7772 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -804,6 +804,18 @@ config PANEL_BOOT_MESSAGE
An empty message will only clear the display at driver init time. Any other
printf()-formatted message is valid with newline and escape codes.
+config Q8_HARDWAREMGR
+ tristate "Allwinner Q8 tablet hardware manager"
+ depends on GPIOLIB || COMPILE_TEST
+ depends on I2C
+ depends on OF
+ default n
+ help
+ This option enables support for autodetecting the touchscreen
+ on Allwinner Q8 tablets.
+
+ If unsure, say N.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7410c6d..cac76b7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-$(CONFIG_CXL_BASE) += cxl/
obj-$(CONFIG_PANEL) += panel.o
+obj-$(CONFIG_Q8_HARDWAREMGR) += q8-hardwaremgr.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
diff --git a/drivers/misc/q8-hardwaremgr.c b/drivers/misc/q8-hardwaremgr.c
new file mode 100644
index 0000000..e75625e
--- /dev/null
+++ b/drivers/misc/q8-hardwaremgr.c
@@ -0,0 +1,512 @@
+/*
+ * Allwinner q8 formfactor tablet hardware manager
+ *
+ * Copyright (C) 2016 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ *
+ * 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 <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+/*
+ * We can detect which touchscreen controller is used automatically,
+ * but some controllers can be wired up differently depending on the
+ * q8 PCB variant used, so they need different firmware files / settings.
+ *
+ * We allow the user to specify a firmware_variant to select a config
+ * from a list of known configs. We also allow overriding each setting
+ * individually.
+ */
+
+static int touchscreen_variant = -1;
+module_param(touchscreen_variant, int, 0444);
+MODULE_PARM_DESC(touchscreen_variant, "Touchscreen variant 0-x, -1 for auto");
+
+static int touchscreen_width = -1;
+module_param(touchscreen_width, int, 0444);
+MODULE_PARM_DESC(touchscreen_width, "Touchscreen width, -1 for auto");
+
+static int touchscreen_height = -1;
+module_param(touchscreen_height, int, 0444);
+MODULE_PARM_DESC(touchscreen_height, "Touchscreen height, -1 for auto");
+
+static int touchscreen_invert_x = -1;
+module_param(touchscreen_invert_x, int, 0444);
+MODULE_PARM_DESC(touchscreen_invert_x, "Touchscreen invert x, -1 for auto");
+
+static int touchscreen_invert_y = -1;
+module_param(touchscreen_invert_y, int, 0444);
+MODULE_PARM_DESC(touchscreen_invert_y, "Touchscreen invert y, -1 for auto");
+
+static int touchscreen_swap_x_y = -1;
+module_param(touchscreen_swap_x_y, int, 0444);
+MODULE_PARM_DESC(touchscreen_swap_x_y, "Touchscreen swap x y, -1 for auto");
+
+static char *touchscreen_fw_name;
+module_param(touchscreen_fw_name, charp, 0444);
+MODULE_PARM_DESC(touchscreen_fw_name, "Touchscreen firmware filename");
+
+#define TOUCHSCREEN_POWER_ON_DELAY 20
+#define SILEAD_REG_ID 0xFC
+#define EKTF2127_RESPONSE 0x52
+#define EKTF2127_REQUEST 0x53
+#define EKTF2127_WIDTH 0x63
+
+enum touchscreen_model {
+ touchscreen_unknown,
+ gsl1680_a082,
+ gsl1680_b482,
+ ektf2127,
+ zet6251,
+};
+
+struct q8_hardwaremgr_data {
+ struct device *dev;
+ bool touchscreen_needs_regulator;
+ enum touchscreen_model touchscreen_model;
+ int touchscreen_addr;
+ int touchscreen_variant;
+ int touchscreen_width;
+ int touchscreen_height;
+ int touchscreen_invert_x;
+ int touchscreen_invert_y;
+ int touchscreen_swap_x_y;
+ const char *touchscreen_compatible;
+ const char *touchscreen_fw_name;
+};
+
+typedef int (*probe_func)(struct q8_hardwaremgr_data *data,
+ struct i2c_adapter *adap);
+
+#if 0
+ ret = i2c_smbus_xfer(adap, 0x40, 0, I2C_SMBUS_WRITE, 0,
+ I2C_SMBUS_QUICK, NULL);
+ if (ret < 0)
+ return -ENODEV;
+
+#endif
+
+static int q8_hardwaremgr_probe_touchscreen(struct q8_hardwaremgr_data *data,
+ struct i2c_adapter *adap)
+{
+ struct i2c_client *client;
+ unsigned char buff[24];
+ __le32 chip_id;
+ int ret;
+
+ msleep(TOUCHSCREEN_POWER_ON_DELAY);
+
+ /* Check for silead touchsceen at addr 0x40 */
+ client = i2c_new_dummy(adap, 0x40);
+ if (!client)
+ return -ENOMEM;
+
+ ret = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_ID,
+ sizeof(chip_id), (u8 *)&chip_id);
+ if (ret == sizeof(chip_id)) {
+ switch (le32_to_cpu(chip_id)) {
+ case 0xa0820000:
+ data->touchscreen_addr = 0x40;
+ data->touchscreen_compatible = "silead,gsl1680";
+ data->touchscreen_model = gsl1680_a082;
+ dev_info(data->dev, "Found Silead touchscreen ID: 0xa0820000\n");
+ break;
+ case 0xb4820000:
+ data->touchscreen_addr = 0x40;
+ data->touchscreen_compatible = "silead,gsl1680";
+ data->touchscreen_model = gsl1680_b482;
+ dev_info(data->dev, "Found Silead touchscreen ID: 0xb4820000\n");
+ break;
+ default:
+ dev_warn(data->dev, "Found Silead touchscreen with unknown ID: 0x%08x\n",
+ le32_to_cpu(chip_id));
+ }
+ ret = 0;
+ }
+ i2c_unregister_device(client);
+ if (ret == 0 || ret == -ETIMEDOUT /* Bus stuck bail immediately */)
+ return ret;
+
+ /* Check for Elan eKTF2127 touchsceen at addr 0x15 */
+ client = i2c_new_dummy(adap, 0x15);
+ if (!client)
+ return -ENOMEM;
+
+ do {
+ /* Read hello, ignore data, depends on initial power state */
+ ret = i2c_master_recv(client, buff, 4);
+ if (ret != 4)
+ break;
+
+ /* Request width */
+ buff[0] = EKTF2127_REQUEST;
+ buff[1] = EKTF2127_WIDTH;
+ buff[2] = 0x00;
+ buff[3] = 0x00;
+ ret = i2c_master_send(client, buff, 4);
+ if (ret != 4)
+ break;
+
+ msleep(20);
+
+ /* Read response */
+ ret = i2c_master_recv(client, buff, 4);
+ if (ret != 4)
+ break;
+
+ if (buff[0] == EKTF2127_RESPONSE && buff[1] == EKTF2127_WIDTH) {
+ data->touchscreen_addr = 0x15;
+ data->touchscreen_compatible = "elan,ektf2127";
+ data->touchscreen_model = ektf2127;
+ dev_info(data->dev, "Found Elan eKTF2127 touchscreen\n");
+ ret = 0;
+ }
+ } while (0);
+ i2c_unregister_device(client);
+ if (ret == 0 || ret == -ETIMEDOUT /* Bus stuck bail immediately */)
+ return ret;
+
+ /* Check for Zeitec zet6251 touchsceen at addr 0x76 */
+ client = i2c_new_dummy(adap, 0x76);
+ if (!client)
+ return -ENOMEM;
+
+ /*
+ * We only do a simple read finger data packet test, because some
+ * versions require firmware to be loaded. If not firmware is loaded
+ * the buffer will be filed with 0xff, so we ignore the contents.
+ */
+ ret = i2c_master_recv(client, buff, 24);
+ if (ret == 24) {
+ data->touchscreen_addr = 0x76;
+ data->touchscreen_compatible = "zeitec,zet6251";
+ data->touchscreen_model = zet6251;
+ dev_info(data->dev, "Found Zeitec zet6251 touchscreen\n");
+ ret = 0;
+ }
+ i2c_unregister_device(client);
+ if (ret == 0 || ret == -ETIMEDOUT /* Bus stuck bail immediately */)
+ return ret;
+
+ return -ENODEV;
+}
+
+static int q8_hardwaremgr_do_probe(struct q8_hardwaremgr_data *data,
+ const char *prefix, probe_func func)
+{
+ struct device *dev = data->dev;
+ struct device_node *np;
+ struct i2c_adapter *adap;
+ struct regulator *reg;
+ struct gpio_desc *gpio;
+ int ret = 0;
+
+ np = of_parse_phandle(dev->of_node, prefix, 0);
+ if (!np) {
+ dev_err(dev, "Error %s not set\n", prefix);
+ return -EINVAL;
+ }
+
+ adap = of_get_i2c_adapter_by_node(np->parent);
+ if (!adap) {
+ ret = -EPROBE_DEFER;
+ goto put_node;
+ }
+
+ reg = regulator_get_optional(dev, prefix);
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+ if (ret == -EPROBE_DEFER)
+ goto put_adapter;
+ reg = NULL;
+ }
+
+ gpio = fwnode_get_named_gpiod(&np->fwnode, "power-gpios");
+ if (IS_ERR(gpio)) {
+ ret = PTR_ERR(gpio);
+ if (ret == -EPROBE_DEFER)
+ goto put_reg;
+ gpio = NULL;
+ }
+
+ /* First try with only the power gpio driven high */
+ if (gpio) {
+ ret = gpiod_direction_output(gpio, 1);
+ if (ret)
+ goto put_gpio;
+ }
+
+ dev_info(dev, "Looking for %s without a regulator\n", prefix);
+ ret = func(data, adap);
+ if (ret != 0 && reg) {
+ /* Second try, also enable the regulator */
+ ret = regulator_enable(reg);
+ if (ret)
+ goto restore_gpio;
+
+ dev_info(dev, "Looking for %s with a regulator\n", prefix);
+ ret = func(data, adap);
+ if (ret == 0)
+ data->touchscreen_needs_regulator = true;
+
+ regulator_disable(reg);
+ }
+ ret = 0; /* Not finding a device is not an error */
+
+restore_gpio:
+ if (gpio)
+ gpiod_direction_output(gpio, 0);
+put_gpio:
+ if (gpio)
+ gpiod_put(gpio);
+put_reg:
+ if (reg)
+ regulator_put(reg);
+put_adapter:
+ i2c_put_adapter(adap);
+
+put_node:
+ of_node_put(np);
+
+ return ret;
+}
+
+static void q8_hardwaremgr_apply_gsl1680_a082_variant(
+ struct q8_hardwaremgr_data *data)
+{
+ if (touchscreen_variant != -1) {
+ data->touchscreen_variant = touchscreen_variant;
+ } else {
+ if (of_machine_is_compatible("allwinner,sun8i-a33"))
+ data->touchscreen_variant = 1;
+ else
+ data->touchscreen_variant = 0;
+ }
+
+ switch (data->touchscreen_variant) {
+ default:
+ dev_warn(data->dev, "Error unknown touchscreen_variant %d using 0\n",
+ touchscreen_variant);
+ /* Fall through */
+ case 0:
+ data->touchscreen_width = 1024;
+ data->touchscreen_height = 600;
+ data->touchscreen_fw_name = "gsl1680-a082-q8-700.fw";
+ break;
+ case 1:
+ data->touchscreen_width = 480;
+ data->touchscreen_height = 800;
+ data->touchscreen_swap_x_y = 1;
+ data->touchscreen_fw_name = "gsl1680-a082-q8-a70.fw";
+ break;
+ }
+}
+
+static void q8_hardwaremgr_apply_gsl1680_b482_variant(
+ struct q8_hardwaremgr_data *data)
+{
+ if (touchscreen_variant != -1)
+ data->touchscreen_variant = touchscreen_variant;
+
+ switch (data->touchscreen_variant) {
+ default:
+ dev_warn(data->dev, "Error unknown touchscreen_variant %d using 0\n",
+ touchscreen_variant);
+ /* Fall through */
+ case 0:
+ data->touchscreen_width = 960;
+ data->touchscreen_height = 640;
+ data->touchscreen_fw_name = "gsl1680-b482-q8-d702.fw";
+ break;
+ case 1:
+ data->touchscreen_width = 960;
+ data->touchscreen_height = 640;
+ data->touchscreen_fw_name = "gsl1680-b482-q8-a70.fw";
+ break;
+ }
+}
+
+static void q8_hardwaremgr_issue_gsl1680_warning(
+ struct q8_hardwaremgr_data *data)
+{
+ dev_warn(data->dev, "gsl1680 touchscreen may require kernel cmdline parameters to function properly\n");
+ dev_warn(data->dev, "Try q8_hardwaremgr.touchscreen_invert_x=1 if x coordinates are inverted\n");
+ dev_warn(data->dev, "Try q8_hardwaremgr.touchscreen_variant=%d if coordinates are all over the place\n",
+ !data->touchscreen_variant);
+
+#define show(x) \
+ dev_info(data->dev, #x " %d (%s)\n", data->x, \
+ (x == -1) ? "auto" : "user supplied")
+
+ show(touchscreen_variant);
+ show(touchscreen_width);
+ show(touchscreen_height);
+ show(touchscreen_invert_x);
+ show(touchscreen_invert_y);
+ show(touchscreen_swap_x_y);
+ dev_info(data->dev, "touchscreen_fw_name %s (%s)\n",
+ data->touchscreen_fw_name,
+ (touchscreen_fw_name == NULL) ? "auto" : "user supplied");
+#undef show
+}
+
+static void q8_hardwaremgr_apply_touchscreen(struct q8_hardwaremgr_data *data)
+{
+ struct device *dev = data->dev;
+ struct of_changeset cset;
+ struct device_node *np;
+
+ switch (data->touchscreen_model) {
+ case touchscreen_unknown:
+ return;
+ case gsl1680_a082:
+ q8_hardwaremgr_apply_gsl1680_a082_variant(data);
+ break;
+ case gsl1680_b482:
+ q8_hardwaremgr_apply_gsl1680_b482_variant(data);
+ break;
+ case ektf2127:
+ case zet6251:
+ /* These have only 1 variant */
+ break;
+ }
+
+ if (touchscreen_width != -1)
+ data->touchscreen_width = touchscreen_width;
+
+ if (touchscreen_height != -1)
+ data->touchscreen_height = touchscreen_height;
+
+ if (touchscreen_invert_x != -1)
+ data->touchscreen_invert_x = touchscreen_invert_x;
+
+ if (touchscreen_invert_y != -1)
+ data->touchscreen_invert_y = touchscreen_invert_y;
+
+ if (touchscreen_swap_x_y != -1)
+ data->touchscreen_swap_x_y = touchscreen_swap_x_y;
+
+ if (touchscreen_fw_name)
+ data->touchscreen_fw_name = touchscreen_fw_name;
+
+ if (data->touchscreen_model == gsl1680_a082 ||
+ data->touchscreen_model == gsl1680_b482)
+ q8_hardwaremgr_issue_gsl1680_warning(data);
+
+ np = of_parse_phandle(data->dev->of_node, "touchscreen", 0);
+ /* Never happens already checked in q8_hardwaremgr_do_probe() */
+ if (WARN_ON(!np))
+ return;
+
+ of_changeset_init(&cset);
+ of_changeset_add_property_u32(&cset, np, "reg", data->touchscreen_addr);
+ of_changeset_add_property_string(&cset, np, "compatible",
+ data->touchscreen_compatible);
+
+ if (data->touchscreen_width)
+ of_changeset_add_property_u32(&cset, np, "touchscreen-size-x",
+ data->touchscreen_width);
+ if (data->touchscreen_height)
+ of_changeset_add_property_u32(&cset, np, "touchscreen-size-y",
+ data->touchscreen_height);
+ if (data->touchscreen_invert_x)
+ of_changeset_add_property_bool(&cset, np,
+ "touchscreen-inverted-x");
+ if (data->touchscreen_invert_y)
+ of_changeset_add_property_bool(&cset, np,
+ "touchscreen-inverted-y");
+ if (data->touchscreen_swap_x_y)
+ of_changeset_add_property_bool(&cset, np,
+ "touchscreen-swapped-x-y");
+ if (data->touchscreen_fw_name)
+ of_changeset_add_property_string(&cset, np, "firmware-name",
+ data->touchscreen_fw_name);
+ if (data->touchscreen_needs_regulator) {
+ struct property *p;
+
+ p = of_find_property(dev->of_node, "touchscreen-supply", NULL);
+ /* Never happens already checked in q8_hardwaremgr_do_probe() */
+ if (WARN_ON(!p))
+ return;
+
+ of_changeset_add_property_copy(&cset, np, "vddio-supply",
+ p->value, p->length);
+ }
+
+ of_changeset_update_property_string(&cset, np, "status", "okay");
+ of_changeset_apply(&cset);
+
+ of_node_put(np);
+}
+
+static int q8_hardwaremgr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct q8_hardwaremgr_data *data;
+ int ret = 0;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = &pdev->dev;
+
+ ret = q8_hardwaremgr_do_probe(data, "touchscreen",
+ q8_hardwaremgr_probe_touchscreen);
+ if (ret)
+ goto error;
+
+ /*
+ * Our pinctrl may conflict with the pinctrl of the detected devices
+ * we're adding, so remove it before adding detected devices.
+ */
+ if (dev->pins) {
+ devm_pinctrl_put(dev->pins->p);
+ devm_kfree(dev, dev->pins);
+ dev->pins = NULL;
+ }
+
+ q8_hardwaremgr_apply_touchscreen(data);
+
+error:
+ kfree(data);
+
+ return ret;
+}
+
+static const struct of_device_id q8_hardwaremgr_of_match[] = {
+ { .compatible = "allwinner,sunxi-q8-hardwaremgr", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, q8_hardwaremgr_of_match);
+
+static struct platform_driver q8_hardwaremgr_driver = {
+ .driver = {
+ .name = "q8-hardwaremgr",
+ .of_match_table = of_match_ptr(q8_hardwaremgr_of_match),
+ },
+ .probe = q8_hardwaremgr_probe,
+};
+
+module_platform_driver(q8_hardwaremgr_driver);
+
+MODULE_DESCRIPTION("Allwinner q8 formfactor tablet hardware manager");
+MODULE_AUTHOR("Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>");
+MODULE_LICENSE("GPL");
--
2.9.3
next prev parent reply other threads:[~2016-09-01 19:08 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-01 19:08 [RFC 0/1] misc: Add Allwinner Q8 tablet hardware manager Hans de Goede
[not found] ` <20160901190820.21987-1-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2016-09-01 19:08 ` Hans de Goede [this message]
[not found] ` <20160901190820.21987-2-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2016-09-09 19:13 ` [RFC] " Pantelis Antoniou
[not found] ` <9E68DE9D-31CE-4F2D-9852-684A8B28A181-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2016-09-10 18:22 ` Hans de Goede
2016-09-09 21:41 ` Rob Herring
[not found] ` <CAL_JsqLGS23JQxtdtUqNhkhDiV4mnKSBpMjdo4fx0=wuq_ydeg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-09-10 18:12 ` [linux-sunxi] " Hans de Goede
[not found] ` <268244d0-55c3-167d-a70f-0e35e6b3dae6-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2016-09-12 14:05 ` Rob Herring
2016-09-09 21:32 ` [RFC 0/1] " Rob Herring
[not found] ` <CAL_JsqJVkPPiDh66nhfh0D7BvkZ7KKN0X7uhfPGgiYbc2Ca1rg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-10-12 9:48 ` Mark Rutland
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=20160901190820.21987-2-hdegoede@redhat.com \
--to=hdegoede-h+wxahxf7alqt0dzr+alfa@public.gmane.org \
--cc=arnd-r2nGTMty4D4@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org \
--cc=maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org \
--cc=pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org \
--cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=wens-jdAy2FN1RRM@public.gmane.org \
/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 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).