video: backlight: add tegra-dsi-backlight driver
Roger Hsieh [Tue, 11 Mar 2014 15:02:39 +0000 (23:02 +0800)]
Some DSI panels require changing backlight intensity through DSI
command. Create a backlight driver hook to Tegra DSI to achieve
these panels.

Bug 1453606

Change-Id: I1c7466c01cde101e8e8346cb27371d35ff48ed58
Reviewed-on: http://git-master/r/380396
(cherry picked from commit 8c5027c7a3c9b6f3d94e85b22cec0351439c03ad)
Signed-off-by: Roger Hsieh <rhsieh@nvidia.com>
Reviewed-on: http://git-master/r/407436
Reviewed-by: Riham Haidar <rhaidar@nvidia.com>
Tested-by: Riham Haidar <rhaidar@nvidia.com>

drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/tegra_dsi_bl.c [new file with mode: 0644]
drivers/video/tegra/dc/dsi.c
drivers/video/tegra/dc/dsi.h
include/linux/tegra_dsi_backlight.h [new file with mode: 0644]

index d071ffa..e48c78d 100644 (file)
@@ -275,6 +275,16 @@ config BACKLIGHT_TEGRA_PWM
          If you have a pwm backlight adjustable by the DC PM0 or PM1 signal
          control on tegra, say Y to enable this driver.
 
+config BACKLIGHT_TEGRA_DSI
+       bool "Tegra DSI based Backlight Driver"
+       depends on TEGRA_DC
+       depends on TEGRA_DSI
+       help
+         Enable support for Tegra DSI backlight driver. If you have a
+         backlight adjustable by sending DSI command for DSI panel, say Y
+         to enable this driver. Providing backlight control sequence by
+         following the format of Tegra DSI driver is also required.
+
 config BACKLIGHT_DA903X
        tristate "Backlight Driver for DA9030/DA9034 using WLED"
        depends on PMIC_DA903X
index 91ec9c6..c3d4b54 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_BACKLIGHT_PWM)           += pwm_bl.o
 obj-$(CONFIG_BACKLIGHT_SAHARA)         += kb3886_bl.o
 CFLAGS_tegra_pwm_bl.o  = -Werror
 obj-$(CONFIG_BACKLIGHT_TEGRA_PWM)      += tegra_pwm_bl.o
+obj-$(CONFIG_BACKLIGHT_TEGRA_DSI)      += tegra_dsi_bl.o
 obj-$(CONFIG_BACKLIGHT_TOSA)           += tosa_bl.o
 obj-$(CONFIG_BACKLIGHT_TPS65217)       += tps65217_bl.o
 obj-$(CONFIG_BACKLIGHT_WM831X)         += wm831x_bl.o
diff --git a/drivers/video/backlight/tegra_dsi_bl.c b/drivers/video/backlight/tegra_dsi_bl.c
new file mode 100644 (file)
index 0000000..2b57269
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/tegra_dsi_backlight.h>
+#include <linux/regmap.h>
+#include <linux/edp.h>
+#include <mach/dc.h>
+#include "../tegra/dc/dsi.h"
+
+struct tegra_dsi_bl_data {
+       struct device           *dev;
+       struct tegra_dsi_cmd    *dsi_backlight_cmd;
+       u32 n_backlight_cmd;
+       int which_dc;
+       int (*notify)(struct device *dev, int brightness);
+       int (*check_fb)(struct device *dev, struct fb_info *info);
+};
+
+static int send_backlight_cmd(struct tegra_dsi_bl_data *tbl, int brightness)
+{
+       int err = 0;
+       struct tegra_dc *dc = tegra_dc_get_dc(tbl->which_dc);
+       struct tegra_dc_dsi_data *dsi = dc->out_data;
+       struct tegra_dsi_cmd *cur_cmd;
+
+       if (tbl->dsi_backlight_cmd)
+               cur_cmd = tbl->dsi_backlight_cmd;
+       else
+               return -EINVAL;
+
+       mutex_lock(&dsi->lock);
+
+       cur_cmd->sp_len_dly.sp.data1 = brightness;
+       err = tegra_dsi_send_panel_cmd(dc, dsi,
+                       tbl->dsi_backlight_cmd,
+                       tbl->n_backlight_cmd);
+
+       if (err < 0)
+               goto fail;
+
+fail:
+       mutex_unlock(&dsi->lock);
+
+       return err;
+}
+
+static int tegra_dsi_backlight_update_status(struct backlight_device *bl)
+{
+       struct tegra_dsi_bl_data *tbl = dev_get_drvdata(&bl->dev);
+       int brightness = bl->props.brightness;
+
+       if (tbl)
+               return send_backlight_cmd(tbl, brightness);
+       else
+               return dev_err(&bl->dev,
+                               "tegra display controller not available\n");
+}
+
+static int tegra_dsi_backlight_get_brightness(struct backlight_device *bl)
+{
+       return bl->props.brightness;
+}
+
+static const struct backlight_ops tegra_dsi_backlight_ops = {
+       .update_status  = tegra_dsi_backlight_update_status,
+       .get_brightness = tegra_dsi_backlight_get_brightness,
+};
+
+static int tegra_dsi_bl_probe(struct platform_device *pdev)
+{
+       struct backlight_device *bl;
+       struct backlight_properties props;
+       struct tegra_dsi_bl_platform_data *data;
+       struct tegra_dsi_bl_data *tbl;
+       int ret;
+
+       data = pdev->dev.platform_data;
+       if (!data) {
+               dev_err(&pdev->dev, "failed to find platform data\n");
+               return -EINVAL;
+       }
+
+       tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
+       if (!tbl)
+               ret = -ENOMEM;
+
+       tbl->dev = &pdev->dev;
+       tbl->which_dc = data->which_dc;
+       tbl->check_fb = data->check_fb;
+       tbl->notify = data->notify;
+       tbl->dsi_backlight_cmd = data->dsi_backlight_cmd;
+       tbl->n_backlight_cmd = data->n_backlight_cmd;
+
+       props.type = BACKLIGHT_RAW;
+       props.max_brightness = 255;
+       bl = backlight_device_register(dev_name(&pdev->dev), tbl->dev, tbl,
+                                      &tegra_dsi_backlight_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               ret = PTR_ERR(bl);
+       }
+
+       bl->props.brightness = data->dft_brightness;
+       platform_set_drvdata(pdev, bl);
+
+       return 0;
+}
+
+static int tegra_dsi_bl_remove(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct tegra_dsi_bl_data *tbl = dev_get_drvdata(&bl->dev);
+
+       backlight_device_unregister(bl);
+       kfree(tbl);
+
+       return 0;
+}
+
+static struct platform_driver tegra_dsi_bl_driver = {
+       .driver = {
+               .name   = "tegra-dsi-backlight",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = tegra_dsi_bl_probe,
+       .remove = tegra_dsi_bl_remove,
+};
+module_platform_driver(tegra_dsi_bl_driver);
+
+static int __init tegra_dsi_bl_init(void)
+{
+       return platform_driver_register(&tegra_dsi_bl_driver);
+}
+late_initcall(tegra_dsi_bl_init);
+
+static void __exit tegra_dsi_bl_exit(void)
+{
+       platform_driver_unregister(&tegra_dsi_bl_driver);
+}
+module_exit(tegra_dsi_bl_exit);
+
+MODULE_DESCRIPTION("Tegra DSI Backlight Driver");
+MODULE_LICENSE("GPL");
index 2accc81..3668768 100644 (file)
@@ -3102,7 +3102,7 @@ int tegra_dsi_end_host_cmd_v_blank_video(struct tegra_dc *dc,
 }
 EXPORT_SYMBOL(tegra_dsi_end_host_cmd_v_blank_video);
 
-static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc,
+int tegra_dsi_send_panel_cmd(struct tegra_dc *dc,
                                        struct tegra_dc_dsi_data *dsi,
                                        struct tegra_dsi_cmd *cmd,
                                        u32 n_cmd)
index cf977ae..3433573 100644 (file)
@@ -18,6 +18,7 @@
 #define __DRIVERS_VIDEO_TEGRA_DC_DSI_H__
 
 #define BOARD_P1761   0x06E1
+#include "dc_priv_defs.h"
 
 /* Defines the DSI phy timing parameters */
 struct dsi_phy_timing_inclk {
@@ -472,6 +473,11 @@ void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data *dsi);
 int tegra_dsi_write_data(struct tegra_dc *dc,
                        struct tegra_dc_dsi_data *dsi,
                        struct tegra_dsi_cmd *cmd, u8 delay_ms);
+int tegra_dsi_send_panel_cmd(struct tegra_dc *dc,
+                                       struct tegra_dc_dsi_data *dsi,
+                                       struct tegra_dsi_cmd *cmd,
+                                       u32 n_cmd);
+
 
 static inline void *tegra_dsi_get_outdata(struct tegra_dc_dsi_data *dsi)
 {
diff --git a/include/linux/tegra_dsi_backlight.h b/include/linux/tegra_dsi_backlight.h
new file mode 100644 (file)
index 0000000..858765a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#ifndef __LINUX_TEGRA_DSI_BACKLIGHT_H
+#define __LINUX_TEGRA_DSI_BACKLIGHT_H
+
+#include <linux/backlight.h>
+
+struct tegra_dsi_bl_platform_data {
+       struct tegra_dsi_cmd    *dsi_backlight_cmd;
+       u32             n_backlight_cmd;
+       unsigned int dft_brightness;
+       int which_dc;
+       int (*notify)(struct device *dev, int brightness);
+       int (*check_fb)(struct device *dev, struct fb_info *info);
+};
+
+#endif
+