From patchwork Thu Jan 28 16:52:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lubomir Rintel X-Patchwork-Id: 12054479 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BFFECC433E0 for ; Thu, 28 Jan 2021 19:44:58 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EAFF764E36 for ; Thu, 28 Jan 2021 19:44:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EAFF764E36 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=v3.sk Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D289A6E9FD; Thu, 28 Jan 2021 19:44:36 +0000 (UTC) Received: from shell.v3.sk (mail.v3.sk [167.172.186.51]) by gabe.freedesktop.org (Postfix) with ESMTPS id 28D6B6E9BC for ; Thu, 28 Jan 2021 16:52:16 +0000 (UTC) Received: from localhost (localhost.localdomain [127.0.0.1]) by zimbra.v3.sk (Postfix) with ESMTP id 0BA8DE0B2E; Thu, 28 Jan 2021 16:48:10 +0000 (UTC) Received: from shell.v3.sk ([127.0.0.1]) by localhost (zimbra.v3.sk [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id upg9um6BP9nN; Thu, 28 Jan 2021 16:48:07 +0000 (UTC) Received: from localhost (localhost.localdomain [127.0.0.1]) by zimbra.v3.sk (Postfix) with ESMTP id D2DD6E0B2B; Thu, 28 Jan 2021 16:48:07 +0000 (UTC) X-Virus-Scanned: amavisd-new at zimbra.v3.sk Received: from shell.v3.sk ([127.0.0.1]) by localhost (zimbra.v3.sk [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id PQ1EsHMStgVC; Thu, 28 Jan 2021 16:48:07 +0000 (UTC) Received: from localhost (unknown [109.183.109.54]) by zimbra.v3.sk (Postfix) with ESMTPSA id 3F529E0B28; Thu, 28 Jan 2021 16:48:07 +0000 (UTC) From: Lubomir Rintel To: Andrzej Hajda Subject: [PATCH v7 1/2] dt-bindings: display: himax, hx8837: Add Himax HX8837 bindings Date: Thu, 28 Jan 2021 17:52:08 +0100 Message-Id: <20210128165209.59903-2-lkundrak@v3.sk> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210128165209.59903-1-lkundrak@v3.sk> References: <20210128165209.59903-1-lkundrak@v3.sk> MIME-Version: 1.0 X-Mailman-Approved-At: Thu, 28 Jan 2021 19:44:35 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Jernej Skrabec , Jonas Karlman , David Airlie , Neil Armstrong , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Lubomir Rintel , Rob Herring , Laurent Pinchart , Sam Ravnborg Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Himax HX8837 is a secondary display controller used to drive the panel on OLPC platforms. Signed-off-by: Lubomir Rintel Reviewed-by: Rob Herring --- Changes since v6: (All based on feedback from Laurent Pinchart) - Add power supplies - Make load/stat-gpios optional - Fix whitespace errors - Use decimal constants instead of hex in example where appropriate - Terminate the bindings with "..." end-of-document marker Changes since v4: - Rob's Reviewed-by Changes since v3: - Moved to bindings/display/ - Added the ports - Converted to YAML - Removed Pavel's Ack, because the changes are substantial Changes since v2: - s/betweend/between/ Changes since v1: - s/load-gpio/load-gpios/ - Use interrupt bindings instead of gpio for the IRQ .../bindings/display/bridge/himax,hx8837.yaml | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/himax,hx8837.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/himax,hx8837.yaml b/Documentation/devicetree/bindings/display/bridge/himax,hx8837.yaml new file mode 100644 index 0000000000000..e9e21a3447088 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/himax,hx8837.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2018,2019,2020,2021 Lubomir Rintel +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/himax,hx8837.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HX8837 Display Controller Device Tree Bindings + +maintainers: + - Lubomir Rintel + +properties: + compatible: + const: himax,hx8837 + + reg: + const: 0xd + + load-gpios: + maxItems: 1 + description: GPIO specifier of DCON_LOAD pin (active high) + + stat-gpios: + minItems: 2 + description: GPIO specifier of DCON_STAT0 and DCON_STAT1 pins (active high) + + interrupts: + maxItems: 1 + description: Interrupt specifier of DCON_IRQ pin (edge falling) + + vddp18-supply: + description: Regulator for 1.8V display interface I/O power. + + vddm25-supply: + description: Regulator for 2.5V SDRAM I/O power. + + vdd33-supply: + description: Regulator for 3.3V digital I/O power. + + vddk18-supply: + description: Regulator for 1.8V internal core power. + + ports: + type: object + + properties: + port@0: + type: object + description: | + Video port for RGB input. + + port@1: + type: object + description: | + Video port connected to the panel. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - interrupts + - ports + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + lcd-controller@d { + compatible = "himax,hx8837"; + reg = <0x0d>; + stat-gpios = <&gpio 100 GPIO_ACTIVE_HIGH>, + <&gpio 101 GPIO_ACTIVE_HIGH>; + load-gpios = <&gpio 142 GPIO_ACTIVE_HIGH>; + interrupts = <&gpio 124 IRQ_TYPE_EDGE_FALLING>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dcon_rgb_in: endpoint { + remote-endpoint = <&lcd0_rgb_out>; + }; + }; + + port@1 { + reg = <1>; + dcon_gettl_out: endpoint { + remote-endpoint = <&panel_dettl_in>; + }; + }; + }; + }; + }; + +... From patchwork Thu Jan 28 16:52:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lubomir Rintel X-Patchwork-Id: 12054493 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DF408C433DB for ; Thu, 28 Jan 2021 19:45:19 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9622A64D99 for ; Thu, 28 Jan 2021 19:45:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9622A64D99 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=v3.sk Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C9A1E6EA26; Thu, 28 Jan 2021 19:44:41 +0000 (UTC) Received: from shell.v3.sk (mail.v3.sk [167.172.186.51]) by gabe.freedesktop.org (Postfix) with ESMTPS id AB38F6E9BC for ; Thu, 28 Jan 2021 16:52:16 +0000 (UTC) Received: from localhost (localhost.localdomain [127.0.0.1]) by zimbra.v3.sk (Postfix) with ESMTP id 7C31AE0B2B; Thu, 28 Jan 2021 16:48:10 +0000 (UTC) Received: from shell.v3.sk ([127.0.0.1]) by localhost (zimbra.v3.sk [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id OqZcDM8R6RHs; Thu, 28 Jan 2021 16:48:08 +0000 (UTC) Received: from localhost (localhost.localdomain [127.0.0.1]) by zimbra.v3.sk (Postfix) with ESMTP id 4234BE0B28; Thu, 28 Jan 2021 16:48:08 +0000 (UTC) X-Virus-Scanned: amavisd-new at zimbra.v3.sk Received: from shell.v3.sk ([127.0.0.1]) by localhost (zimbra.v3.sk [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id lUwDgMKADM6Y; Thu, 28 Jan 2021 16:48:07 +0000 (UTC) Received: from localhost (unknown [109.183.109.54]) by zimbra.v3.sk (Postfix) with ESMTPSA id ACBCFE0B17; Thu, 28 Jan 2021 16:48:07 +0000 (UTC) From: Lubomir Rintel To: Andrzej Hajda Subject: [PATCH v7 2/2] drm/bridge: hx8837: add a Himax HX8837 display controller driver Date: Thu, 28 Jan 2021 17:52:09 +0100 Message-Id: <20210128165209.59903-3-lkundrak@v3.sk> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210128165209.59903-1-lkundrak@v3.sk> References: <20210128165209.59903-1-lkundrak@v3.sk> MIME-Version: 1.0 X-Mailman-Approved-At: Thu, 28 Jan 2021 19:44:35 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Jernej Skrabec , Jonas Karlman , David Airlie , Neil Armstrong , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Lubomir Rintel , Rob Herring , Laurent Pinchart , Sam Ravnborg Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Himax HX8837 is used to drive the LCD panel on OLPC platforms. It controls the panel backlight and is able to refresh it when the LCD controller (and the rest of the plaform) is powered off. It also converts regular RGB color data from the LCDC so that it looks reasonable on the OLPC LCD panel with a monochromatic layer on top of a layer that can either reflect light (b/w sunlight readable mode) or light pattern of red, green and blue pixels. At this point, the driver is rather basic. The self-refresh mode is not supported. There's no way of independently controlling the color swizzling, antialiasing or b/w conversion, but it probably isn't too useful either. There's another driver for the same hardware on OLPC XO-1.5 and XO-1.75 in drivers/staging/olpc_dcon. The display on that hardware doesn't utilize DRM, so this driver doesn't replace the other one yet. Signed-off-by: Lubomir Rintel --- Changes since v6: (All also based on feedback from Sam Ravnborg) - Drop selecting BACKLIGHT_LCD_SUPPORT - Don't include drm/drm_print.h anymore - Fix or clarify a couple of error messages - Remove printing of info banner at end of probe() Changes since v5: (All based on feedback from Sam Ravnborg) - Fix indentation in Kconfig - Sort #includes - Use a constant for max brightness instead of a literal - Remove struct drm_panel from priv data - Use dev_err() instead of DRM_ERROR - Replace direct use of backlight props.brightness with backlight_get_brightness() - Document sentinels with { /* sentinel */ } - Remove unsetting of panel->backlight Changes since v3: - Added this patch, in place of a driver derived from drivers/staging/olpc_dcon. Compared to the previous one this implements the bare minimum, without the fancy stuff such as self-refresh that need more work/thinking. drivers/gpu/drm/bridge/Kconfig | 12 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/himax-hx8837.c | 328 ++++++++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 drivers/gpu/drm/bridge/himax-hx8837.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index e4110d6ca7b3c..9d753f55bcc05 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -48,6 +48,18 @@ config DRM_DISPLAY_CONNECTOR on ARM-based platforms. Saying Y here when this driver is not needed will not cause any issue. +config DRM_HIMAX_HX8837 + tristate "HiMax HX8837 OLPC Display Controller" + depends on OF + depends on OLPC || ARCH_MMP || COMPILE_TEST + select DRM_KMS_HELPER + select BACKLIGHT_CLASS_DEVICE + help + Enable support for HiMax HX8837 Display Controller as found in the + OLPC XO laptops. + + If your laptop doesn't have green ears, say "N" + config DRM_LONTIUM_LT9611 tristate "Lontium LT9611 DSI/HDMI bridge" select SND_SOC_HDMI_CODEC if SND_SOC diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 86e7acc76f8d6..1e27939d69d09 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o +obj-$(CONFIG_DRM_HIMAX_HX8837) += himax-hx8837.o obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o diff --git a/drivers/gpu/drm/bridge/himax-hx8837.c b/drivers/gpu/drm/bridge/himax-hx8837.c new file mode 100644 index 0000000000000..b97b71ba3f32e --- /dev/null +++ b/drivers/gpu/drm/bridge/himax-hx8837.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HiMax HX8837 Display Controller Driver + * + * Datasheet: http://wiki.laptop.org/images/0/09/DCON_datasheet_HX8837-A.pdf + * + * Copyright (C) 2020 Lubomir Rintel + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define bridge_to_hx8837_priv(x) \ + container_of(x, struct hx8837_priv, bridge) + +/* DCON registers */ +enum { + DCON_REG_ID = 0x00, + DCON_REG_MODE = 0x01, + DCON_REG_HRES = 0x02, + DCON_REG_HTOTAL = 0x03, + DCON_REG_HSYNC_WIDTH = 0x04, + DCON_REG_VRES = 0x05, + DCON_REG_VTOTAL = 0x06, + DCON_REG_VSYNC_WIDTH = 0x07, + DCON_REG_TIMEOUT = 0x08, + DCON_REG_SCAN_INT = 0x09, + DCON_REG_BRIGHT = 0x0a, + DCON_REG_MEM_OPT_A = 0x41, + DCON_REG_MEM_OPT_B = 0x42, +}; + +/* DCON_REG_MODE */ +enum { + MODE_PASSTHRU = BIT(0), + MODE_SLEEP = BIT(1), + MODE_SLEEP_AUTO = BIT(2), + MODE_BL_ENABLE = BIT(3), + MODE_BLANK = BIT(4), + MODE_CSWIZZLE = BIT(5), + MODE_COL_AA = BIT(6), + MODE_MONO_LUMA = BIT(7), + MODE_SCAN_INT = BIT(8), + MODE_CLOCKDIV = BIT(9), + MODE_DEBUG = BIT(14), + MODE_SELFTEST = BIT(15), +}; + +/* DCON_REG_BRIGHT */ +enum { + BRIGHT_MASK = GENMASK(7, 0), +}; + +struct hx8837_priv { + struct device *dev; + struct regmap *regmap; + struct gpio_desc *load_gpio; + + struct drm_bridge *panel_bridge; + struct drm_bridge bridge; +}; + +static int hx8837_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct hx8837_priv *priv = bridge_to_hx8837_priv(bridge); + + return drm_bridge_attach(bridge->encoder, priv->panel_bridge, + bridge, flags); +} + +static enum drm_mode_status hx8837_bridge_mode_valid( + struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + if (mode->hdisplay > 0xffff) + return MODE_BAD_HVALUE; + if (mode->htotal > 0xffff) + return MODE_BAD_HVALUE; + if (mode->hsync_start - mode->hdisplay > 0xff) + return MODE_HBLANK_WIDE; + if (mode->hsync_end - mode->hsync_start > 0xff) + return MODE_HSYNC_WIDE; + if (mode->vdisplay > 0xffff) + return MODE_BAD_VVALUE; + if (mode->vtotal > 0xffff) + return MODE_BAD_VVALUE; + if (mode->vsync_start - mode->vdisplay > 0xff) + return MODE_VBLANK_WIDE; + if (mode->vsync_end - mode->vsync_start > 0xff) + return MODE_VSYNC_WIDE; + + return MODE_OK; +} + +static void hx8837_bridge_disable(struct drm_bridge *bridge) +{ + struct hx8837_priv *priv = bridge_to_hx8837_priv(bridge); + int ret; + + ret = gpiod_direction_output(priv->load_gpio, 0); + if (ret) + dev_err(priv->dev, "error disabling the dcon load: %d\n", ret); + + ret = regmap_update_bits(priv->regmap, DCON_REG_MODE, + MODE_PASSTHRU | + MODE_SLEEP, + MODE_PASSTHRU | + MODE_SLEEP); + if (ret) + dev_err(priv->dev, "error disabling the dcon: %d\n", ret); +} + +static void hx8837_bridge_enable(struct drm_bridge *bridge) +{ + struct hx8837_priv *priv = bridge_to_hx8837_priv(bridge); + int ret; + + ret = regmap_update_bits(priv->regmap, DCON_REG_MODE, + MODE_PASSTHRU | + MODE_SLEEP | + MODE_SLEEP_AUTO | + MODE_BLANK | + MODE_SCAN_INT | + MODE_CLOCKDIV | + MODE_DEBUG | + MODE_SELFTEST, + MODE_PASSTHRU); + if (ret) + dev_err(priv->dev, "error enabling the dcon: %d\n", ret); + + ret = gpiod_direction_output(priv->load_gpio, 1); + if (ret) + dev_err(priv->dev, "error enabling the dcon load: %d\n", ret); +} + +static void hx8837_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct hx8837_priv *priv = bridge_to_hx8837_priv(bridge); + + regmap_write(priv->regmap, DCON_REG_HRES, mode->hdisplay); + regmap_write(priv->regmap, DCON_REG_HTOTAL, mode->htotal); + regmap_write(priv->regmap, DCON_REG_HSYNC_WIDTH, + (mode->hsync_start - mode->hdisplay) << 8 | + (mode->hsync_end - mode->hsync_start)); + regmap_write(priv->regmap, DCON_REG_VRES, mode->vdisplay); + regmap_write(priv->regmap, DCON_REG_VTOTAL, mode->vtotal); + regmap_write(priv->regmap, DCON_REG_VSYNC_WIDTH, + (mode->vsync_start - mode->vdisplay) << 8 | + (mode->vsync_end - mode->vsync_start)); +} + +static const struct drm_bridge_funcs hx8837_bridge_funcs = { + .attach = hx8837_bridge_attach, + .mode_valid = hx8837_bridge_mode_valid, + .disable = hx8837_bridge_disable, + .enable = hx8837_bridge_enable, + .mode_set = hx8837_bridge_mode_set, +}; + +static int hx8837_bl_update_status(struct backlight_device *bl) +{ + struct hx8837_priv *priv = bl_get_data(bl); + unsigned int val; + int ret; + + ret = regmap_update_bits(priv->regmap, DCON_REG_BRIGHT, + BRIGHT_MASK, + backlight_get_brightness(bl)); + if (ret) { + dev_err(&bl->dev, "error setting the backlight: %d\n", ret); + return ret; + } + + if (backlight_get_brightness(bl)) + val = MODE_CSWIZZLE | MODE_COL_AA; + else + val = MODE_MONO_LUMA; + + ret = regmap_update_bits(priv->regmap, DCON_REG_MODE, + MODE_CSWIZZLE | + MODE_COL_AA | + MODE_MONO_LUMA, + val); + if (ret) { + dev_err(&bl->dev, "error setting color mode: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct backlight_ops hx8837_bl_ops = { + .update_status = hx8837_bl_update_status, +}; + +static const struct regmap_config hx8837_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 0x4c, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int hx8837_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct backlight_properties bl_props = { + .type = BACKLIGHT_RAW, + .max_brightness = BRIGHT_MASK, + }; + struct device *dev = &client->dev; + struct backlight_device *bl; + struct hx8837_priv *priv; + struct drm_panel *panel; + unsigned int val; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + priv->dev = dev; + + priv->load_gpio = devm_gpiod_get(dev, "load", GPIOD_ASIS); + if (IS_ERR(priv->load_gpio)) + return PTR_ERR(priv->load_gpio); + + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, &panel, NULL); + if (ret) + return ret; + + if (panel->backlight) { + dev_err(dev, "the panel already has a backlight controller\n"); + return -ENODEV; + } + + priv->panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(priv->panel_bridge)) + return PTR_ERR(priv->panel_bridge); + + priv->regmap = devm_regmap_init_i2c(client, &hx8837_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(dev, "regmap_init_i2c failed\n"); + return PTR_ERR(priv->regmap); + } + + ret = regmap_read(priv->regmap, DCON_REG_ID, &val); + if (ret < 0) { + dev_err(dev, "error reading the model id: %d\n", ret); + return ret; + } + if ((val & 0xff00) != 0xdc00) { + dev_err(dev, "the device is not a hx8837\n"); + return -ENODEV; + } + + ret = regmap_read(priv->regmap, DCON_REG_BRIGHT, &val); + if (ret < 0) { + dev_err(&bl->dev, "error getting the backlight: %d\n", ret); + return ret; + } + bl_props.brightness = val & 0xf; + + bl = devm_backlight_device_register(dev, dev_name(dev), dev, priv, + &hx8837_bl_ops, &bl_props); + if (IS_ERR(bl)) { + dev_err(dev, "failed to register backlight\n"); + return PTR_ERR(bl); + } + + panel->backlight = bl; + + INIT_LIST_HEAD(&priv->bridge.list); + priv->bridge.funcs = &hx8837_bridge_funcs; + priv->bridge.of_node = dev->of_node; + drm_bridge_add(&priv->bridge); + + return 0; +} + +static int hx8837_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct hx8837_priv *priv = dev_get_drvdata(dev); + + drm_bridge_remove(&priv->bridge); + + return 0; +} + +static const struct of_device_id hx8837_dt_ids[] = { + { .compatible = "himax,hx8837", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, hx8837_dt_ids); + +static const struct i2c_device_id hx8837_ids[] = { + { "hx8837", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, hx8837_ids); + +static struct i2c_driver hx8837_driver = { + .probe = hx8837_probe, + .remove = hx8837_remove, + .driver = { + .name = "hx8837", + .of_match_table = of_match_ptr(hx8837_dt_ids), + }, + .id_table = hx8837_ids, +}; + +module_i2c_driver(hx8837_driver); + +MODULE_AUTHOR("Lubomir Rintel "); +MODULE_DESCRIPTION("HiMax HX8837 Display Controller Driver"); +MODULE_LICENSE("GPL");