From patchwork Mon Nov 19 08:54:44 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Fuzzey X-Patchwork-Id: 1763541 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id AE8F73FCA5 for ; Mon, 19 Nov 2012 08:56:52 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TaN87-0003va-Qm; Mon, 19 Nov 2012 08:54:59 +0000 Received: from mta1.parkeon.com ([91.121.43.66]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TaN81-0003v2-1i for linux-arm-kernel@lists.infradead.org; Mon, 19 Nov 2012 08:54:56 +0000 Received: from mta2.parkeon.com ([81.80.172.220]) by mta1.parkeon.com with esmtp (Exim 4.76) (envelope-from ) id 1TaN7s-0006qv-Gy; Mon, 19 Nov 2012 09:54:44 +0100 Received: from [10.32.16.23] (helo=mail.besancon.parkeon.com) by mta2.parkeon.com with esmtp (Exim 4.77) (envelope-from ) id 1TaN7q-0001Ew-Lp; Mon, 19 Nov 2012 09:54:42 +0100 Received: from [10.32.51.221] (port=46548 helo=[127.0.0.1]) by mail.besancon.parkeon.com with esmtp (Exim 4.71) (envelope-from ) id 1TaN7s-0000Tl-0i; Mon, 19 Nov 2012 09:54:44 +0100 Subject: [PATCH] Video: Backlight: Add a MMIO backlight driver using DT. To: Richard Purdie From: Martin Fuzzey Date: Mon, 19 Nov 2012 09:54:44 +0100 Message-ID: <20121119085443.350.96371.stgit@localhost> User-Agent: StGit/0.15 MIME-Version: 1.0 X-Virus-Scanned: by ClamAV at mta2.parkeon.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121119_035453_365807_3F2AB63A X-CRM114-Status: GOOD ( 23.29 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Some boards have very simple backlight controllers consisting of a latch on the bus with a bunch of resistors used as a "poor man's DAC". Prior to the device tree such boards were supported using generic-bl with a callback in the board file to poke the hardware. This driver allows such hardware to be supported on device tree based platforms where callbacks and board files cannot be used. Signed-off-by: Martin Fuzzey --- .../bindings/video/backlight/mmio_bl.txt | 50 ++++ drivers/video/backlight/Kconfig | 12 + drivers/video/backlight/Makefile | 1 drivers/video/backlight/mmio_bl.c | 225 ++++++++++++++++++++ 4 files changed, 288 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/video/backlight/mmio_bl.txt create mode 100644 drivers/video/backlight/mmio_bl.c diff --git a/Documentation/devicetree/bindings/video/backlight/mmio_bl.txt b/Documentation/devicetree/bindings/video/backlight/mmio_bl.txt new file mode 100644 index 0000000..39a53d0 --- /dev/null +++ b/Documentation/devicetree/bindings/video/backlight/mmio_bl.txt @@ -0,0 +1,50 @@ +Memory mapped IO backlight bindings +=================================== + +Required properties: + - compatible : mmio-bl + - reg : register address and size + +Optional properties: + - reg-width : Register size in bits (default = 8 * size of reg) + - reg-shift : Register shift in bits (default = 0) + - max-brightness : Maximum brightness (defaults to all bits 1) + - default-brightness : Default brightness (defaults to all bits 1) + +The size of reg must be 1,2 or 4 bytes and is used to determine the type +of bus access. + +The brightness values are silently clamped to the maximum supported by +reg-width. + +Examples: + backlight@1,0 { + compatible = "mmio-bl"; + reg = <1 0 2>; + }; + Defines a 16 bit register with max and default brightness 0xFFFF + + + backlight@1,0 { + compatible = "mmio-bl"; + reg = <1 0 1>; + reg-width = <6>; + reg-shift = <1>; + max-brightness = <50>; + default-brightness = <40>; + }; + Defines a 6 bit register on D1->D7 so that + brightness 0 => X000000X + brigtness 50 => X110010X + + + backlight@1,0 { + compatible = "mmio-bl"; + reg = <1 0 1>; + reg-width = <6>; + max-brightness = <100>; + default-brightness = <100>; + }; + Defines a 6 bit register on D0->D5 with maximum and default + brighntesses of 63 (since not enough bits for 100) + diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 765a945..6482092 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -185,6 +185,18 @@ config BACKLIGHT_GENERIC known as the Corgi backlight driver. If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y. +config BACKLIGHT_MMIO + tristate "Memory Mapped IO Backlight Driver" + depends on OF + default n + help + Say Y to enable backlight driver for simple memory mapped latches. + + Typically this type of backlight interface consists of a latch on + the bus with a bunch of resistors behind it (a poor man's DAC). + A device tree configuration is required, non DT systems can + use BACKLIGHT_GENERIC instead with a board specific callback. + config BACKLIGHT_LM3533 tristate "Backlight Driver for LM3533" depends on BACKLIGHT_CLASS_DEVICE diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index e7ce729..9de5aa2 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o +obj-$(CONFIG_BACKLIGHT_MMIO) += mmio_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o diff --git a/drivers/video/backlight/mmio_bl.c b/drivers/video/backlight/mmio_bl.c new file mode 100644 index 0000000..e5442d9 --- /dev/null +++ b/drivers/video/backlight/mmio_bl.c @@ -0,0 +1,225 @@ +/* + * Memory mapped IO backlight driver. + * + * Copyright (c) 2012 Martin Fuzzey (Parkeon) + * + * Supports backlights controlled by simple bus addressed + * latches with a poor man's DAC (a bunch of resistors) + * + * This used to be done with generic_bl but it requires + * callbacks in platform_data which are not supported by device tree. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +struct mmio_bl_data { + void __iomem *reg; + int brightness; + void (*set_brightness)(struct mmio_bl_data *data); + u32 mask; + u8 shift; +}; + +static void mmio_set_brightness_8bit(struct mmio_bl_data *data) +{ + u8 value = readb(data->reg); + + value &= ~data->mask; + value |= (data->brightness << data->shift) & data->mask; + writeb(value, data->reg); +} + +static void mmio_set_brightness_16bit(struct mmio_bl_data *data) +{ + u16 value = readw(data->reg); + + value &= ~data->mask; + value |= (data->brightness << data->shift) & data->mask; + writew(value, data->reg); +} + +static void mmio_set_brightness_32bit(struct mmio_bl_data *data) +{ + u32 value = readl(data->reg); + + value &= ~data->mask; + value |= (data->brightness << data->shift) & data->mask; + writel(value, data->reg); +} + +static int mmio_bl_update_status(struct backlight_device *bd) +{ + int brightness = bd->props.brightness; + struct mmio_bl_data *data = bl_get_data(bd); + + if (bd->props.power != FB_BLANK_UNBLANK) + brightness = 0; + if (bd->props.state & BL_CORE_FBBLANK) + brightness = 0; + if (bd->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + pr_info("set brightness %d\n", brightness); + data->brightness = brightness; + data->set_brightness(data); + return 0; +} + +static int mmio_bl_get_brightness(struct backlight_device *bd) +{ + struct mmio_bl_data *data = bl_get_data(bd); + + return data->brightness; +} + +static const struct backlight_ops mmio_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = mmio_bl_get_brightness, + .update_status = mmio_bl_update_status, +}; + +static void mmio_bl_configure_from_dt( + struct device *dev, + resource_size_t res_size, + struct mmio_bl_data *data, + struct backlight_properties *props) +{ + struct device_node *of_node = dev->of_node; + u32 bits = res_size * 8; + u32 shift = 0; + u32 max_brightness, brightness; + + of_property_read_u32(of_node, "reg-width", &bits); + of_property_read_u32(of_node, "reg-shift", &shift); + data->mask = ((1 << bits) - 1) << shift; + data->shift = shift; + + max_brightness = 1 << bits; + brightness = max_brightness; + of_property_read_u32(of_node, "max-brightness", &max_brightness); + of_property_read_u32(of_node, "default-brightness", &brightness); + max_brightness = min(max_brightness, 1U << bits); + brightness = min(brightness, max_brightness); + + dev_dbg(dev, "brightness: max=%d default=%d mask:%X\n", + max_brightness, brightness, data->mask); + + props->max_brightness = max_brightness; + props->brightness = brightness; +} + +static int mmio_bl_probe(struct platform_device *pdev) +{ + struct backlight_properties props = {0,}; + struct backlight_device *bd; + struct mmio_bl_data *data; + struct resource *res; + resource_size_t res_size; + int ret; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -EINVAL; + goto out_err; + } + + res_size = resource_size(res); + switch (res_size) { + case 1: + data->set_brightness = mmio_set_brightness_8bit; + break; + case 2: + data->set_brightness = mmio_set_brightness_16bit; + break; + case 4: + data->set_brightness = mmio_set_brightness_32bit; + break; + default: + dev_err(&pdev->dev, + "Invalid resource size %d (must be 1/2/4)\n", res_size); + ret = -EINVAL; + goto out_err; + } + + props.type = BACKLIGHT_RAW; + mmio_bl_configure_from_dt(&pdev->dev, res_size, data, &props); + + data->reg = devm_request_and_ioremap(&pdev->dev, res); + if (!data->reg) { + ret = -EADDRNOTAVAIL; + goto out_err; + } + + + bd = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, + data, &mmio_bl_ops, &props); + if (IS_ERR(bd)) { + ret = PTR_ERR(bd); + goto out_err; + } + + platform_set_drvdata(pdev, bd); + + bd->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bd); + + pr_info("MMIO Backlight Driver Initialized.\n"); + return 0; + +out_err: + kfree(data); + return ret; +} + +static int mmio_bl_remove(struct platform_device *pdev) +{ + struct backlight_device *bd = platform_get_drvdata(pdev); + + bd->props.power = 0; + bd->props.brightness = 0; + backlight_update_status(bd); + + backlight_device_unregister(bd); + + pr_info("MMIO Backlight Driver Unloaded\n"); + return 0; +} + +static const struct of_device_id mmio_bl_of_match[] = { + { .compatible = "mmio-bl" }, + {}, +}; +MODULE_DEVICE_TABLE(of, platform_lcd_of_match); + +static struct platform_driver mmio_bl_driver = { + .probe = mmio_bl_probe, + .remove = mmio_bl_remove, + .driver = { + .name = "mmio-bl", + .of_match_table = of_match_ptr(mmio_bl_of_match), + }, +}; + +module_platform_driver(mmio_bl_driver); + +MODULE_AUTHOR("Martin Fuzzey "); +MODULE_DESCRIPTION("Memory Mapped IO Backlight Driver"); +MODULE_LICENSE("GPL");