summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorMin-wuk Lee <mlee@nvidia.com>2013-07-19 19:21:02 +0900
committerGabby Lee <galee@nvidia.com>2013-10-13 16:32:03 -0700
commit75b600cb4f20649e94c21d1f446fc9f58ec38502 (patch)
tree710755ab2c5bcc713db7f47e760902eac08dfb5f /drivers/video
parent6f5c3ec6e53e8f364d2dd49af1e12fa4b060280f (diff)
video: backlight: pwm_bl: device tree support for pwm_bl
Add device tree support for pwm based backlight driver. Values for platform data required by pwm backlight driver are parsed from device tree properties, directly. For function pointers in platform data, separate devdata generating driver is prepared. In order to construct functions, it also parses values from different device tree node. Backlight output array to make linear backlight response are parsed in separate devdata generating driver. Bug 1240921 Change-Id: Ie2b20efa368a0caa3a8a4d316482a2153cdaadc1 Signed-off-by: Min-wuk Lee <mlee@nvidia.com> Reviewed-on: http://git-master/r/251313 (cherry picked from commit e1fa47428e164545237ba30a460308b146263ccd) Reviewed-on: http://git-master/r/289748 Reviewed-by: Gabby Lee <galee@nvidia.com> Tested-by: Gabby Lee <galee@nvidia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/backlight/Makefile6
-rw-r--r--drivers/video/backlight/of_pwm_bl.c155
-rw-r--r--drivers/video/backlight/of_pwm_bl_device_data/Makefile3
-rw-r--r--drivers/video/backlight/of_pwm_bl_device_data/tegratab_pwm_bl_dev_data.c187
-rw-r--r--drivers/video/backlight/pwm_bl.c68
5 files changed, 414 insertions, 5 deletions
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 86b8d2dcea81..610485806f16 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -27,7 +27,11 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
-obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
+ifeq ($(CONFIG_BACKLIGHT_PWM),y)
+obj-$(CONFIG_USE_OF) += of_pwm_bl_device_data/
+obj-y += pwm_bl.o
+obj-y += of_pwm_bl.o
+endif
CFLAGS_tegra_pwm_bl.o = -Werror
obj-$(CONFIG_BACKLIGHT_TEGRA_PWM) += tegra_pwm_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
diff --git a/drivers/video/backlight/of_pwm_bl.c b/drivers/video/backlight/of_pwm_bl.c
new file mode 100644
index 000000000000..f7a55e481227
--- /dev/null
+++ b/drivers/video/backlight/of_pwm_bl.c
@@ -0,0 +1,155 @@
+/*
+ * linux/drivers/video/backlight/of_pwm_bl.c
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
+
+#include <mach/latency_allowance.h>
+#include <mach/iomap.h>
+
+#include <linux/pwm_backlight.h>
+
+#ifdef CONFIG_OF
+/*#define OF_PWMBL_DEBUG 1*/
+
+#undef OF_PWMBL_LOG
+#ifdef OF_PWMBL_DEBUG
+#define OF_PWMBL_LOG(fmt, args...) pr_info("OF_PWMBL_LOG: " fmt, ## args)
+#else
+#define OF_PWMBL_LOG(fmt, args...)
+#endif
+
+struct platform_pwm_backlight_data
+ *of_pwm_bl_parse_platform_data(struct platform_device *ndev)
+{
+ struct platform_pwm_backlight_data *pdata;
+ struct platform_pwm_backlight_data *temp_pdata;
+ u32 temp;
+ bool is_charged = false;
+ unsigned int temp_dft_bri = 0;
+ unsigned int temp_dft_charge_bri = 0;
+ int pwm_gpio;
+ enum of_gpio_flags flags;
+ struct property *prop;
+ const __be32 *p;
+ u32 u;
+ int edp_stat_count = 0;
+ unsigned int *edp_states;
+ unsigned int *edp_brightness;
+ struct device_node *np = ndev->dev.of_node;
+
+ temp_pdata = (struct platform_pwm_backlight_data *)
+ ndev->dev.platform_data;
+ if (temp_pdata && temp_pdata->is_charged) {
+ OF_PWMBL_LOG("charging mode\n");
+ is_charged = true;
+ } else
+ OF_PWMBL_LOG("NOT charging mode\n");
+
+ pdata = devm_kzalloc(&ndev->dev,
+ sizeof(struct platform_pwm_backlight_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&ndev->dev, "not enough memory\n");
+ goto fail_parse;
+ }
+ if (!of_property_read_u32(np, "nvidia,pwm-id", &temp)) {
+ pdata->pwm_id = (int)temp;
+ OF_PWMBL_LOG("pwm_id %d\n", pdata->pwm_id);
+ }
+ if (!of_property_read_u32(np, "nvidia,max-brightness", &temp)) {
+ pdata->max_brightness = (unsigned int)temp;
+ OF_PWMBL_LOG("max_brightness %d\n", pdata->max_brightness);
+ }
+ if (!of_property_read_u32(np, "nvidia,dft-brightness", &temp))
+ temp_dft_bri = (unsigned int)temp;
+
+ if (!of_property_read_u32(np, "nvidia,dft-charge-brightness", &temp))
+ temp_dft_charge_bri = (unsigned int)temp;
+ if (is_charged)
+ pdata->dft_brightness = temp_dft_charge_bri;
+ else
+ pdata->dft_brightness = temp_dft_bri;
+ OF_PWMBL_LOG("dft_brightness %d\n", pdata->dft_brightness);
+
+ if (!of_property_read_u32(np, "nvidia,lth-brightness", &temp)) {
+ pdata->lth_brightness = (unsigned int)temp;
+ OF_PWMBL_LOG("lth_brightness %d\n", pdata->lth_brightness);
+ }
+ if (!of_property_read_u32(np, "nvidia,pwm-period-ns", &temp)) {
+ pdata->pwm_period_ns = (unsigned int)temp;
+ OF_PWMBL_LOG("pwm_period_ns %d\n", pdata->pwm_period_ns);
+ }
+ pwm_gpio = of_get_named_gpio_flags(np, "nvidia,pwm-gpio", 0, &flags);
+ if (pwm_gpio != 0) {
+ pdata->pwm_gpio = pwm_gpio;
+ OF_PWMBL_LOG("pwm gpio %d\n", pdata->pwm_gpio);
+ }
+
+ edp_states = &(pdata->edp_states[0]);
+ edp_brightness = &(pdata->edp_brightness[0]);
+
+ of_property_for_each_u32(np, "nvidia,edp-states", prop, p, u)
+ edp_stat_count++;
+ if (edp_stat_count > TEGRA_PWM_BL_EDP_NUM_STATES) {
+ pr_err("edp states overflow\n");
+ goto fail_parse;
+ } else {
+ of_property_for_each_u32(np, "nvidia,edp-states",
+ prop, p, u) {
+ OF_PWMBL_LOG("edp states %d\n", u);
+ *(edp_states++) = (unsigned int)u;
+ }
+ }
+ edp_stat_count = 0;
+ of_property_for_each_u32(np, "nvidia,edp-brightness", prop, p, u)
+ edp_stat_count++;
+ if (edp_stat_count > TEGRA_PWM_BL_EDP_NUM_STATES) {
+ pr_err("edp brightness overflow\n");
+ goto fail_parse;
+ } else {
+ of_property_for_each_u32(np, "nvidia,edp-brightness",
+ prop, p, u) {
+ OF_PWMBL_LOG("edp brightness %d\n", u);
+ *(edp_brightness++) = (unsigned int)u;
+ }
+ }
+ return pdata;
+fail_parse:
+ return NULL;
+}
+#else
+struct platform_pwm_backlight_data
+ *of_pwm_bl_parse_platform_data(struct platform_device *ndev)
+{
+ return NULL;
+}
+#endif
+
diff --git a/drivers/video/backlight/of_pwm_bl_device_data/Makefile b/drivers/video/backlight/of_pwm_bl_device_data/Makefile
new file mode 100644
index 000000000000..51566822c5be
--- /dev/null
+++ b/drivers/video/backlight/of_pwm_bl_device_data/Makefile
@@ -0,0 +1,3 @@
+OV_PROFILE := y
+obj-${CONFIG_MACH_TEGRATAB} += tegratab_pwm_bl_dev_data.o
+
diff --git a/drivers/video/backlight/of_pwm_bl_device_data/tegratab_pwm_bl_dev_data.c b/drivers/video/backlight/of_pwm_bl_device_data/tegratab_pwm_bl_dev_data.c
new file mode 100644
index 000000000000..00be595e7240
--- /dev/null
+++ b/drivers/video/backlight/of_pwm_bl_device_data/tegratab_pwm_bl_dev_data.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION, All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/pwm_backlight.h>
+#include <mach/dc.h>
+
+/*#define OF_PANEL_PWMBL_DEBUG 1*/
+
+#undef OF_PANEL_PWMBL_LOG
+#ifdef OF_PANEL_PWMBL_DEBUG
+#define OF_PANEL_PWMBL_LOG(fmt, args...) \
+ pr_info("OF_PANEL_PWMBL_LOG: " fmt, ## args)
+#else
+#define OF_PANEL_PWMBL_LOG(fmt, args...)
+#endif
+
+static atomic_t sd_brightness = ATOMIC_INIT(255);
+
+static struct platform_driver tegratab_pwm_bl_devdata_gen_drv;
+static struct device_node *gp_node;
+
+/* pwm bl list*/
+struct of_tegra_pwm_bl_devdata tegratab_lgd_pwm_bl;
+
+static bool tegratab_valid_bl_out;
+
+static tegra_dc_bl_output dsi_lgd_wxga_7_0_bl_output_measured = {
+ 0,
+};
+
+static int tegratab_pwm_bl_output_parse(void)
+{
+ struct property *prop;
+ const __be32 *p;
+ u32 u;
+ u8 *parse_bl_output;
+ int bl_output_cnt = 0;
+
+ parse_bl_output = &(dsi_lgd_wxga_7_0_bl_output_measured[0]);
+ of_property_for_each_u32(gp_node, "nvidia,bl-output", prop, p, u)
+ bl_output_cnt++;
+ if (bl_output_cnt > sizeof(dsi_lgd_wxga_7_0_bl_output_measured)/
+ sizeof(dsi_lgd_wxga_7_0_bl_output_measured[0])) {
+ pr_err("bl_output_cnt overflow\n");
+ return false;
+ } else {
+ of_property_for_each_u32(gp_node,
+ "nvidia,bl-output", prop, p, u) {
+ OF_PANEL_PWMBL_LOG("bl-output %d\n", u);
+ *(parse_bl_output++) = (u8)u;
+ }
+ return true;
+ }
+}
+
+static int dsi_lgd_wxga_7_0_bl_notify(struct device *unused, int brightness)
+{
+ int cur_sd_brightness = atomic_read(&sd_brightness);
+
+ /* SD brightness is a percentage */
+ brightness = (brightness * cur_sd_brightness) / 255;
+
+ if (!tegratab_valid_bl_out) {
+ pr_info("Error: invalid bl_out parsed!\n");
+ if (brightness > 255)
+ pr_info("Error: Brightness > 255!\n");
+ return brightness;
+ }
+
+ /* Apply any backlight response curve */
+ if (brightness > 255)
+ pr_info("Error: Brightness > 255!\n");
+ else
+ brightness = dsi_lgd_wxga_7_0_bl_output_measured[brightness];
+
+ return brightness;
+}
+
+static int dsi_lgd_wxga_7_0_check_fb(struct device *dev, struct fb_info *info)
+{
+ struct platform_device *disp_device;
+ disp_device = to_platform_device(bus_find_device_by_name(
+ &platform_bus_type, NULL, "tegradc.0"));
+ return info->device == &disp_device->dev;
+}
+
+static void tegratab_lgd_pwm_bl_devdata
+ (struct of_tegra_pwm_bl_devdata *pwm_bl_dev_data)
+{
+ tegratab_valid_bl_out = tegratab_pwm_bl_output_parse();
+ pwm_bl_dev_data->notify = dsi_lgd_wxga_7_0_bl_notify;
+ pwm_bl_dev_data->check_fb = dsi_lgd_wxga_7_0_check_fb;
+}
+
+static int tegra_pwm_bl_match(struct device *dev, void *data)
+{
+ struct device_node *dn = data;
+
+ return (dev->of_node == dn) ? 1 : 0;
+}
+
+struct device *tegratab_pwm_bl_devdata_to_pwm_bl(struct device_node *dn)
+{
+ struct device *dev;
+ dev = driver_find_device(&tegratab_pwm_bl_devdata_gen_drv.driver,
+ NULL, dn, tegra_pwm_bl_match);
+ if (!dev)
+ return NULL;
+ return dev;
+}
+
+static int tegratab_pwm_bl_devdata_gen_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct of_tegra_pwm_bl_devdata *pwm_bl_devdata;
+
+ gp_node = np;
+
+ pwm_bl_devdata = devm_kzalloc(dev, sizeof(*pwm_bl_devdata), GFP_KERNEL);
+ if (!pwm_bl_devdata)
+ return -ENOMEM;
+
+
+ if (of_find_compatible_node(NULL, NULL, "lgd-pwm-bl,tegratab")) {
+ tegratab_lgd_pwm_bl_devdata(&tegratab_lgd_pwm_bl);
+ memcpy(pwm_bl_devdata, &tegratab_lgd_pwm_bl,
+ sizeof(struct of_tegra_pwm_bl_devdata));
+ }
+
+ platform_set_drvdata(pdev, pwm_bl_devdata);
+ pwm_bl_devdata_set_callback(tegratab_pwm_bl_devdata_to_pwm_bl);
+ return 0;
+}
+
+static int tegratab_pwm_bl_devdata_gen_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id tegratab_pwm_bl_of_match[] = {
+ { .compatible = "lgd-pwm-bl,tegratab", },
+ { },
+};
+
+static struct platform_driver tegratab_pwm_bl_devdata_gen_drv = {
+ .probe = tegratab_pwm_bl_devdata_gen_probe,
+ .remove = tegratab_pwm_bl_devdata_gen_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "of_tegratab_pwm_bl_devdata_generate",
+ .of_match_table = tegratab_pwm_bl_of_match,
+ },
+};
+
+int __init of_tegratab_pwm_bl_devdata_init(void)
+{
+ return platform_driver_register(&tegratab_pwm_bl_devdata_gen_drv);
+}
+
+void __exit of_tegratab_pwm_bl_devdata_exit(void)
+{
+ platform_driver_unregister(&tegratab_pwm_bl_devdata_gen_drv);
+}
+
+subsys_initcall(of_tegratab_pwm_bl_devdata_init);
+module_exit(of_tegratab_pwm_bl_devdata_exit);
+MODULE_DESCRIPTION("tegratab pwm_bl devdata generate driver with device tree info");
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 10a6b9b8ef39..2e5fddc2ca8e 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -137,18 +137,68 @@ static const struct backlight_ops pwm_backlight_ops = {
.check_fb = pwm_backlight_check_fb,
};
+typedef struct device *(*tegra_pwm_bl_devdata_to_dc_CB)(struct device_node *);
+tegra_pwm_bl_devdata_to_dc_CB tegra_pwm_bl_devdata_to_pwm_bl;
+
+void pwm_bl_devdata_set_callback(struct device*(*func)
+ (struct device_node *))
+{
+ if (func != NULL)
+ tegra_pwm_bl_devdata_to_pwm_bl = func;
+}
+EXPORT_SYMBOL(pwm_bl_devdata_set_callback);
+
+struct device *pwm_bl_devdata_set_callback_run(struct device_node *dn)
+{
+ struct device *rdev = NULL;
+
+ if (tegra_pwm_bl_devdata_to_pwm_bl)
+ rdev = tegra_pwm_bl_devdata_to_pwm_bl(dn);
+
+ return rdev;
+}
+EXPORT_SYMBOL(pwm_bl_devdata_set_callback_run);
+
static int pwm_backlight_probe(struct platform_device *pdev)
{
struct backlight_properties props;
- struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
+ struct platform_pwm_backlight_data *data;
+ struct device_node *np = pdev->dev.of_node;
+ struct of_tegra_pwm_bl_devdata *pwm_bl_dev_data = NULL;
+ struct device_node *pnode = NULL;
+ struct device *pwm_bl_dev = NULL;
struct backlight_device *bl;
struct pwm_bl_data *pb;
struct edp_manager *battery_manager = NULL;
int ret;
- if (!data) {
- dev_err(&pdev->dev, "failed to find platform data\n");
- return -EINVAL;
+ if (np) {
+ data = of_pwm_bl_parse_platform_data(pdev);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to find platform data\n");
+ return -EINVAL;
+ }
+ pnode = of_parse_phandle(np, "nvidia,panel-pwm-bl", 0);
+ if (pnode)
+ pwm_bl_dev = pwm_bl_devdata_set_callback_run(pnode);
+ if (pwm_bl_dev) {
+ pwm_bl_dev_data = (struct of_tegra_pwm_bl_devdata *)
+ dev_get_drvdata(pwm_bl_dev);
+ if (pwm_bl_dev_data) {
+ data->init = pwm_bl_dev_data->init;
+ data->notify = pwm_bl_dev_data->notify;
+ data->notify_after =
+ pwm_bl_dev_data->notify_after;
+ data->exit = pwm_bl_dev_data->exit;
+ data->check_fb = pwm_bl_dev_data->check_fb;
+ }
+ }
+ } else {
+ data = pdev->dev.platform_data;
+ if (!data) {
+ dev_err(&pdev->dev, "failed to find platform data\n");
+ return -EINVAL;
+ }
}
if (data->init) {
@@ -306,6 +356,13 @@ static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend,
#endif
+#ifdef CONFIG_OF
+static struct of_device_id tegra_pwm_bl_of_match[] __devinitdata = {
+ {.compatible = "nvidia,tegra114-pwm-bl", },
+ { },
+};
+#endif
+
static struct platform_driver pwm_backlight_driver = {
.driver = {
.name = "pwm-backlight",
@@ -313,6 +370,9 @@ static struct platform_driver pwm_backlight_driver = {
#ifdef CONFIG_PM
.pm = &pwm_backlight_pm_ops,
#endif
+#ifdef CONFIG_OF
+ .of_match_table = tegra_pwm_bl_of_match,
+#endif
},
.probe = pwm_backlight_probe,
.remove = pwm_backlight_remove,