linux/drivers/video/backlight/l4f00242t03.c
<<
>>
Prefs
   1/*
   2 * l4f00242t03.c -- support for Epson L4F00242T03 LCD
   3 *
   4 * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
   5 *
   6 * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
   7 *      Inspired by Marek Vasut work in l4f00242t03.c
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15
  16#include <linux/device.h>
  17#include <linux/kernel.h>
  18#include <linux/delay.h>
  19#include <linux/module.h>
  20#include <linux/gpio.h>
  21#include <linux/lcd.h>
  22#include <linux/slab.h>
  23#include <linux/regulator/consumer.h>
  24
  25#include <linux/spi/spi.h>
  26#include <linux/spi/l4f00242t03.h>
  27
  28struct l4f00242t03_priv {
  29        struct spi_device       *spi;
  30        struct lcd_device       *ld;
  31        int lcd_state;
  32        struct regulator *io_reg;
  33        struct regulator *core_reg;
  34};
  35
  36static void l4f00242t03_reset(unsigned int gpio)
  37{
  38        pr_debug("l4f00242t03_reset.\n");
  39        gpio_set_value(gpio, 1);
  40        mdelay(100);
  41        gpio_set_value(gpio, 0);
  42        mdelay(10);     /* tRES >= 100us */
  43        gpio_set_value(gpio, 1);
  44        mdelay(20);
  45}
  46
  47#define param(x) ((x) | 0x100)
  48
  49static void l4f00242t03_lcd_init(struct spi_device *spi)
  50{
  51        struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev);
  52        struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
  53        const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) };
  54        int ret;
  55
  56        dev_dbg(&spi->dev, "initializing LCD\n");
  57
  58        ret = regulator_set_voltage(priv->io_reg, 1800000, 1800000);
  59        if (ret) {
  60                dev_err(&spi->dev, "failed to set the IO regulator voltage.\n");
  61                return;
  62        }
  63        ret = regulator_enable(priv->io_reg);
  64        if (ret) {
  65                dev_err(&spi->dev, "failed to enable the IO regulator.\n");
  66                return;
  67        }
  68
  69        ret = regulator_set_voltage(priv->core_reg, 2800000, 2800000);
  70        if (ret) {
  71                dev_err(&spi->dev, "failed to set the core regulator voltage.\n");
  72                regulator_disable(priv->io_reg);
  73                return;
  74        }
  75        ret = regulator_enable(priv->core_reg);
  76        if (ret) {
  77                dev_err(&spi->dev, "failed to enable the core regulator.\n");
  78                regulator_disable(priv->io_reg);
  79                return;
  80        }
  81
  82        l4f00242t03_reset(pdata->reset_gpio);
  83
  84        gpio_set_value(pdata->data_enable_gpio, 1);
  85        msleep(60);
  86        spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16));
  87}
  88
  89static void l4f00242t03_lcd_powerdown(struct spi_device *spi)
  90{
  91        struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev);
  92        struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
  93
  94        dev_dbg(&spi->dev, "Powering down LCD\n");
  95
  96        gpio_set_value(pdata->data_enable_gpio, 0);
  97
  98        regulator_disable(priv->io_reg);
  99        regulator_disable(priv->core_reg);
 100}
 101
 102static int l4f00242t03_lcd_power_get(struct lcd_device *ld)
 103{
 104        struct l4f00242t03_priv *priv = lcd_get_data(ld);
 105
 106        return priv->lcd_state;
 107}
 108
 109static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power)
 110{
 111        struct l4f00242t03_priv *priv = lcd_get_data(ld);
 112        struct spi_device *spi = priv->spi;
 113
 114        const u16 slpout = 0x11;
 115        const u16 dison = 0x29;
 116
 117        const u16 slpin = 0x10;
 118        const u16 disoff = 0x28;
 119
 120        if (power <= FB_BLANK_NORMAL) {
 121                if (priv->lcd_state <= FB_BLANK_NORMAL) {
 122                        /* Do nothing, the LCD is running */
 123                } else if (priv->lcd_state < FB_BLANK_POWERDOWN) {
 124                        dev_dbg(&spi->dev, "Resuming LCD\n");
 125
 126                        spi_write(spi, (const u8 *)&slpout, sizeof(u16));
 127                        msleep(60);
 128                        spi_write(spi, (const u8 *)&dison, sizeof(u16));
 129                } else {
 130                        /* priv->lcd_state == FB_BLANK_POWERDOWN */
 131                        l4f00242t03_lcd_init(spi);
 132                        priv->lcd_state = FB_BLANK_VSYNC_SUSPEND;
 133                        l4f00242t03_lcd_power_set(priv->ld, power);
 134                }
 135        } else if (power < FB_BLANK_POWERDOWN) {
 136                if (priv->lcd_state <= FB_BLANK_NORMAL) {
 137                        /* Send the display in standby */
 138                        dev_dbg(&spi->dev, "Standby the LCD\n");
 139
 140                        spi_write(spi, (const u8 *)&disoff, sizeof(u16));
 141                        msleep(60);
 142                        spi_write(spi, (const u8 *)&slpin, sizeof(u16));
 143                } else if (priv->lcd_state < FB_BLANK_POWERDOWN) {
 144                        /* Do nothing, the LCD is already in standby */
 145                } else {
 146                        /* priv->lcd_state == FB_BLANK_POWERDOWN */
 147                        l4f00242t03_lcd_init(spi);
 148                        priv->lcd_state = FB_BLANK_UNBLANK;
 149                        l4f00242t03_lcd_power_set(ld, power);
 150                }
 151        } else {
 152                /* power == FB_BLANK_POWERDOWN */
 153                if (priv->lcd_state != FB_BLANK_POWERDOWN) {
 154                        /* Clear the screen before shutting down */
 155                        spi_write(spi, (const u8 *)&disoff, sizeof(u16));
 156                        msleep(60);
 157                        l4f00242t03_lcd_powerdown(spi);
 158                }
 159        }
 160
 161        priv->lcd_state = power;
 162
 163        return 0;
 164}
 165
 166static struct lcd_ops l4f_ops = {
 167        .set_power      = l4f00242t03_lcd_power_set,
 168        .get_power      = l4f00242t03_lcd_power_get,
 169};
 170
 171static int l4f00242t03_probe(struct spi_device *spi)
 172{
 173        struct l4f00242t03_priv *priv;
 174        struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev);
 175        int ret;
 176
 177        if (pdata == NULL) {
 178                dev_err(&spi->dev, "Uninitialized platform data.\n");
 179                return -EINVAL;
 180        }
 181
 182        priv = devm_kzalloc(&spi->dev, sizeof(struct l4f00242t03_priv),
 183                                GFP_KERNEL);
 184        if (priv == NULL)
 185                return -ENOMEM;
 186
 187        spi_set_drvdata(spi, priv);
 188        spi->bits_per_word = 9;
 189        spi_setup(spi);
 190
 191        priv->spi = spi;
 192
 193        ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio,
 194                        GPIOF_OUT_INIT_HIGH, "lcd l4f00242t03 reset");
 195        if (ret) {
 196                dev_err(&spi->dev,
 197                        "Unable to get the lcd l4f00242t03 reset gpio.\n");
 198                return ret;
 199        }
 200
 201        ret = devm_gpio_request_one(&spi->dev, pdata->data_enable_gpio,
 202                        GPIOF_OUT_INIT_LOW, "lcd l4f00242t03 data enable");
 203        if (ret) {
 204                dev_err(&spi->dev,
 205                        "Unable to get the lcd l4f00242t03 data en gpio.\n");
 206                return ret;
 207        }
 208
 209        priv->io_reg = devm_regulator_get(&spi->dev, "vdd");
 210        if (IS_ERR(priv->io_reg)) {
 211                dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
 212                       __func__);
 213                return PTR_ERR(priv->io_reg);
 214        }
 215
 216        priv->core_reg = devm_regulator_get(&spi->dev, "vcore");
 217        if (IS_ERR(priv->core_reg)) {
 218                dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
 219                       __func__);
 220                return PTR_ERR(priv->core_reg);
 221        }
 222
 223        priv->ld = devm_lcd_device_register(&spi->dev, "l4f00242t03", &spi->dev,
 224                                        priv, &l4f_ops);
 225        if (IS_ERR(priv->ld))
 226                return PTR_ERR(priv->ld);
 227
 228        /* Init the LCD */
 229        l4f00242t03_lcd_init(spi);
 230        priv->lcd_state = FB_BLANK_VSYNC_SUSPEND;
 231        l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_UNBLANK);
 232
 233        dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n");
 234
 235        return 0;
 236}
 237
 238static int l4f00242t03_remove(struct spi_device *spi)
 239{
 240        struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
 241
 242        l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
 243        return 0;
 244}
 245
 246static void l4f00242t03_shutdown(struct spi_device *spi)
 247{
 248        struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
 249
 250        if (priv)
 251                l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
 252
 253}
 254
 255static struct spi_driver l4f00242t03_driver = {
 256        .driver = {
 257                .name   = "l4f00242t03",
 258        },
 259        .probe          = l4f00242t03_probe,
 260        .remove         = l4f00242t03_remove,
 261        .shutdown       = l4f00242t03_shutdown,
 262};
 263
 264module_spi_driver(l4f00242t03_driver);
 265
 266MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
 267MODULE_DESCRIPTION("EPSON L4F00242T03 LCD");
 268MODULE_LICENSE("GPL v2");
 269