diff options
| author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2013-05-24 07:18:30 -0400 |
|---|---|---|
| committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2013-06-17 07:16:03 -0400 |
| commit | 2773fefbd764646a3dba3349d4848d90d85a127d (patch) | |
| tree | e4e5891dce17c0f8a2457c6ca2c4f2e3a1ba6928 | |
| parent | deb16df884966570ebe6197feecab100436414e5 (diff) | |
OMAPDSS: Add new TFP410 Encoder driver
Add TFP410 DPI-to-DVI Encoder driver which uses the new DSS device
model and DSS ops.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
| -rw-r--r-- | drivers/video/omap2/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/video/omap2/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/omap2/displays-new/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/video/omap2/displays-new/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/omap2/displays-new/encoder-tfp410.c | 267 | ||||
| -rw-r--r-- | include/video/omap-panel-data.h | 13 |
6 files changed, 292 insertions, 0 deletions
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig index b07b2b042e7e..56cad0f5386c 100644 --- a/drivers/video/omap2/Kconfig +++ b/drivers/video/omap2/Kconfig | |||
| @@ -6,5 +6,6 @@ if ARCH_OMAP2PLUS | |||
| 6 | source "drivers/video/omap2/dss/Kconfig" | 6 | source "drivers/video/omap2/dss/Kconfig" |
| 7 | source "drivers/video/omap2/omapfb/Kconfig" | 7 | source "drivers/video/omap2/omapfb/Kconfig" |
| 8 | source "drivers/video/omap2/displays/Kconfig" | 8 | source "drivers/video/omap2/displays/Kconfig" |
| 9 | source "drivers/video/omap2/displays-new/Kconfig" | ||
| 9 | 10 | ||
| 10 | endif | 11 | endif |
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile index 296e5c5281c5..86873c2fbb27 100644 --- a/drivers/video/omap2/Makefile +++ b/drivers/video/omap2/Makefile | |||
| @@ -2,4 +2,5 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o | |||
| 2 | 2 | ||
| 3 | obj-$(CONFIG_OMAP2_DSS) += dss/ | 3 | obj-$(CONFIG_OMAP2_DSS) += dss/ |
| 4 | obj-y += displays/ | 4 | obj-y += displays/ |
| 5 | obj-y += displays-new/ | ||
| 5 | obj-$(CONFIG_FB_OMAP2) += omapfb/ | 6 | obj-$(CONFIG_FB_OMAP2) += omapfb/ |
diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig new file mode 100644 index 000000000000..92c232498fcc --- /dev/null +++ b/drivers/video/omap2/displays-new/Kconfig | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | menu "OMAP Display Device Drivers" | ||
| 2 | depends on OMAP2_DSS | ||
| 3 | |||
| 4 | config DISPLAY_ENCODER_TFP410 | ||
| 5 | tristate "TFP410 DPI to DVI Encoder" | ||
| 6 | help | ||
| 7 | Driver for TFP410 DPI to DVI encoder. | ||
| 8 | |||
| 9 | endmenu | ||
diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile new file mode 100644 index 000000000000..b0d34572ec7c --- /dev/null +++ b/drivers/video/omap2/displays-new/Makefile | |||
| @@ -0,0 +1 @@ | |||
| obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o | |||
diff --git a/drivers/video/omap2/displays-new/encoder-tfp410.c b/drivers/video/omap2/displays-new/encoder-tfp410.c new file mode 100644 index 000000000000..a04f65856d6b --- /dev/null +++ b/drivers/video/omap2/displays-new/encoder-tfp410.c | |||
| @@ -0,0 +1,267 @@ | |||
| 1 | /* | ||
| 2 | * TFP410 DPI-to-DVI encoder driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Texas Instruments | ||
| 5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License version 2 as published by | ||
| 9 | * the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/gpio.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | |||
| 17 | #include <video/omapdss.h> | ||
| 18 | #include <video/omap-panel-data.h> | ||
| 19 | |||
| 20 | struct panel_drv_data { | ||
| 21 | struct omap_dss_device dssdev; | ||
| 22 | struct omap_dss_device *in; | ||
| 23 | |||
| 24 | int pd_gpio; | ||
| 25 | int data_lines; | ||
| 26 | |||
| 27 | struct omap_video_timings timings; | ||
| 28 | }; | ||
| 29 | |||
| 30 | #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) | ||
| 31 | |||
| 32 | static int tfp410_connect(struct omap_dss_device *dssdev, | ||
| 33 | struct omap_dss_device *dst) | ||
| 34 | { | ||
| 35 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 36 | struct omap_dss_device *in = ddata->in; | ||
| 37 | int r; | ||
| 38 | |||
| 39 | if (omapdss_device_is_connected(dssdev)) | ||
| 40 | return -EBUSY; | ||
| 41 | |||
| 42 | r = in->ops.dpi->connect(in, dssdev); | ||
| 43 | if (r) | ||
| 44 | return r; | ||
| 45 | |||
| 46 | dst->output = dssdev; | ||
| 47 | dssdev->device = dst; | ||
| 48 | |||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | static void tfp410_disconnect(struct omap_dss_device *dssdev, | ||
| 53 | struct omap_dss_device *dst) | ||
| 54 | { | ||
| 55 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 56 | struct omap_dss_device *in = ddata->in; | ||
| 57 | |||
| 58 | WARN_ON(!omapdss_device_is_connected(dssdev)); | ||
| 59 | if (!omapdss_device_is_connected(dssdev)) | ||
| 60 | return; | ||
| 61 | |||
| 62 | WARN_ON(dst != dssdev->device); | ||
| 63 | if (dst != dssdev->device) | ||
| 64 | return; | ||
| 65 | |||
| 66 | dst->output = NULL; | ||
| 67 | dssdev->device = NULL; | ||
| 68 | |||
| 69 | in->ops.dpi->disconnect(in, &ddata->dssdev); | ||
| 70 | } | ||
| 71 | |||
| 72 | static int tfp410_enable(struct omap_dss_device *dssdev) | ||
| 73 | { | ||
| 74 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 75 | struct omap_dss_device *in = ddata->in; | ||
| 76 | int r; | ||
| 77 | |||
| 78 | if (!omapdss_device_is_connected(dssdev)) | ||
| 79 | return -ENODEV; | ||
| 80 | |||
| 81 | if (omapdss_device_is_enabled(dssdev)) | ||
| 82 | return 0; | ||
| 83 | |||
| 84 | in->ops.dpi->set_timings(in, &ddata->timings); | ||
| 85 | in->ops.dpi->set_data_lines(in, ddata->data_lines); | ||
| 86 | |||
| 87 | r = in->ops.dpi->enable(in); | ||
| 88 | if (r) | ||
| 89 | return r; | ||
| 90 | |||
| 91 | if (gpio_is_valid(ddata->pd_gpio)) | ||
| 92 | gpio_set_value_cansleep(ddata->pd_gpio, 1); | ||
| 93 | |||
| 94 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static void tfp410_disable(struct omap_dss_device *dssdev) | ||
| 100 | { | ||
| 101 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 102 | struct omap_dss_device *in = ddata->in; | ||
| 103 | |||
| 104 | if (!omapdss_device_is_enabled(dssdev)) | ||
| 105 | return; | ||
| 106 | |||
| 107 | if (gpio_is_valid(ddata->pd_gpio)) | ||
| 108 | gpio_set_value_cansleep(ddata->pd_gpio, 0); | ||
| 109 | |||
| 110 | in->ops.dpi->disable(in); | ||
| 111 | |||
| 112 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
| 113 | } | ||
| 114 | |||
| 115 | static void tfp410_set_timings(struct omap_dss_device *dssdev, | ||
| 116 | struct omap_video_timings *timings) | ||
| 117 | { | ||
| 118 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 119 | struct omap_dss_device *in = ddata->in; | ||
| 120 | |||
| 121 | ddata->timings = *timings; | ||
| 122 | dssdev->panel.timings = *timings; | ||
| 123 | |||
| 124 | in->ops.dpi->set_timings(in, timings); | ||
| 125 | } | ||
| 126 | |||
| 127 | static void tfp410_get_timings(struct omap_dss_device *dssdev, | ||
| 128 | struct omap_video_timings *timings) | ||
| 129 | { | ||
| 130 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 131 | |||
| 132 | *timings = ddata->timings; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int tfp410_check_timings(struct omap_dss_device *dssdev, | ||
| 136 | struct omap_video_timings *timings) | ||
| 137 | { | ||
| 138 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 139 | struct omap_dss_device *in = ddata->in; | ||
| 140 | |||
| 141 | return in->ops.dpi->check_timings(in, timings); | ||
| 142 | } | ||
| 143 | |||
| 144 | static const struct omapdss_dvi_ops tfp410_dvi_ops = { | ||
| 145 | .connect = tfp410_connect, | ||
| 146 | .disconnect = tfp410_disconnect, | ||
| 147 | |||
| 148 | .enable = tfp410_enable, | ||
| 149 | .disable = tfp410_disable, | ||
| 150 | |||
| 151 | .check_timings = tfp410_check_timings, | ||
| 152 | .set_timings = tfp410_set_timings, | ||
| 153 | .get_timings = tfp410_get_timings, | ||
| 154 | }; | ||
| 155 | |||
| 156 | static int tfp410_probe_pdata(struct platform_device *pdev) | ||
| 157 | { | ||
| 158 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
| 159 | struct encoder_tfp410_platform_data *pdata; | ||
| 160 | struct omap_dss_device *dssdev, *in; | ||
| 161 | |||
| 162 | pdata = dev_get_platdata(&pdev->dev); | ||
| 163 | |||
| 164 | ddata->pd_gpio = pdata->power_down_gpio; | ||
| 165 | |||
| 166 | ddata->data_lines = pdata->data_lines; | ||
| 167 | |||
| 168 | in = omap_dss_find_output(pdata->source); | ||
| 169 | if (in == NULL) { | ||
| 170 | dev_err(&pdev->dev, "Failed to find video source\n"); | ||
| 171 | return -ENODEV; | ||
| 172 | } | ||
| 173 | |||
| 174 | ddata->in = in; | ||
| 175 | |||
| 176 | dssdev = &ddata->dssdev; | ||
| 177 | dssdev->name = pdata->name; | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static int tfp410_probe(struct platform_device *pdev) | ||
| 183 | { | ||
| 184 | struct panel_drv_data *ddata; | ||
| 185 | struct omap_dss_device *dssdev; | ||
| 186 | int r; | ||
| 187 | |||
| 188 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
| 189 | if (!ddata) | ||
| 190 | return -ENOMEM; | ||
| 191 | |||
| 192 | platform_set_drvdata(pdev, ddata); | ||
| 193 | |||
| 194 | if (dev_get_platdata(&pdev->dev)) { | ||
| 195 | r = tfp410_probe_pdata(pdev); | ||
| 196 | if (r) | ||
| 197 | return r; | ||
| 198 | } else { | ||
| 199 | return -ENODEV; | ||
| 200 | } | ||
| 201 | |||
| 202 | if (gpio_is_valid(ddata->pd_gpio)) { | ||
| 203 | r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio, | ||
| 204 | GPIOF_OUT_INIT_LOW, "tfp410 PD"); | ||
| 205 | if (r) { | ||
| 206 | dev_err(&pdev->dev, "Failed to request PD GPIO %d\n", | ||
| 207 | ddata->pd_gpio); | ||
| 208 | goto err_gpio; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | dssdev = &ddata->dssdev; | ||
| 213 | dssdev->ops.dvi = &tfp410_dvi_ops; | ||
| 214 | dssdev->dev = &pdev->dev; | ||
| 215 | dssdev->type = OMAP_DISPLAY_TYPE_DPI; | ||
| 216 | dssdev->output_type = OMAP_DISPLAY_TYPE_DVI; | ||
| 217 | dssdev->owner = THIS_MODULE; | ||
| 218 | dssdev->phy.dpi.data_lines = ddata->data_lines; | ||
| 219 | |||
| 220 | r = omapdss_register_output(dssdev); | ||
| 221 | if (r) { | ||
| 222 | dev_err(&pdev->dev, "Failed to register output\n"); | ||
| 223 | goto err_reg; | ||
| 224 | } | ||
| 225 | |||
| 226 | return 0; | ||
| 227 | err_reg: | ||
| 228 | err_gpio: | ||
| 229 | omap_dss_put_device(ddata->in); | ||
| 230 | return r; | ||
| 231 | } | ||
| 232 | |||
| 233 | static int __exit tfp410_remove(struct platform_device *pdev) | ||
| 234 | { | ||
| 235 | struct panel_drv_data *ddata = platform_get_drvdata(pdev); | ||
| 236 | struct omap_dss_device *dssdev = &ddata->dssdev; | ||
| 237 | struct omap_dss_device *in = ddata->in; | ||
| 238 | |||
| 239 | omapdss_unregister_output(&ddata->dssdev); | ||
| 240 | |||
| 241 | WARN_ON(omapdss_device_is_enabled(dssdev)); | ||
| 242 | if (omapdss_device_is_enabled(dssdev)) | ||
| 243 | tfp410_disable(dssdev); | ||
| 244 | |||
| 245 | WARN_ON(omapdss_device_is_connected(dssdev)); | ||
| 246 | if (omapdss_device_is_connected(dssdev)) | ||
| 247 | tfp410_disconnect(dssdev, dssdev->device); | ||
| 248 | |||
| 249 | omap_dss_put_device(in); | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | static struct platform_driver tfp410_driver = { | ||
| 255 | .probe = tfp410_probe, | ||
| 256 | .remove = __exit_p(tfp410_remove), | ||
| 257 | .driver = { | ||
| 258 | .name = "tfp410", | ||
| 259 | .owner = THIS_MODULE, | ||
| 260 | }, | ||
| 261 | }; | ||
| 262 | |||
| 263 | module_platform_driver(tfp410_driver); | ||
| 264 | |||
| 265 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
| 266 | MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver"); | ||
| 267 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/video/omap-panel-data.h b/include/video/omap-panel-data.h index 0c3b46d3daf3..bc899b7a4a64 100644 --- a/include/video/omap-panel-data.h +++ b/include/video/omap-panel-data.h | |||
| @@ -147,4 +147,17 @@ struct panel_tpo_td043_data { | |||
| 147 | int nreset_gpio; | 147 | int nreset_gpio; |
| 148 | }; | 148 | }; |
| 149 | 149 | ||
| 150 | /** | ||
| 151 | * encoder_tfp410 platform data | ||
| 152 | * @name: name for this display entity | ||
| 153 | * @power_down_gpio: gpio number for PD pin (or -1 if not available) | ||
| 154 | * @data_lines: number of DPI datalines | ||
| 155 | */ | ||
| 156 | struct encoder_tfp410_platform_data { | ||
| 157 | const char *name; | ||
| 158 | const char *source; | ||
| 159 | int power_down_gpio; | ||
| 160 | int data_lines; | ||
| 161 | }; | ||
| 162 | |||
| 150 | #endif /* __OMAP_PANEL_DATA_H */ | 163 | #endif /* __OMAP_PANEL_DATA_H */ |
