diff options
-rw-r--r-- | drivers/video/mcde/display-sony_acx424akp_dsi.c | 295 | ||||
-rw-r--r-- | include/video/mcde_display-sony_acx424akp_dsi.h | 2 |
2 files changed, 148 insertions, 149 deletions
diff --git a/drivers/video/mcde/display-sony_acx424akp_dsi.c b/drivers/video/mcde/display-sony_acx424akp_dsi.c index 3cad2b9718e..aace9ff94f2 100644 --- a/drivers/video/mcde/display-sony_acx424akp_dsi.c +++ b/drivers/video/mcde/display-sony_acx424akp_dsi.c @@ -14,10 +14,31 @@ #include <linux/delay.h> #include <linux/gpio.h> #include <linux/err.h> +#include <linux/slab.h> + +#include <linux/regulator/consumer.h> #include <video/mcde_display.h> #include <video/mcde_display-sony_acx424akp_dsi.h> +#define RESET_DELAY_MS 11 +#define RESET_LOW_DELAY_US 20 +#define SLEEP_OUT_DELAY_MS 140 +#define IO_REGU "vddi" +#define IO_REGU_MIN 1600000 +#define IO_REGU_MAX 3300000 + +struct device_info { + int reset_gpio; + struct mcde_port port; + struct regulator *regulator; +}; + +static inline struct device_info *get_drvdata(struct mcde_display_device *ddev) +{ + return (struct device_info *)dev_get_drvdata(&ddev->dev); +} + static int display_read_deviceid(struct mcde_display_device *dev, u16 *id) { struct mcde_chnl_state *chnl; @@ -58,50 +79,62 @@ out: return 0; } -static int sony_acx424akp_platform_enable(struct mcde_display_device *dev) +static int power_on(struct mcde_display_device *dev) { - struct mcde_display_sony_acx424akp_platform_data *pdata = - dev->dev.platform_data; + struct device_info *di = get_drvdata(dev); dev_dbg(&dev->dev, "%s: Reset & power on sony display\n", __func__); - if (pdata->regulator) { - if (regulator_enable(pdata->regulator) < 0) { - dev_err(&dev->dev, "%s:Failed to enable regulator\n" - , __func__); - return -EINVAL; - } - } - if (pdata->reset_gpio) - gpio_set_value(pdata->reset_gpio, pdata->reset_high); - msleep(pdata->reset_delay); /* as per sony lcd spec */ - if (pdata->reset_gpio) - gpio_set_value(pdata->reset_gpio, !pdata->reset_high); - msleep(pdata->reset_low_delay); /* as per sony lcd spec */ - if (pdata->reset_gpio) - gpio_set_value(pdata->reset_gpio, pdata->reset_high); - msleep(pdata->reset_delay); /* as per sony lcd spec */ + regulator_enable(di->regulator); + gpio_set_value_cansleep(di->reset_gpio, 0); + udelay(RESET_LOW_DELAY_US); + gpio_set_value_cansleep(di->reset_gpio, 1); + msleep(RESET_DELAY_MS); return 0; } -static int sony_acx424akp_platform_disable(struct mcde_display_device *dev) +static int power_off(struct mcde_display_device *dev) { - struct mcde_display_sony_acx424akp_platform_data *pdata = - dev->dev.platform_data; + struct device_info *di = get_drvdata(dev); dev_dbg(&dev->dev, "%s:Reset & power off sony display\n", __func__); - if (pdata->regulator) { - if (regulator_disable(pdata->regulator) < 0) { - dev_err(&dev->dev, "%s:Failed to disable regulator\n" - , __func__); - return -EINVAL; - } - } + regulator_disable(di->regulator); + return 0; } +static int display_on(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display on sony display\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_EXIT_SLEEP_MODE, + NULL, 0); + if (ret) + return ret; + msleep(SLEEP_OUT_DELAY_MS); + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_ON, + NULL, 0); +} + +static int display_off(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display off sony display\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_OFF, + NULL, 0); + if (ret) + return ret; + + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_ENTER_SLEEP_MODE, + NULL, 0); +} + static int sony_acx424akp_set_scan_mode(struct mcde_display_device *ddev, enum mcde_display_power_mode power_mode) { @@ -148,187 +181,155 @@ static int sony_acx424akp_set_power_mode(struct mcde_display_device *ddev, enum mcde_display_power_mode power_mode) { int ret = 0; - struct mcde_display_sony_acx424akp_platform_data *pdata = - ddev->dev.platform_data; dev_dbg(&ddev->dev, "%s:Set Power mode\n", __func__); /* OFF -> STANDBY */ if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && - power_mode != MCDE_DISPLAY_PM_OFF) { - - if (ddev->platform_enable) { - ret = ddev->platform_enable(ddev); - if (ret) - return ret; - } - + power_mode != MCDE_DISPLAY_PM_OFF) { + ret = power_on(ddev); + if (ret) + return ret; ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; } /* STANDBY -> ON */ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && - power_mode == MCDE_DISPLAY_PM_ON) { - - ret = mcde_dsi_dcs_write(ddev->chnl_state, - DCS_CMD_EXIT_SLEEP_MODE, NULL, 0); - if (ret) - return ret; + power_mode == MCDE_DISPLAY_PM_ON) { - msleep(pdata->sleep_out_delay); - - ret = mcde_dsi_dcs_write(ddev->chnl_state, - DCS_CMD_SET_DISPLAY_ON, NULL, 0); + ret = display_on(ddev); if (ret) return ret; - ddev->power_mode = MCDE_DISPLAY_PM_ON; - goto set_power_and_exit; } /* ON -> STANDBY */ else if (ddev->power_mode == MCDE_DISPLAY_PM_ON && - power_mode <= MCDE_DISPLAY_PM_STANDBY) { - ret = mcde_dsi_dcs_write(ddev->chnl_state, - DCS_CMD_SET_DISPLAY_OFF, NULL, 0); - if (ret) - return ret; + power_mode <= MCDE_DISPLAY_PM_STANDBY) { - ret = mcde_dsi_dcs_write(ddev->chnl_state, - DCS_CMD_ENTER_SLEEP_MODE, NULL, 0); + ret = display_off(ddev); if (ret) return ret; - ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; } - /* SLEEP -> OFF */ + /* STANDBY -> OFF */ if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && - power_mode == MCDE_DISPLAY_PM_OFF) { - if (ddev->platform_disable) { - ret = ddev->platform_disable(ddev); - if (ret) - return ret; - } + power_mode == MCDE_DISPLAY_PM_OFF) { + ret = power_off(ddev); + if (ret) + return ret; ddev->power_mode = MCDE_DISPLAY_PM_OFF; } -set_power_and_exit: mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode); - ret = sony_acx424akp_set_scan_mode(ddev, power_mode); - - return ret; + return sony_acx424akp_set_scan_mode(ddev, power_mode); } static int __devinit sony_acx424akp_probe(struct mcde_display_device *dev) { int ret = 0; - u16 id; + u16 id = 0; + struct device_info *di; + struct mcde_port *port; struct mcde_display_sony_acx424akp_platform_data *pdata = dev->dev.platform_data; - if (pdata == NULL) { - dev_err(&dev->dev, "%s:Platform data missing\n", __func__); - return -EINVAL; - } - - if (dev->port->type != MCDE_PORTTYPE_DSI) { - dev_err(&dev->dev, - "%s:Invalid port type %d\n", - __func__, dev->port->type); + if (pdata == NULL || !pdata->reset_gpio) { + dev_err(&dev->dev, "Invalid platform data\n"); return -EINVAL; } - if (!dev->platform_enable && !dev->platform_disable) { - pdata->sony_acx424akp_platform_enable = true; - if (pdata->reset_gpio) { - ret = gpio_request(pdata->reset_gpio, NULL); - if (ret) { - dev_warn(&dev->dev, - "%s:Failed to request gpio %d\n", - __func__, pdata->reset_gpio); - goto gpio_request_failed; - } - gpio_direction_output(pdata->reset_gpio, - !pdata->reset_high); - } - if (pdata->regulator_id) { - pdata->regulator = regulator_get(NULL, - pdata->regulator_id); - if (IS_ERR(pdata->regulator)) { - ret = PTR_ERR(pdata->regulator); - dev_warn(&dev->dev, - "%s:Failed to get regulator '%s'\n", - __func__, pdata->regulator_id); - pdata->regulator = NULL; - goto regulator_get_failed; - } - regulator_set_voltage(pdata->regulator, - pdata->min_supply_voltage, - pdata->max_supply_voltage); - /* - * When u-boot has display a startup screen. - * U-boot has turned on display power however the - * regulator framework does not know about that - * This is the case here, the display driver has to - * enable the regulator for the display. - */ - if (dev->power_mode == MCDE_DISPLAY_PM_STANDBY) { - ret = regulator_enable(pdata->regulator); - if (ret < 0) { - dev_err(&dev->dev, - "%s:Failed to enable regulator\n" - , __func__); - goto regulator_enable_failed; - } - } - } + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) + return -ENOMEM; + + port = dev->port; + di->reset_gpio = pdata->reset_gpio; + di->port.type = MCDE_PORTTYPE_DSI; + di->port.mode = MCDE_PORTMODE_CMD; + di->port.pixel_format = MCDE_PORTPIXFMT_DSI_24BPP; + di->port.sync_src = MCDE_SYNCSRC_BTA; + di->port.phy.dsi.num_data_lanes = 2; + di->port.link = port->link; + /* TODO: Move UI to mcde_hw.c when clk_get_rate(dsi) is done */ + di->port.phy.dsi.ui = 9; + + ret = gpio_request(di->reset_gpio, NULL); + if (WARN_ON(ret)) + goto gpio_request_failed; + + gpio_direction_output(di->reset_gpio, 1); + di->regulator = regulator_get(&dev->dev, IO_REGU); + if (IS_ERR(di->regulator)) { + ret = PTR_ERR(di->regulator); + di->regulator = NULL; + goto regulator_get_failed; } + ret = regulator_set_voltage(di->regulator, IO_REGU_MIN, IO_REGU_MAX); + if (WARN_ON(ret)) + goto regulator_voltage_failed; - /* TODO: Remove when DSI send command uses interrupts */ - dev->platform_enable = sony_acx424akp_platform_enable, - dev->platform_disable = sony_acx424akp_platform_disable, dev->set_power_mode = sony_acx424akp_set_power_mode; + dev->port = &di->port; + dev->native_x_res = 480; + dev->native_y_res = 854; + dev_set_drvdata(&dev->dev, di); + + /* + * When u-boot has display a startup screen. + * U-boot has turned on display power however the + * regulator framework does not know about that + * This is the case here, the display driver has to + * enable the regulator for the display. + */ + if (dev->power_mode == MCDE_DISPLAY_PM_STANDBY) { + (void) regulator_enable(di->regulator); + } else if (dev->power_mode == MCDE_DISPLAY_PM_OFF) { + power_on(dev); + dev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + ret = display_read_deviceid(dev, &id); + if (ret) + goto read_id_failed; switch (id) { case DISPLAY_SONY_ACX424AKP: pdata->disp_panel = DISPLAY_SONY_ACX424AKP; - dev_info(&dev->dev, "Sony ACX424AKP display (ID 0x%.4X) \ - probed\n", id); - goto out; - + dev_info(&dev->dev, + "Sony ACX424AKP display (ID 0x%.4X) probed\n", id); + break; default: pdata->disp_panel = DISPLAY_NONE; - dev_warn(&dev->dev, "Display not recognized\n"); - break; + dev_info(&dev->dev, + "Display not recognized (ID 0x%.4X) probed\n", id); + goto read_id_failed; } -regulator_enable_failed: + return 0; + +read_id_failed: +regulator_voltage_failed: + regulator_put(di->regulator); regulator_get_failed: - if (pdata->sony_acx424akp_platform_enable && pdata->reset_gpio) - gpio_free(pdata->reset_gpio); + gpio_free(di->reset_gpio); gpio_request_failed: -out: + kfree(di); return ret; } static int __devexit sony_acx424akp_remove(struct mcde_display_device *dev) { - struct mcde_display_sony_acx424akp_platform_data *pdata = - dev->dev.platform_data; + struct device_info *di = get_drvdata(dev); dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF); - if (!pdata->sony_acx424akp_platform_enable) - return 0; + regulator_put(di->regulator); + gpio_direction_input(di->reset_gpio); + gpio_free(di->reset_gpio); - if (pdata->regulator) - regulator_put(pdata->regulator); - if (pdata->reset_gpio) { - gpio_direction_input(pdata->reset_gpio); - gpio_free(pdata->reset_gpio); - } + kfree(di); return 0; } diff --git a/include/video/mcde_display-sony_acx424akp_dsi.h b/include/video/mcde_display-sony_acx424akp_dsi.h index de862a3f28b..c00c3513da3 100644 --- a/include/video/mcde_display-sony_acx424akp_dsi.h +++ b/include/video/mcde_display-sony_acx424akp_dsi.h @@ -31,8 +31,6 @@ struct mcde_display_sony_acx424akp_platform_data { enum display_panel_type disp_panel; /* display panel types */ /* Driver data */ - bool sony_acx424akp_platform_enable; - struct regulator *regulator; int max_supply_voltage; int min_supply_voltage; }; |