LCD Display with powerup sequence in device tree

cancel
Showing results for 
Search instead for 
Did you mean: 

LCD Display with powerup sequence in device tree

Jump to solution
6,201 Views
wolnet
Contributor III

Hello,

I use a LCD display that has a defined powerup sequence (switch on VCC and backlight vcc - wait 5ms send LVDS data -  wait 300 ms - switch on backlight)

Right now I use kernel 3.0.43 and added a function to set the gpio pins inside the drivers/video/mxc/ldb.c which handles my extended fsl_mxc_ldb_platform_data.

We port our system to kernel 3.10.53 and use the device tree for board configuration.

Is there an option in device tree files to handle powerup sequences for display ?

Kind regards

Wolfgang

0 Kudos
1 Solution
1,619 Views
wolnet
Contributor III

I fixed my issue by extending the ldb driver located in driver/video/mxc/ldb.c ,with parameters display-powerup@0 and  display-powerdown@0.

Here the part of the devicetree used to configure the display

&ldb {

    status = "okay";

   

    lvds-channel@0 {

        fsl,data-mapping = "spwg";

        fsl,data-width = <18>;

        crtc = "ipu1-di0";

        primary;

        status = "okay";

       

        //display powerup sequence

        display-powerup@0{

            pre_gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>,

                        <&gpio7 12 GPIO_ACTIVE_LOW>;

            pre_values = <1 1>;

            pre_delays-us = <0 40000>;

           

            init_delays-us = <200000>;

           

            post_gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;

            post_values = <1>;

            post_delays-us = <0>;

        };

        display-powerdown@0{

            pre_gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;

            pre_values = <0>;

            pre_delays-us = <0>;

           

            init_delays-us = <0>;

           

            post_gpios = <&gpio7 12 GPIO_ACTIVE_LOW>,

                        <&gpio1 14 GPIO_ACTIVE_HIGH>;

            //post_values = <0 0>;

            post_values = <0 0>;

            post_delays-us = <5000 0>;

        };

       

        display-timings {

        native-mode = <&timing0>;

        timing0: 800x600_60Hz {

            // 800x600 60Hz

            clock-frequency = <40000000>;        //pixclock [pico seconds] -> MHz = 1/(pixclock*10^-12)

            hactive = <800>;

            vactive = <600>;

            hfront-porch = <88>;    // (Blank Horizontal Active Display Term) / 2

            hback-porch = <72>;    // (Blank Horizontal Active Display Term) / 2

            hsync-len = <64>;                // (Total Horizontal Active Display Term) / DCLK [MHz]

            vback-porch = <15>;        // (Blank Vertical Active Display Term) / 2

            vfront-porch = <4>;        // (Blank Vertical Active Display Term) / 2

            vsync-len = <6>;                // (Total Vertical Active Display Term) / DCLK [MHz]

            hsync-active = <2>;                //ignored

            vsync-active = <2>;                //ignored

            enable-count = <26>;

            };

        };

    };

};

Kind regards

Wolfgang

View solution in original post

0 Kudos
8 Replies
1,620 Views
fulinux
Contributor IV

Hi, Wolfgang Netbal

is it a same problem between us. look at this thread:where to add lvds power sequence in linux-4.1.15

0 Kudos
1,620 Views
jimmychan
NXP TechSupport
NXP TechSupport

Do you mean use the GPIO pin output high or low to control the powerup sequence?

May be you can read the following for reference:

Re: usbh1 only works when booted plugged in. (mainline linux 3.17)

Re: spi more than 4 chipselects on imx6

Hope this information can help you.

0 Kudos
1,620 Views
wolnet
Contributor III

Thank you for your fast reply jimmy

I added the power setting to my ldb device but the gpio pins stay low.

How does the startup delay work ?

Starts the time when the parsing of the devicetree was started or when ldb will be parsed or when the first delay finished the second one will be started ?

My main problem is that my display doesn't show anything

I tried the hints from this thread LVDS and PWM settings on iMX6 but my display stays black.

I set the gpios by hardware to the values I need so the wrong gpio settings are not the reason for my black screen.

&ldb {

  startup-delay-us = <2>;

    gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;

    enable-active-high;

    startup-delay-us = <5000>;

    gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;

    startup-delay-us = <10000>;

   

    lvds-channel@0 {

        crtc = "ipu1-di0";

        status = "okay";

       

        display-timings {

        native-mode = <&timing0>;

        timing0: 1024x768_60Hz {

            // 1024x768 60Hz

            clock-frequency = <64900000>;

            hactive = <1024>;

            vactive = <768>;

            hfront-porch = <108 160 220>;    // (Blank Horizontal Active Display Term) / 2

            hback-porch = <108 160 220>;    // (Blank Horizontal Active Display Term) / 2

            hsync-len = <21>;                // (Total Horizontal Active Display Term) / DCLK [MHz]

            vback-porch = <3 19 40>;        // (Blank Vertical Active Display Term) / 2

            vfront-porch = <3 19 40>;        // (Blank Vertical Active Display Term) / 2

            vsync-len = <12>;                // (Total Vertical Active Display Term) / DCLK [MHz]

            hsync-active = <2>;                //ignored

            vsync-active = <2>;                //ignored

            };

        };

    };

};

Thank you

Wolfgang

0 Kudos
1,620 Views
wolnet
Contributor III

I think my problem is that the ipu is not activated,

because I have a working boardfile for kernel 3.0.43 and I read out the registers to see whats the different.

I am able to read register IPU_CONF at address 0x260_0000 where value 0x660 is set,

but when I try to read this on kernel 3.10.53 with my device tree the kernel stops working and I have to hard reset the device.

Here my whole device tree for display control

I added the powersupply part because this fix the issue in this thread LVDS and PWM settings on iMX6

&cpu0 {

    pu-supply = <&reg_pu>; /* use pu_dummy if VDDSOC share with VDDPU */

};

&gpc {

    pu-supply = <&reg_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */

};

&gpu {

    pu-supply = <&reg_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */

};

&vpu {

    pu-supply = <&reg_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */

};

/*

* Backlight

*/

&bl {

//    startup-delay-us = <300000>;

//    gpio = <&gpio2 15 GPIO_ACTIVE_HIGH>;

//    enable-active-high;

//    startup-delay-us = <700000>;

    pwms = <&pwm1 0 5000000>;

    status = "okay";

};

&pwm1 {

    status = "okay";

};

/*

* LCD

*/

/*

&mxcfb1 {

  compatible = "fsl,mxc_sdc_fb";

  disp_dev = "ldb";

  mode_str ="SIGMATEK-XGA";

  status = "okay";

};

&ldb {

  ipu_id = <0>;

  disp_id = <0>;

  ext_ref = <1>;

  mode = "sin0";

  sec_ipu_id = <1>;

  sec_disp_id = <0>;

  status = "okay";

};

If anyone has a hint this would be great.

Kind regards

Wolfgang

0 Kudos
1,620 Views
wolnet
Contributor III

I fixed my issue by extending the ldb driver located in driver/video/mxc/ldb.c ,with parameters display-powerup@0 and  display-powerdown@0.

Here the part of the devicetree used to configure the display

&ldb {

    status = "okay";

   

    lvds-channel@0 {

        fsl,data-mapping = "spwg";

        fsl,data-width = <18>;

        crtc = "ipu1-di0";

        primary;

        status = "okay";

       

        //display powerup sequence

        display-powerup@0{

            pre_gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>,

                        <&gpio7 12 GPIO_ACTIVE_LOW>;

            pre_values = <1 1>;

            pre_delays-us = <0 40000>;

           

            init_delays-us = <200000>;

           

            post_gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;

            post_values = <1>;

            post_delays-us = <0>;

        };

        display-powerdown@0{

            pre_gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;

            pre_values = <0>;

            pre_delays-us = <0>;

           

            init_delays-us = <0>;

           

            post_gpios = <&gpio7 12 GPIO_ACTIVE_LOW>,

                        <&gpio1 14 GPIO_ACTIVE_HIGH>;

            //post_values = <0 0>;

            post_values = <0 0>;

            post_delays-us = <5000 0>;

        };

       

        display-timings {

        native-mode = <&timing0>;

        timing0: 800x600_60Hz {

            // 800x600 60Hz

            clock-frequency = <40000000>;        //pixclock [pico seconds] -> MHz = 1/(pixclock*10^-12)

            hactive = <800>;

            vactive = <600>;

            hfront-porch = <88>;    // (Blank Horizontal Active Display Term) / 2

            hback-porch = <72>;    // (Blank Horizontal Active Display Term) / 2

            hsync-len = <64>;                // (Total Horizontal Active Display Term) / DCLK [MHz]

            vback-porch = <15>;        // (Blank Vertical Active Display Term) / 2

            vfront-porch = <4>;        // (Blank Vertical Active Display Term) / 2

            vsync-len = <6>;                // (Total Vertical Active Display Term) / DCLK [MHz]

            hsync-active = <2>;                //ignored

            vsync-active = <2>;                //ignored

            enable-count = <26>;

            };

        };

    };

};

Kind regards

Wolfgang

0 Kudos
1,620 Views
marioschuknecht
Contributor I

Hi Wolfgang,

I also use a LCD display and have to comply with powerup sequence. I have some questions to your code.

1. Did you sent the fix to freescale? Is your code elsewhere available?

2. Why do you have 3 gpos? First gpo to enable VCC, LVDS data can be enabled by register write and a second gpo to enable backlight. Or do you enable LVDS data via a separate gpo?

3. Is gpo for backlight-pwm not the gpo to enalbe backlight?

And what I do not understand. Everyone has to comply with the display timings. Is there no official way to fulfill the powerup sequence?

Kind regards

Mario

0 Kudos
1,620 Views
wolnet
Contributor III

Dear Mario,

1. I didn't send my patch to freescale because I thought it will only be a quick fix and there is a better/official way to handle this.

     I had to extend the ldb driver in the linux kernel and disable some warnings in the kernel, because access GPIOs directly will cause a warning in kernel      3.10.53.

2. Our display uses 3 GPIOs (VCC, VCC_ENABLE and BACKLIGHT_ENABLE)

3. In our case the backlight-pwm has an extry pin on the display and you can switch on/off the backlight using the BACKLIGHT_ENABLE pin.

If you find a better way to handle this please let me know.

Kind regards

Wolfgang

I attached you my patch, for kernel 3.10.53.

--- a/drivers/video/mxc/ldb.c

+++ b/drivers/video/mxc/ldb.c

@@ -29,8 +29,12 @@

#include <linux/platform_device.h>

#include <linux/regmap.h>

#include <linux/types.h>

+#include <linux/gpio.h>

+#include <linux/delay.h>

+#include <linux/of_gpio.h>

#include <video/of_videomode.h>

#include <video/videomode.h>

+#include <dt-bindings/gpio/gpio.h>

#include "mxc_dispdrv.h"

#define DRIVER_NAME    "ldb"

@@ -57,6 +61,47 @@

#define INVALID_BUS_REG                        (~0UL)

+

+#define PWRUPSEQ_INIT                  0

+#define PWRUPSEQ_PRE_FINISHED  1

+#define PWRUPSEQ_POST_FINISHED 2

+/**

+ * struct ldb_power_timing - config structure

+  * @gpios:            Array containing the gpios needed to control

+ *                     the powersequence

+ * @nr_gpios:          Number of gpios

+ * @startup_delay_times Array of delays between the configured gpios

+ * @nr_delays          Number of delays, should be the same like nr_gpios if not the delay is 0

+ *

+ * This structure contains powersequence configuration

+ * information that must be passed by platform code to the

+ * ldb driver, if a display is used that needs a defined powersequence.

+ */

+struct ldb_gpio_timing{

+       struct gpio *gpios;

+       int nr_gpios;

+       unsigned *values;

+       int nr_values;

+       unsigned *delay_times;

+       int nr_delays;

+};

+

+/**

+ * struct ldb_power_timing - config structure

+ * @pre_timing:                powersequence running befor lvds data will be initialised

+ * @post_timing:       powersequence running after lvds data was initialised

+ * @lvds_delay_us:     delay waiting befor LVDS data will be initialised

+ *

+ * This structure contains powersequence configuration

+ * information that must be passed by platform code to the

+ * ldb driver, if a display is used that needs a defined powersequence.

+ */

+struct ldb_power_timing{

+       struct ldb_gpio_timing pre_timing;

+       struct ldb_gpio_timing post_timing;

+       int lvds_delay_us;

+};

+

struct crtc_mux {

        enum crtc crtc;

        u32 val;

@@ -76,7 +121,12 @@ struct ldb_info {

        bool ext_bgref_cap;

        int ctrl_reg;

        int bus_mux_num;

+       int PowerState;

        const struct bus_mux *buses;

+       struct fb_info *fbi;

+       struct ldb_power_timing disp_powerup_timing;

+       struct ldb_power_timing disp_powerdown_timing;

+

};

struct ldb_data;

@@ -285,7 +335,7 @@ static const struct of_device_id ldb_dt_ids[] = {

};

MODULE_DEVICE_TABLE(of, ldb_dt_ids);

-static int ldb_init(struct mxc_dispdrv_handle *mddh,

+static int ldb_init_internal(struct mxc_dispdrv_handle *mddh,

                    struct mxc_dispdrv_setting *setting)

{

        struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);

@@ -324,6 +374,90 @@ static int ldb_init(struct mxc_dispdrv_handle *mddh,

        return 0;

}

+static inline void ldb_delay(int delay_us) {

+       if (delay_us >= 1000) {

+               mdelay(delay_us / 1000);

+               udelay(delay_us % 1000);

+       } else {

+               udelay(delay_us);

+       }

+}

+

+static void ldb_init_gpio(const struct ldb_gpio_timing *gpio_timing)

+{

+       int i;

+       char label[15];

+       for(i = 0; i < gpio_timing->nr_gpios; ++i) {

+               if(gpio_is_output(gpio_timing->gpios[i].gpio) == 0)

+               {

+                       memset(label, 0, sizeof(label));

+                       sprintf(label, "%d", gpio_timing->gpios[i].gpio);

+                       gpio_request(gpio_timing->gpios[i].gpio, label);

+

+                       if(i < gpio_timing->nr_values) {

+                               int value = gpio_timing->values[i];

+                               //Invert value if pin is ACTIVE_LOW

+                               if(gpio_timing->gpios[i].flags & GPIO_ACTIVE_LOW) {

+                                       value = ((~gpio_timing->values[i]) & 0x01);

+                               }

+                               //Initvalue is set the inverse of value

+                               gpio_direction_output(gpio_timing->gpios[i].gpio, ~value);

+                       } else {

+                               gpio_direction_output(gpio_timing->gpios[i].gpio, 0);

+                       }

+               }

+       }

+}

+

+static void ldb_gpio_timing(const struct ldb_gpio_timing *gpio_timing)

+{

+       int i;

+       for(i = 0; i < gpio_timing->nr_gpios; ++i) {

+               if(i < gpio_timing->nr_values) {

+                       int value = gpio_timing->values[i];

+                       //Invert value if pin is ACTIVE_LOW

+                       if(gpio_timing->gpios[i].flags & GPIO_ACTIVE_LOW) {

+                               value = ((~gpio_timing->values[i]) & 0x01);

+                       }

+                       gpio_set_value(gpio_timing->gpios[i].gpio, value);

+               } else {

+                       gpio_set_value(gpio_timing->gpios[i].gpio, 0);

+               }

+

+               if(i < gpio_timing->nr_delays

+               && gpio_timing->delay_times[i] > 0) {

+                       ldb_delay(gpio_timing->delay_times[i]);

+               }

+       }

+}

+

+static int ldb_init(struct mxc_dispdrv_handle *mddh,

+                   struct mxc_dispdrv_setting *setting)

+{

+       struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);

+       struct device *dev = ldb->dev;

+       const struct of_device_id *of_id = of_match_device(ldb_dt_ids, dev);

+       struct ldb_info *ldb_info =     (struct ldb_info *)of_id->data;

+       int ret;

+

+       //Init GPIOs

+       ldb_init_gpio(&ldb_info->disp_powerup_timing.pre_timing);

+       ldb_init_gpio(&ldb_info->disp_powerup_timing.post_timing);

+       ldb_init_gpio(&ldb_info->disp_powerdown_timing.pre_timing);

+       ldb_init_gpio(&ldb_info->disp_powerdown_timing.post_timing);

+

+       //Set gpios needed befor LVDS init

+       ldb_gpio_timing(&ldb_info->disp_powerup_timing.pre_timing);

+

+       //init lvds data, the lvds lines will be activated by ldb_enable()

+       ret = ldb_init_internal(mddh, setting);

+

+       //Set PowerState to PWRUPSEQ_PRE_FINISHED because ldb_enable switches the post_powerup gpios

+       ldb_info->PowerState = PWRUPSEQ_PRE_FINISHED;

+

+       return ret;

+}

+

static int get_di_clk_id(struct ldb_chan chan, int *id)

{

        struct ldb_data *ldb = chan.ldb;

@@ -484,6 +618,8 @@ static int ldb_enable(struct mxc_dispdrv_handle *mddh,

        struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);

        struct ldb_chan chan;

        struct device *dev = ldb->dev;

+       const struct of_device_id *of_id = of_match_device(ldb_dt_ids, dev);

+       struct ldb_info *ldb_info =     (struct ldb_info *)of_id->data;

        struct bus_mux bus_mux;

        int ret = 0, id = 0, chno, other_chno;

@@ -523,6 +659,19 @@ static int ldb_enable(struct mxc_dispdrv_handle *mddh,

        }

        regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ctrl);

+

+       if(ldb_info->PowerState == PWRUPSEQ_PRE_FINISHED) {

+               ldb_info->fbi = fbi;

+

+               //Wait after LVDS init

+               ldb_delay(ldb_info->disp_powerup_timing.lvds_delay_us);

+

+               //Set gpios needed after LVDS init

+               ldb_gpio_timing(&ldb_info->disp_powerup_timing.post_timing);

+

+               ldb_info->PowerState = PWRUPSEQ_POST_FINISHED;

+       }

+

        return 0;

}

@@ -549,9 +698,34 @@ static void ldb_disable(struct mxc_dispdrv_handle *mddh,

        return;

}

+static void ldb_deinit(struct mxc_dispdrv_handle *mddh)

+{

+       struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);

+       struct device *dev = ldb->dev;

+       const struct of_device_id *of_id = of_match_device(ldb_dt_ids, dev);

+       struct ldb_info *ldb_info =     (struct ldb_info *)of_id->data;

+       int ret;

+       ret = 0;

+

+       //Set gpios needed befor disable LVDS data

+       ldb_gpio_timing(&ldb_info->disp_powerdown_timing.pre_timing);

+

+       //deactivate lvds data

+       if(mddh != NULL && ldb_info->fbi != NULL) {

+               ldb_disable(mddh, ldb_info->fbi);

+       }

+

+       //Set gpios needed after LVDS disabled

+       ldb_gpio_timing(&ldb_info->disp_powerdown_timing.post_timing);

+

+       //Set powerup sequence t

+       ldb_info->PowerState = PWRUPSEQ_INIT;

+}

+

static struct mxc_dispdrv_driver ldb_drv = {

        .name           = DRIVER_NAME,

        .init           = ldb_init,

+       .deinit         = ldb_deinit,

        .setup          = ldb_setup,

        .enable         = ldb_enable,

        .disable        = ldb_disable

@@ -663,7 +837,7 @@ static bool is_valid_crtc(struct ldb_data *ldb, enum crtc crtc,

        return false;

}

-static int ldb_probe(struct platform_device *pdev)

+static int ldb_probe_internal(struct platform_device *pdev)

{

        struct device *dev = &pdev->dev;

        const struct of_device_id *of_id =

@@ -864,12 +1038,157 @@ static int ldb_probe(struct platform_device *pdev)

static int ldb_remove(struct platform_device *pdev)

{

        struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);

+       struct device *dev = &pdev->dev;

+       const struct of_device_id *of_id = of_match_device(ldb_dt_ids, dev);

+       const struct ldb_info *ldb_info = (const struct ldb_info *)of_id->data;

        mxc_dispdrv_puthandle(ldb->mddh);

        mxc_dispdrv_unregister(ldb->mddh);

+

+       //Cleanup memory

+       kfree(ldb_info->disp_powerup_timing.pre_timing.gpios);

+       kfree(ldb_info->disp_powerup_timing.pre_timing.delay_times);

+       kfree(ldb_info->disp_powerup_timing.pre_timing.values);

+       kfree(ldb_info->disp_powerup_timing.post_timing.gpios);

+       kfree(ldb_info->disp_powerup_timing.post_timing.delay_times);

+       kfree(ldb_info->disp_powerup_timing.post_timing.values);

+       kfree(ldb_info->disp_powerdown_timing.pre_timing.gpios);

+       kfree(ldb_info->disp_powerdown_timing.pre_timing.delay_times);

+       kfree(ldb_info->disp_powerdown_timing.pre_timing.values);

+       kfree(ldb_info->disp_powerdown_timing.post_timing.gpios);

+       kfree(ldb_info->disp_powerdown_timing.post_timing.delay_times);

+       kfree(ldb_info->disp_powerdown_timing.post_timing.values);

        return 0;

}

+static int ldb_parse_powertiming(struct platform_device *pdev, struct device_node *np, struct ldb_power_timing* ldb_power_timing)

+{

+       int gpio, length, i;

+       enum of_gpio_flags flags;

+       struct property *prop;

+

+       //Parse pre_timing

+       //Parse gpios

+       ldb_power_timing->pre_timing.nr_gpios = of_gpio_named_count(np, "pre_gpios");

+       ldb_power_timing->pre_timing.gpios = devm_kzalloc(&pdev->dev,

+                                       sizeof(struct gpio) * ldb_power_timing->pre_timing.nr_gpios,

+                                       GFP_KERNEL);

+       if (!ldb_power_timing->pre_timing.gpios)

+               return -ENOMEM;

+

+       for (i = 0; i < ldb_power_timing->pre_timing.nr_gpios; i++) {

+                       gpio = of_get_named_gpio_flags(np, "pre_gpios", i, &flags);

+                       if (gpio < 0)

+                               break;

+                       ldb_power_timing->pre_timing.gpios[i].gpio = gpio;

+                       ldb_power_timing->pre_timing.gpios[i].flags = flags;

+       }

+

+       //Parse values

+       prop = of_find_property(np, "pre_values", &length);

+       if (prop) {

+               ldb_power_timing->pre_timing.nr_values = length / sizeof(u32);

+

+               ldb_power_timing->pre_timing.values = devm_kzalloc(&pdev->dev,

+                                                       sizeof(u32) * ldb_power_timing->pre_timing.nr_values,

+                                                       GFP_KERNEL);

+               if (!ldb_power_timing->pre_timing.values)

+                       return -ENOMEM;

+

+               of_property_read_u32_array(np, "pre_values", ldb_power_timing->pre_timing.values, ldb_power_timing->pre_timing.nr_values);

+       }

+

+       //Parse delay times

+       prop = of_find_property(np, "pre_delays-us", &length);

+       if (prop) {

+               ldb_power_timing->pre_timing.nr_delays = length / sizeof(u32);

+

+               ldb_power_timing->pre_timing.delay_times = devm_kzalloc(&pdev->dev,

+                                                       sizeof(u32) * ldb_power_timing->pre_timing.nr_delays,

+                                                       GFP_KERNEL);

+               if (!ldb_power_timing->pre_timing.delay_times)

+                       return -ENOMEM;

+

+               of_property_read_u32_array(np, "pre_delays-us", ldb_power_timing->pre_timing.delay_times, ldb_power_timing->pre_timing.nr_delays);

+       }

+

+       //Parse LVDS delay

+       of_property_read_u32(np, "init_delays-us", &ldb_power_timing->lvds_delay_us);

+

+       //Parse post_timing

+       //Parse gpios

+       ldb_power_timing->post_timing.nr_gpios = of_gpio_named_count(np, "post_gpios");

+       ldb_power_timing->post_timing.gpios = devm_kzalloc(&pdev->dev,

+                                       sizeof(struct gpio) * ldb_power_timing->post_timing.nr_gpios,

+                                       GFP_KERNEL);

+       if (!ldb_power_timing->post_timing.gpios)

+               return -ENOMEM;

+

+       for (i = 0; i < ldb_power_timing->post_timing.nr_gpios; i++) {

+               gpio = of_get_named_gpio_flags(np, "post_gpios", i, &flags);

+               if (gpio < 0)

+                       break;

+               ldb_power_timing->post_timing.gpios[i].gpio = gpio;

+               ldb_power_timing->post_timing.gpios[i].flags = flags;

+       }

+

+       //Parse values

+       prop = of_find_property(np, "post_values", &length);

+       if (prop) {

+               ldb_power_timing->post_timing.nr_values = length / sizeof(u32);

+

+               ldb_power_timing->post_timing.values = devm_kzalloc(&pdev->dev,

+                                                       sizeof(u32) * ldb_power_timing->post_timing.nr_values,

+                                                       GFP_KERNEL);

+               if (!ldb_power_timing->post_timing.values)

+                       return -ENOMEM;

+

+               of_property_read_u32_array(np, "post_values", ldb_power_timing->post_timing.values, ldb_power_timing->post_timing.nr_values);

+       }

+       //Parse delay times

+       prop = of_find_property(np, "post_delays-us", &length);

+       if (prop) {

+               ldb_power_timing->post_timing.nr_delays = length / sizeof(u32);

+

+               ldb_power_timing->post_timing.delay_times = devm_kzalloc(&pdev->dev,

+                                                       sizeof(u32) * ldb_power_timing->post_timing.nr_delays,

+                                                       GFP_KERNEL);

+               if (!ldb_power_timing->post_timing.delay_times)

+                       return -ENOMEM;

+

+               of_property_read_u32_array(np, "post_delays-us", ldb_power_timing->post_timing.delay_times, ldb_power_timing->post_timing.nr_delays);

+       }

+

+       return 0;

+}

+

+static int ldb_probe(struct platform_device *pdev)

+{

+       struct device *dev = &pdev->dev;

+       const struct of_device_id *of_id = of_match_device(ldb_dt_ids, dev);

+       struct ldb_info *ldb_info =     (struct ldb_info *)of_id->data;

+       struct device_node *np = dev->of_node, *child, *powerseq;

+       int ret;

+       ret = 0;

+

+       //Get display power sequence

+       for_each_child_of_node(np, child) {

+               powerseq = of_get_child_by_name(child, "display-powerup");

+               if(powerseq != NULL) {

+                       ret = ldb_parse_powertiming(pdev, powerseq, &ldb_info->disp_powerup_timing);

+               }

+

+               powerseq = of_get_child_by_name(child, "display-powerdown");

+               if(powerseq != NULL) {

+                       ret = ldb_parse_powertiming(pdev, powerseq, &ldb_info->disp_powerdown_timing);

+               }

+       }

+

+       ret = ldb_probe_internal(pdev);

+

+       return ret;

+}

+

static struct platform_driver ldb_driver = {

        .driver = {

                .name = DRIVER_NAME,

--- a/drivers/video/mxc/mxc_dispdrv.c

+++ b/drivers/video/mxc/mxc_dispdrv.c

@@ -50,6 +50,8 @@ struct mxc_dispdrv_entry {

        struct list_head list;

};

+static struct mxc_dispdrv_entry *g_dispdrv_handle = NULL;

+

struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv)

{

        struct mxc_dispdrv_entry *new;

@@ -77,6 +79,9 @@ int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle)

        if (entry) {

                mutex_lock(&dispdrv_lock);

+               if(entry->drv->deinit) {

+                       entry->drv->deinit(handle);

+               }

                list_del(&entry->list);

                mutex_unlock(&dispdrv_lock);

                kfree(entry);

@@ -86,6 +91,15 @@ int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle)

}

EXPORT_SYMBOL_GPL(mxc_dispdrv_unregister);

+int mxc_dispdrv_powerfail(void)

+{

+       int ret = 0;

+       ret = mxc_dispdrv_unregister((struct mxc_dispdrv_handle *)g_dispdrv_handle);

+       g_dispdrv_handle = NULL;

+       return ret;

+}

+EXPORT_SYMBOL_GPL(mxc_dispdrv_powerfail);

+

struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name,

        struct mxc_dispdrv_setting *setting)

{

@@ -99,6 +113,7 @@ struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name,

                                entry, setting);

                        if (ret >= 0) {

                                entry->active = true;

+                               g_dispdrv_handle = entry;

                                found = 1;

                                break;

                        }

--- a/drivers/video/mxc/mxc_dispdrv.h

+++ b/drivers/video/mxc/mxc_dispdrv.h

@@ -44,6 +44,7 @@ struct mxc_dispdrv_driver {

struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv);

int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle);

+int mxc_dispdrv_powerfail(void);

struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name,

        struct mxc_dispdrv_setting *setting);

void mxc_dispdrv_puthandle(struct mxc_dispdrv_handle *handle);

0 Kudos
1,620 Views
xoduddk123
Contributor I

Hi wolnet

I am interested in this patch.

I am applying your patch.
I get the following error during compilation.

drivers/video/mxc/ldb.c: In function ‘ldb_init_gpio’:
drivers/video/mxc/ldb.c:390:3: error: implicit declaration of function ‘gpio_is_output’ [-Werror=implicit-function-declaration]
cc1: some warnings being treated as errors
scripts/Makefile.build:308: recipe for target 'drivers/video/mxc/ldb.o' failed
make[3]: *** [drivers/video/mxc/ldb.o] Error 1

I could not find gpio_is_output().
Can you share something about gpio_is_output()?

I'm sorry I do not have enough English. :)
Thank you.

Kind regards
Kwon

0 Kudos