Various fbdev changes for 3.11
* xilinxfb updates * Small cleanups and fixes to multiple drivers * OMAP display subsystem bug updates * imxfb dt support -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJR2nxAAAoJEOrjwV5ZMRf2YYcP+gIc2j4so9c4gMp5UaWtyzU8 q5rG0WtRghvVHupYTampm8+xCMcAKAAcUUhVMNbN3X7QHUAlbYQiL2Gddmo42nSw bjzYoodiuXQIgcp53UGG1bl1zmd8GhmTc8NRYQEBXUqZ4nLGlauQ5O9ZNr4V4dOQ vh5bfV61x9FBUay05cHLG8FIxV9Zcg0wUKCIHHtOkj+twk7wdnAKtOZChiXD0RVC lPXc8+xIvwu1q2R88XTvMrNVIy52tq1iIwohdwqKjpc8ndusC5DUi9DI7icUBg8B 0D81tZvCny8/HFVt8tQPW/htT1KsWlnL+qM1IMM8DRAfcAQFxXSxWITXRtOxZHIs rW5ocWxqUmS2A7wjXctDv3EbAuj/gjpZ52hDzb2B9C1KuRsj9Rp42CU2HN+KqviG YNtZV86w9Kv3Q+GLrPtWarrHW5YpOEK+ADU5PgNdrfzl22+I+Caja5IfHHNbIvr7 mBv6NlsGYHZxV75gcxvSpy33OxP4UY7F7RmtFQSXGojAE9Qwkvgca3Ug9KcTIyYs SEzBDMXlaKVn+YzpZpHeFRSm19wkU3fRyeD15r4L3orVj2jwp7fQihrX3UWyj6lh SLjr5C+YYI/leWZd5p5gjrtStyGrIXCv9EX255OkR2VA2ZS1t32/sbIKlNnyichX 4ZAPuBMCW70BxR3RZvJ1 =G+Vu -----END PGP SIGNATURE----- Merge tag 'fbdev-for-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/plagnioj/linux-fbdev Pull fbdev update from Jean-Christophe PLAGNIOL-VILLARD: "Various fbdev changes for 3.11 - xilinxfb updates - Small cleanups and fixes to multiple drivers - OMAP display subsystem bug updates - imxfb dt support" * tag 'fbdev-for-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/plagnioj/linux-fbdev: (95 commits) video: imxfb: Add DT support video: i740fb: Make i740fb_init static fb: make fp_get_options name argument const video: mmp: fix graphics/video layer enable/mask swap issue video: mmp: fix memcpy wrong size for mmp_addr issue radeon: use pdev->pm_cap instead of pci_find_capability(..,PCI_CAP_ID_PM) aty128fb: use pdev->pm_cap instead of pci_find_capability(..,PCI_CAP_ID_PM) video: of_display_timing.h: Declare 'display_timing' fbdev: bfin-lq035q1-fb: Use dev_pm_ops fbmem: return -EFAULT on copy_to_user() failure OMAPDSS: DPI: Fix wrong pixel clock limit video: replace strict_strtoul() with kstrtoul() uvesafb: Correct/simplify warning message fb: fix atyfb unused data warnings fb: fix atyfb build warning video: imxfb: Make local symbols static video: udlfb: Make local symbol static video: udlfb: Use NULL instead of 0 video: smscufx: Use NULL instead of 0 video: remove unnecessary platform_set_drvdata() ...
This commit is contained in:
Коммит
5f097cd249
|
@ -0,0 +1,51 @@
|
|||
Freescale imx21 Framebuffer
|
||||
|
||||
This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
|
||||
|
||||
Required properties:
|
||||
- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
|
||||
- reg : Should contain 1 register ranges(address and length)
|
||||
- interrupts : One interrupt of the fb dev
|
||||
|
||||
Required nodes:
|
||||
- display: Phandle to a display node as described in
|
||||
Documentation/devicetree/bindings/video/display-timing.txt
|
||||
Additional, the display node has to define properties:
|
||||
- bits-per-pixel: Bits per pixel
|
||||
- fsl,pcr: LCDC PCR value
|
||||
|
||||
Optional properties:
|
||||
- fsl,dmacr: DMA Control Register value. This is optional. By default, the
|
||||
register is not modified as recommended by the datasheet.
|
||||
- fsl,lscr1: LCDC Sharp Configuration Register value.
|
||||
|
||||
Example:
|
||||
|
||||
imxfb: fb@10021000 {
|
||||
compatible = "fsl,imx21-fb";
|
||||
interrupts = <61>;
|
||||
reg = <0x10021000 0x1000>;
|
||||
display = <&display0>;
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
display0: display0 {
|
||||
model = "Primeview-PD050VL1";
|
||||
native-mode = <&timing_disp0>;
|
||||
bits-per-pixel = <16>;
|
||||
fsl,pcr = <0xf0c88080>; /* non-standard but required */
|
||||
display-timings {
|
||||
timing_disp0: 640x480 {
|
||||
hactive = <640>;
|
||||
vactive = <480>;
|
||||
hback-porch = <112>;
|
||||
hfront-porch = <36>;
|
||||
hsync-len = <32>;
|
||||
vback-porch = <33>;
|
||||
vfront-porch = <33>;
|
||||
vsync-len = <2>;
|
||||
clock-frequency = <25000000>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,13 +1,17 @@
|
|||
* Solomon SSD1307 Framebuffer Driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "solomon,ssd1307fb-<bus>". The only supported bus for
|
||||
now is i2c.
|
||||
- compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for
|
||||
now is i2c, and the supported chips are ssd1306 and ssd1307.
|
||||
- reg: Should contain address of the controller on the I2C bus. Most likely
|
||||
0x3c or 0x3d
|
||||
- pwm: Should contain the pwm to use according to the OF device tree PWM
|
||||
specification [0]
|
||||
specification [0]. Only required for the ssd1307.
|
||||
- reset-gpios: Should contain the GPIO used to reset the OLED display
|
||||
- solomon,height: Height in pixel of the screen driven by the controller
|
||||
- solomon,width: Width in pixel of the screen driven by the controller
|
||||
- solomon,page-offset: Offset of pages (band of 8 pixels) that the screen is
|
||||
mapped to.
|
||||
|
||||
Optional properties:
|
||||
- reset-active-low: Is the reset gpio is active on physical low?
|
||||
|
|
|
@ -40,7 +40,7 @@ struct omap_crtc {
|
|||
* mgr->id.) Eventually this will be replaced w/ something
|
||||
* more common-panel-framework-y
|
||||
*/
|
||||
struct omap_overlay_manager mgr;
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
bool enabled;
|
||||
|
@ -90,7 +90,32 @@ uint32_t pipe2vbl(struct drm_crtc *crtc)
|
|||
* job of sequencing the setup of the video pipe in the proper order
|
||||
*/
|
||||
|
||||
/* ovl-mgr-id -> crtc */
|
||||
static struct omap_crtc *omap_crtcs[8];
|
||||
|
||||
/* we can probably ignore these until we support command-mode panels: */
|
||||
static int omap_crtc_connect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
if (mgr->output)
|
||||
return -EINVAL;
|
||||
|
||||
if ((mgr->supported_outputs & dst->id) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
dst->manager = mgr;
|
||||
mgr->output = dst;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_crtc_disconnect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
mgr->output->manager = NULL;
|
||||
mgr->output = NULL;
|
||||
}
|
||||
|
||||
static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
}
|
||||
|
@ -107,7 +132,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr)
|
|||
static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
|
||||
DBG("%s", omap_crtc->name);
|
||||
omap_crtc->timings = *timings;
|
||||
omap_crtc->full_update = true;
|
||||
|
@ -116,7 +141,7 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
|
|||
static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
|
||||
DBG("%s", omap_crtc->name);
|
||||
dispc_mgr_set_lcd_config(omap_crtc->channel, config);
|
||||
}
|
||||
|
@ -135,6 +160,8 @@ static void omap_crtc_unregister_framedone_handler(
|
|||
}
|
||||
|
||||
static const struct dss_mgr_ops mgr_ops = {
|
||||
.connect = omap_crtc_connect,
|
||||
.disconnect = omap_crtc_disconnect,
|
||||
.start_update = omap_crtc_start_update,
|
||||
.enable = omap_crtc_enable,
|
||||
.disable = omap_crtc_disable,
|
||||
|
@ -569,7 +596,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
|
|||
} else {
|
||||
if (encoder) {
|
||||
omap_encoder_set_enabled(encoder, false);
|
||||
omap_encoder_update(encoder, &omap_crtc->mgr,
|
||||
omap_encoder_update(encoder, omap_crtc->mgr,
|
||||
&omap_crtc->timings);
|
||||
omap_encoder_set_enabled(encoder, true);
|
||||
omap_crtc->full_update = false;
|
||||
|
@ -595,6 +622,11 @@ static const char *channel_names[] = {
|
|||
[OMAP_DSS_CHANNEL_LCD2] = "lcd2",
|
||||
};
|
||||
|
||||
void omap_crtc_pre_init(void)
|
||||
{
|
||||
dss_install_mgr_ops(&mgr_ops);
|
||||
}
|
||||
|
||||
/* initialize crtc */
|
||||
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
||||
struct drm_plane *plane, enum omap_channel channel, int id)
|
||||
|
@ -635,9 +667,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
|||
omap_irq_register(dev, &omap_crtc->error_irq);
|
||||
|
||||
/* temporary: */
|
||||
omap_crtc->mgr.id = channel;
|
||||
|
||||
dss_install_mgr_ops(&mgr_ops);
|
||||
omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
|
||||
|
||||
/* TODO: fix hard-coded setup.. add properties! */
|
||||
info = &omap_crtc->info;
|
||||
|
@ -651,6 +681,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
|||
|
||||
omap_plane_install_properties(omap_crtc->plane, &crtc->base);
|
||||
|
||||
omap_crtcs[channel] = omap_crtc;
|
||||
|
||||
return crtc;
|
||||
|
||||
fail:
|
||||
|
|
|
@ -65,10 +65,8 @@ static int get_connector_type(struct omap_dss_device *dssdev)
|
|||
switch (dssdev->type) {
|
||||
case OMAP_DISPLAY_TYPE_HDMI:
|
||||
return DRM_MODE_CONNECTOR_HDMIA;
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
if (!strcmp(dssdev->name, "dvi"))
|
||||
return DRM_MODE_CONNECTOR_DVID;
|
||||
/* fallthrough */
|
||||
case OMAP_DISPLAY_TYPE_DVI:
|
||||
return DRM_MODE_CONNECTOR_DVID;
|
||||
default:
|
||||
return DRM_MODE_CONNECTOR_Unknown;
|
||||
}
|
||||
|
@ -97,6 +95,9 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
int num_mgrs = dss_feat_get_num_mgrs();
|
||||
int num_crtcs;
|
||||
int i, id = 0;
|
||||
int r;
|
||||
|
||||
omap_crtc_pre_init();
|
||||
|
||||
drm_mode_config_init(dev);
|
||||
|
||||
|
@ -116,6 +117,7 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
enum omap_channel channel;
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
if (!dssdev->driver) {
|
||||
dev_warn(dev->dev, "%s has no driver.. skipping it\n",
|
||||
|
@ -131,6 +133,13 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
continue;
|
||||
}
|
||||
|
||||
r = dssdev->driver->connect(dssdev);
|
||||
if (r) {
|
||||
dev_err(dev->dev, "could not connect display: %s\n",
|
||||
dssdev->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
encoder = omap_encoder_init(dev, dssdev);
|
||||
|
||||
if (!encoder) {
|
||||
|
@ -172,8 +181,9 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
* other possible channels to which the encoder can connect are
|
||||
* not considered.
|
||||
*/
|
||||
channel = dssdev->output->dispc_channel;
|
||||
|
||||
mgr = omapdss_find_mgr_from_display(dssdev);
|
||||
channel = mgr->id;
|
||||
/*
|
||||
* if this channel hasn't already been taken by a previously
|
||||
* allocated crtc, we create a new crtc for it
|
||||
|
@ -247,6 +257,9 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
struct drm_encoder *encoder = priv->encoders[i];
|
||||
struct omap_dss_device *dssdev =
|
||||
omap_encoder_get_dssdev(encoder);
|
||||
struct omap_dss_device *output;
|
||||
|
||||
output = omapdss_find_output_from_display(dssdev);
|
||||
|
||||
/* figure out which crtc's we can connect the encoder to: */
|
||||
encoder->possible_crtcs = 0;
|
||||
|
@ -259,9 +272,11 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
supported_outputs =
|
||||
dss_feat_get_supported_outputs(crtc_channel);
|
||||
|
||||
if (supported_outputs & dssdev->output->id)
|
||||
if (supported_outputs & output->id)
|
||||
encoder->possible_crtcs |= (1 << id);
|
||||
}
|
||||
|
||||
omap_dss_put_device(output);
|
||||
}
|
||||
|
||||
DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
|
||||
|
|
|
@ -157,6 +157,7 @@ const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
|
|||
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
|
||||
int omap_crtc_apply(struct drm_crtc *crtc,
|
||||
struct omap_drm_apply *apply);
|
||||
void omap_crtc_pre_init(void);
|
||||
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
||||
struct drm_plane *plane, enum omap_channel channel, int id);
|
||||
|
||||
|
|
|
@ -367,6 +367,8 @@ config FB_IMX
|
|||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select FB_MODE_HELPERS
|
||||
select VIDEOMODE_HELPERS
|
||||
|
||||
config FB_CYBER2000
|
||||
tristate "CyberPro 2000/2010/5000 support"
|
||||
|
@ -2188,7 +2190,7 @@ config FB_PS3_DEFAULT_SIZE_M
|
|||
|
||||
config FB_XILINX
|
||||
tristate "Xilinx frame buffer support"
|
||||
depends on FB && (XILINX_VIRTEX || MICROBLAZE)
|
||||
depends on FB && (XILINX_VIRTEX || MICROBLAZE || ARCH_ZYNQ)
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
|
|
|
@ -2016,7 +2016,7 @@ static int aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
aty128_init_engine(par);
|
||||
|
||||
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
|
||||
par->pm_reg = pdev->pm_cap;
|
||||
par->pdev = pdev;
|
||||
par->asleep = 0;
|
||||
par->lock_blank = 0;
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -434,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par)
|
|||
const char *name;
|
||||
int i;
|
||||
|
||||
for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
|
||||
if (par->pci_id == aty_chips[i].pci_id)
|
||||
for (i = ARRAY_SIZE(aty_chips); i > 0; i--)
|
||||
if (par->pci_id == aty_chips[i - 1].pci_id)
|
||||
break;
|
||||
|
||||
if (i < 0)
|
||||
|
@ -531,8 +532,8 @@ static int correct_chipset(struct atyfb_par *par)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char ram_dram[] = "DRAM";
|
||||
static char ram_resv[] = "RESV";
|
||||
static char ram_dram[] __maybe_unused = "DRAM";
|
||||
static char ram_resv[] __maybe_unused = "RESV";
|
||||
#ifdef CONFIG_FB_ATY_GX
|
||||
static char ram_vram[] = "VRAM";
|
||||
#endif /* CONFIG_FB_ATY_GX */
|
||||
|
|
|
@ -2805,7 +2805,7 @@ static void radeonfb_early_resume(void *data)
|
|||
void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep)
|
||||
{
|
||||
/* Find PM registers in config space if any*/
|
||||
rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
|
||||
rinfo->pm_reg = rinfo->pdev->pm_cap;
|
||||
|
||||
/* Enable/Disable dynamic clocks: TODO add sysfs access */
|
||||
if (rinfo->family == CHIP_FAMILY_RS480)
|
||||
|
|
|
@ -577,7 +577,6 @@ failed:
|
|||
if (fbdev->info.cmap.len != 0) {
|
||||
fb_dealloc_cmap(&fbdev->info.cmap);
|
||||
}
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -681,7 +681,6 @@ out3:
|
|||
out2:
|
||||
free_dma(CH_EPPI0);
|
||||
out1:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -170,16 +170,19 @@ static int lq035q1_spidev_remove(struct spi_device *spi)
|
|||
return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int lq035q1_spidev_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
|
||||
}
|
||||
|
||||
static int lq035q1_spidev_resume(struct spi_device *spi)
|
||||
static int lq035q1_spidev_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct spi_control *ctl = spi_get_drvdata(spi);
|
||||
int ret;
|
||||
|
||||
ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode);
|
||||
if (ret)
|
||||
|
@ -187,9 +190,13 @@ static int lq035q1_spidev_resume(struct spi_device *spi)
|
|||
|
||||
return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(lq035q1_spidev_pm_ops, lq035q1_spidev_suspend,
|
||||
lq035q1_spidev_resume);
|
||||
#define LQ035Q1_SPIDEV_PM_OPS (&lq035q1_spidev_pm_ops)
|
||||
|
||||
#else
|
||||
# define lq035q1_spidev_suspend NULL
|
||||
# define lq035q1_spidev_resume NULL
|
||||
#define LQ035Q1_SPIDEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
/* Power down all displays on reboot, poweroff or halt */
|
||||
|
@ -708,8 +715,7 @@ static int bfin_lq035q1_probe(struct platform_device *pdev)
|
|||
info->spidrv.probe = lq035q1_spidev_probe;
|
||||
info->spidrv.remove = lq035q1_spidev_remove;
|
||||
info->spidrv.shutdown = lq035q1_spidev_shutdown;
|
||||
info->spidrv.suspend = lq035q1_spidev_suspend;
|
||||
info->spidrv.resume = lq035q1_spidev_resume;
|
||||
info->spidrv.driver.pm = LQ035Q1_SPIDEV_PM_OPS;
|
||||
|
||||
ret = spi_register_driver(&info->spidrv);
|
||||
if (ret < 0) {
|
||||
|
@ -759,7 +765,6 @@ static int bfin_lq035q1_probe(struct platform_device *pdev)
|
|||
out2:
|
||||
free_dma(CH_PPI);
|
||||
out1:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -788,7 +793,6 @@ static int bfin_lq035q1_remove(struct platform_device *pdev)
|
|||
bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
|
||||
USE_RGB565_16_BIT_PPI);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
framebuffer_release(fbinfo);
|
||||
|
||||
dev_info(&pdev->dev, "unregistered LCD driver\n");
|
||||
|
|
|
@ -578,7 +578,6 @@ out3:
|
|||
out2:
|
||||
free_dma(CH_PPI);
|
||||
out1:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -608,7 +607,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev)
|
|||
|
||||
bfin_t350mcqb_request_ports(0);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
framebuffer_release(fbinfo);
|
||||
|
||||
printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n");
|
||||
|
|
|
@ -595,7 +595,6 @@ failed_videomem:
|
|||
fb_dealloc_cmap(&info->cmap);
|
||||
failed_cmap:
|
||||
kfree(info);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -614,7 +613,6 @@ static int ep93xxfb_remove(struct platform_device *pdev)
|
|||
fbi->mach_info->teardown(pdev);
|
||||
|
||||
kfree(info);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1305,7 +1305,9 @@ static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
|
|||
err |= copy_to_user(fix32->reserved, fix->reserved,
|
||||
sizeof(fix->reserved));
|
||||
|
||||
return err;
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
|
||||
|
@ -1881,7 +1883,7 @@ static int ofonly __read_mostly;
|
|||
*
|
||||
* NOTE: Needed to maintain backwards compatibility
|
||||
*/
|
||||
int fb_get_options(char *name, char **option)
|
||||
int fb_get_options(const char *name, char **option)
|
||||
{
|
||||
char *opt, *options = NULL;
|
||||
int retval = 0;
|
||||
|
|
|
@ -469,7 +469,7 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
|
|||
unsigned long val;
|
||||
|
||||
if (s) {
|
||||
if (!strict_strtoul(s, 10, &val) && (val <= 2))
|
||||
if (!kstrtoul(s, 10, &val) && (val <= 2))
|
||||
port = (enum fsl_diu_monitor_port) val;
|
||||
else if (strncmp(s, "lvds", 4) == 0)
|
||||
port = FSL_DIU_PORT_LVDS;
|
||||
|
@ -1853,7 +1853,7 @@ static int __init fsl_diu_setup(char *options)
|
|||
if (!strncmp(opt, "monitor=", 8)) {
|
||||
monitor_port = fsl_diu_name_to_port(opt + 8);
|
||||
} else if (!strncmp(opt, "bpp=", 4)) {
|
||||
if (!strict_strtoul(opt + 4, 10, &val))
|
||||
if (!kstrtoul(opt + 4, 10, &val))
|
||||
default_bpp = val;
|
||||
} else
|
||||
fb_mode = opt;
|
||||
|
|
|
@ -1302,7 +1302,7 @@ static int __init i740fb_setup(char *options)
|
|||
}
|
||||
#endif
|
||||
|
||||
int __init i740fb_init(void)
|
||||
static int __init i740fb_init(void)
|
||||
{
|
||||
#ifndef MODULE
|
||||
char *option = NULL;
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/of_videomode.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
#include <linux/platform_data/video-imxfb.h>
|
||||
|
||||
|
@ -112,10 +118,11 @@
|
|||
#define LCDISR_EOF (1<<1)
|
||||
#define LCDISR_BOF (1<<0)
|
||||
|
||||
#define IMXFB_LSCR1_DEFAULT 0x00120300
|
||||
|
||||
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
|
||||
static const char *fb_mode;
|
||||
|
||||
|
||||
/*
|
||||
* These are the bitfields for each
|
||||
* display depth that we support.
|
||||
|
@ -187,6 +194,19 @@ static struct platform_device_id imxfb_devtype[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(platform, imxfb_devtype);
|
||||
|
||||
static struct of_device_id imxfb_of_dev_id[] = {
|
||||
{
|
||||
.compatible = "fsl,imx1-fb",
|
||||
.data = &imxfb_devtype[IMX1_FB],
|
||||
}, {
|
||||
.compatible = "fsl,imx21-fb",
|
||||
.data = &imxfb_devtype[IMX21_FB],
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
|
||||
|
||||
static inline int is_imx1_fb(struct imxfb_info *fbi)
|
||||
{
|
||||
return fbi->devtype == IMX1_FB;
|
||||
|
@ -319,6 +339,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
|
|||
struct imx_fb_videomode *m;
|
||||
int i;
|
||||
|
||||
if (!fb_mode)
|
||||
return &fbi->mode[0];
|
||||
|
||||
for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
|
||||
if (!strcmp(m->mode.name, fb_mode))
|
||||
return m;
|
||||
|
@ -474,6 +497,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl)
|
|||
struct imxfb_info *fbi = bl_get_data(bl);
|
||||
int brightness = bl->props.brightness;
|
||||
|
||||
if (!fbi->pwmr)
|
||||
return 0;
|
||||
|
||||
if (bl->props.power != FB_BLANK_UNBLANK)
|
||||
brightness = 0;
|
||||
if (bl->props.fb_blank != FB_BLANK_UNBLANK)
|
||||
|
@ -684,10 +710,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
|
|||
|
||||
writel(fbi->pcr, fbi->regs + LCDC_PCR);
|
||||
#ifndef PWMR_BACKLIGHT_AVAILABLE
|
||||
writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
|
||||
if (fbi->pwmr)
|
||||
writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
|
||||
#endif
|
||||
writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
|
||||
writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
|
||||
|
||||
/* dmacr = 0 is no valid value, as we need DMA control marks. */
|
||||
if (fbi->dmacr)
|
||||
writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -723,13 +753,12 @@ static int imxfb_resume(struct platform_device *dev)
|
|||
#define imxfb_resume NULL
|
||||
#endif
|
||||
|
||||
static int __init imxfb_init_fbinfo(struct platform_device *pdev)
|
||||
static int imxfb_init_fbinfo(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct fb_info *info = dev_get_drvdata(&pdev->dev);
|
||||
struct imxfb_info *fbi = info->par;
|
||||
struct imx_fb_videomode *m;
|
||||
int i;
|
||||
struct device_node *np;
|
||||
|
||||
pr_debug("%s\n",__func__);
|
||||
|
||||
|
@ -760,41 +789,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
|
|||
info->fbops = &imxfb_ops;
|
||||
info->flags = FBINFO_FLAG_DEFAULT |
|
||||
FBINFO_READS_FAST;
|
||||
info->var.grayscale = pdata->cmap_greyscale;
|
||||
fbi->cmap_inverse = pdata->cmap_inverse;
|
||||
fbi->cmap_static = pdata->cmap_static;
|
||||
fbi->lscr1 = pdata->lscr1;
|
||||
fbi->dmacr = pdata->dmacr;
|
||||
fbi->pwmr = pdata->pwmr;
|
||||
fbi->lcd_power = pdata->lcd_power;
|
||||
fbi->backlight_power = pdata->backlight_power;
|
||||
if (pdata) {
|
||||
info->var.grayscale = pdata->cmap_greyscale;
|
||||
fbi->cmap_inverse = pdata->cmap_inverse;
|
||||
fbi->cmap_static = pdata->cmap_static;
|
||||
fbi->lscr1 = pdata->lscr1;
|
||||
fbi->dmacr = pdata->dmacr;
|
||||
fbi->pwmr = pdata->pwmr;
|
||||
fbi->lcd_power = pdata->lcd_power;
|
||||
fbi->backlight_power = pdata->backlight_power;
|
||||
} else {
|
||||
np = pdev->dev.of_node;
|
||||
info->var.grayscale = of_property_read_bool(np,
|
||||
"cmap-greyscale");
|
||||
fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
|
||||
fbi->cmap_static = of_property_read_bool(np, "cmap-static");
|
||||
|
||||
for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
|
||||
info->fix.smem_len = max_t(size_t, info->fix.smem_len,
|
||||
m->mode.xres * m->mode.yres * m->bpp / 8);
|
||||
fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
|
||||
of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
|
||||
|
||||
of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
|
||||
|
||||
/* These two function pointers could be used by some specific
|
||||
* platforms. */
|
||||
fbi->lcd_power = NULL;
|
||||
fbi->backlight_power = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init imxfb_probe(struct platform_device *pdev)
|
||||
static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
|
||||
struct imx_fb_videomode *imxfb_mode)
|
||||
{
|
||||
int ret;
|
||||
struct fb_videomode *of_mode = &imxfb_mode->mode;
|
||||
u32 bpp;
|
||||
u32 pcr;
|
||||
|
||||
ret = of_property_read_string(np, "model", &of_mode->name);
|
||||
if (ret)
|
||||
of_mode->name = NULL;
|
||||
|
||||
ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get videomode from DT\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "bits-per-pixel", &bpp);
|
||||
ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read bpp and pcr from DT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bpp < 1 || bpp > 255) {
|
||||
dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
imxfb_mode->bpp = bpp;
|
||||
imxfb_mode->pcr = pcr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imxfb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct imxfb_info *fbi;
|
||||
struct fb_info *info;
|
||||
struct imx_fb_platform_data *pdata;
|
||||
struct resource *res;
|
||||
struct imx_fb_videomode *m;
|
||||
const struct of_device_id *of_id;
|
||||
int ret, i;
|
||||
int bytes_per_pixel;
|
||||
|
||||
dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
|
||||
|
||||
of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
|
||||
if (of_id)
|
||||
pdev->id_entry = of_id->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev,"No platform_data available\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
|
||||
if (!info)
|
||||
|
@ -802,15 +885,55 @@ static int __init imxfb_probe(struct platform_device *pdev)
|
|||
|
||||
fbi = info->par;
|
||||
|
||||
if (!fb_mode)
|
||||
fb_mode = pdata->mode[0].mode.name;
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
ret = imxfb_init_fbinfo(pdev);
|
||||
if (ret < 0)
|
||||
goto failed_init;
|
||||
|
||||
if (pdata) {
|
||||
if (!fb_mode)
|
||||
fb_mode = pdata->mode[0].mode.name;
|
||||
|
||||
fbi->mode = pdata->mode;
|
||||
fbi->num_modes = pdata->num_modes;
|
||||
} else {
|
||||
struct device_node *display_np;
|
||||
fb_mode = NULL;
|
||||
|
||||
display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
|
||||
if (!display_np) {
|
||||
dev_err(&pdev->dev, "No display defined in devicetree\n");
|
||||
ret = -EINVAL;
|
||||
goto failed_of_parse;
|
||||
}
|
||||
|
||||
/*
|
||||
* imxfb does not support more modes, we choose only the native
|
||||
* mode.
|
||||
*/
|
||||
fbi->num_modes = 1;
|
||||
|
||||
fbi->mode = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct imx_fb_videomode), GFP_KERNEL);
|
||||
if (!fbi->mode) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_of_parse;
|
||||
}
|
||||
|
||||
ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
|
||||
if (ret)
|
||||
goto failed_of_parse;
|
||||
}
|
||||
|
||||
/* Calculate maximum bytes used per pixel. In most cases this should
|
||||
* be the same as m->bpp/8 */
|
||||
m = &fbi->mode[0];
|
||||
bytes_per_pixel = (m->bpp + 7) / 8;
|
||||
for (i = 0; i < fbi->num_modes; i++, m++)
|
||||
info->fix.smem_len = max_t(size_t, info->fix.smem_len,
|
||||
m->mode.xres * m->mode.yres * bytes_per_pixel);
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res),
|
||||
DRIVER_NAME);
|
||||
if (!res) {
|
||||
|
@ -843,7 +966,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
|
|||
goto failed_ioremap;
|
||||
}
|
||||
|
||||
if (!pdata->fixed_screen_cpu) {
|
||||
/* Seems not being used by anyone, so no support for oftree */
|
||||
if (!pdata || !pdata->fixed_screen_cpu) {
|
||||
fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
|
||||
fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
|
||||
fbi->map_size, &fbi->map_dma, GFP_KERNEL);
|
||||
|
@ -868,18 +992,16 @@ static int __init imxfb_probe(struct platform_device *pdev)
|
|||
info->fix.smem_start = fbi->screen_dma;
|
||||
}
|
||||
|
||||
if (pdata->init) {
|
||||
if (pdata && pdata->init) {
|
||||
ret = pdata->init(fbi->pdev);
|
||||
if (ret)
|
||||
goto failed_platform_init;
|
||||
}
|
||||
|
||||
fbi->mode = pdata->mode;
|
||||
fbi->num_modes = pdata->num_modes;
|
||||
|
||||
INIT_LIST_HEAD(&info->modelist);
|
||||
for (i = 0; i < pdata->num_modes; i++)
|
||||
fb_add_videomode(&pdata->mode[i].mode, &info->modelist);
|
||||
for (i = 0; i < fbi->num_modes; i++)
|
||||
fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
|
||||
|
||||
/*
|
||||
* This makes sure that our colour bitfield
|
||||
|
@ -909,10 +1031,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
|
|||
failed_register:
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
failed_cmap:
|
||||
if (pdata->exit)
|
||||
if (pdata && pdata->exit)
|
||||
pdata->exit(fbi->pdev);
|
||||
failed_platform_init:
|
||||
if (!pdata->fixed_screen_cpu)
|
||||
if (pdata && !pdata->fixed_screen_cpu)
|
||||
dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
|
||||
fbi->map_dma);
|
||||
failed_map:
|
||||
|
@ -921,9 +1043,9 @@ failed_ioremap:
|
|||
failed_getclock:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
failed_req:
|
||||
failed_of_parse:
|
||||
kfree(info->pseudo_palette);
|
||||
failed_init:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
framebuffer_release(info);
|
||||
return ret;
|
||||
}
|
||||
|
@ -945,7 +1067,7 @@ static int imxfb_remove(struct platform_device *pdev)
|
|||
unregister_framebuffer(info);
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata->exit)
|
||||
if (pdata && pdata->exit)
|
||||
pdata->exit(fbi->pdev);
|
||||
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
|
@ -955,12 +1077,10 @@ static int imxfb_remove(struct platform_device *pdev)
|
|||
iounmap(fbi->regs);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void imxfb_shutdown(struct platform_device * dev)
|
||||
static void imxfb_shutdown(struct platform_device *dev)
|
||||
{
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
struct imxfb_info *fbi = info->par;
|
||||
|
@ -974,6 +1094,7 @@ static struct platform_driver imxfb_driver = {
|
|||
.shutdown = imxfb_shutdown,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = imxfb_of_dev_id,
|
||||
},
|
||||
.id_table = imxfb_devtype,
|
||||
};
|
||||
|
@ -999,7 +1120,7 @@ static int imxfb_setup(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init imxfb_init(void)
|
||||
static int __init imxfb_init(void)
|
||||
{
|
||||
int ret = imxfb_setup();
|
||||
|
||||
|
|
|
@ -737,8 +737,6 @@ static int jzfb_remove(struct platform_device *pdev)
|
|||
fb_dealloc_cmap(&jzfb->fb->cmap);
|
||||
jzfb_free_devmem(jzfb);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
framebuffer_release(jzfb->fb);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -659,7 +659,6 @@ failed_destroy_mutex:
|
|||
mutex_destroy(&fbi->access_ok);
|
||||
failed:
|
||||
dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n");
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
framebuffer_release(info);
|
||||
|
||||
|
|
|
@ -165,9 +165,9 @@ static void overlay_set_win(struct mmp_overlay *overlay, struct mmp_win *win)
|
|||
|
||||
static void dmafetch_onoff(struct mmp_overlay *overlay, int on)
|
||||
{
|
||||
u32 mask = overlay_is_vid(overlay) ? CFG_GRA_ENA_MASK :
|
||||
CFG_DMA_ENA_MASK;
|
||||
u32 enable = overlay_is_vid(overlay) ? CFG_GRA_ENA(1) : CFG_DMA_ENA(1);
|
||||
u32 mask = overlay_is_vid(overlay) ? CFG_DMA_ENA_MASK :
|
||||
CFG_GRA_ENA_MASK;
|
||||
u32 enable = overlay_is_vid(overlay) ? CFG_DMA_ENA(1) : CFG_GRA_ENA(1);
|
||||
u32 tmp;
|
||||
struct mmp_path *path = overlay->path;
|
||||
|
||||
|
@ -238,7 +238,7 @@ static int overlay_set_addr(struct mmp_overlay *overlay, struct mmp_addr *addr)
|
|||
struct lcd_regs *regs = path_regs(overlay->path);
|
||||
|
||||
/* FIXME: assert addr supported */
|
||||
memcpy(&overlay->addr, addr, sizeof(struct mmp_win));
|
||||
memcpy(&overlay->addr, addr, sizeof(struct mmp_addr));
|
||||
writel(addr->phys[0], ®s->g_0);
|
||||
|
||||
return overlay->addr.phys[0];
|
||||
|
@ -566,7 +566,6 @@ failed:
|
|||
devm_kfree(ctrl->dev, ctrl);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
dev_err(&pdev->dev, "device init failed\n");
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -899,7 +899,6 @@ static int mxsfb_probe(struct platform_device *pdev)
|
|||
|
||||
host->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(host->base)) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = PTR_ERR(host->base);
|
||||
goto fb_release;
|
||||
}
|
||||
|
@ -986,8 +985,6 @@ static int mxsfb_remove(struct platform_device *pdev)
|
|||
|
||||
framebuffer_release(fb_info);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -707,7 +707,6 @@ static int nuc900fb_remove(struct platform_device *pdev)
|
|||
release_resource(fbi->mem);
|
||||
kfree(fbi->mem);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
framebuffer_release(fbinfo);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -53,21 +53,16 @@ static int parse_timing_property(struct device_node *np, const char *name,
|
|||
}
|
||||
|
||||
/**
|
||||
* of_get_display_timing - parse display_timing entry from device_node
|
||||
* of_parse_display_timing - parse display_timing entry from device_node
|
||||
* @np: device_node with the properties
|
||||
**/
|
||||
static struct display_timing *of_get_display_timing(struct device_node *np)
|
||||
static int of_parse_display_timing(struct device_node *np,
|
||||
struct display_timing *dt)
|
||||
{
|
||||
struct display_timing *dt;
|
||||
u32 val = 0;
|
||||
int ret = 0;
|
||||
|
||||
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
|
||||
if (!dt) {
|
||||
pr_err("%s: could not allocate display_timing struct\n",
|
||||
of_node_full_name(np));
|
||||
return NULL;
|
||||
}
|
||||
memset(dt, 0, sizeof(*dt));
|
||||
|
||||
ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch);
|
||||
ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch);
|
||||
|
@ -101,13 +96,39 @@ static struct display_timing *of_get_display_timing(struct device_node *np)
|
|||
if (ret) {
|
||||
pr_err("%s: error reading timing properties\n",
|
||||
of_node_full_name(np));
|
||||
kfree(dt);
|
||||
return NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return dt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_get_display_timing - parse a display_timing entry
|
||||
* @np: device_node with the timing subnode
|
||||
* @name: name of the timing node
|
||||
* @dt: display_timing struct to fill
|
||||
**/
|
||||
int of_get_display_timing(struct device_node *np, const char *name,
|
||||
struct display_timing *dt)
|
||||
{
|
||||
struct device_node *timing_np;
|
||||
|
||||
if (!np) {
|
||||
pr_err("%s: no devicenode given\n", of_node_full_name(np));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
timing_np = of_find_node_by_name(np, name);
|
||||
if (!timing_np) {
|
||||
pr_err("%s: could not find node '%s'\n",
|
||||
of_node_full_name(np), name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return of_parse_display_timing(timing_np, dt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_get_display_timing);
|
||||
|
||||
/**
|
||||
* of_get_display_timings - parse all display_timing entries from a device_node
|
||||
* @np: device_node with the subnodes
|
||||
|
@ -174,9 +195,17 @@ struct display_timings *of_get_display_timings(struct device_node *np)
|
|||
|
||||
for_each_child_of_node(timings_np, entry) {
|
||||
struct display_timing *dt;
|
||||
int r;
|
||||
|
||||
dt = of_get_display_timing(entry);
|
||||
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
|
||||
if (!dt) {
|
||||
pr_err("%s: could not allocate display_timing struct\n",
|
||||
of_node_full_name(np));
|
||||
goto timingfail;
|
||||
}
|
||||
|
||||
r = of_parse_display_timing(entry, dt);
|
||||
if (r) {
|
||||
/*
|
||||
* to not encourage wrong devicetrees, fail in case of
|
||||
* an error
|
||||
|
|
|
@ -6,5 +6,6 @@ if ARCH_OMAP2PLUS
|
|||
source "drivers/video/omap2/dss/Kconfig"
|
||||
source "drivers/video/omap2/omapfb/Kconfig"
|
||||
source "drivers/video/omap2/displays/Kconfig"
|
||||
source "drivers/video/omap2/displays-new/Kconfig"
|
||||
|
||||
endif
|
||||
|
|
|
@ -2,4 +2,5 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
|
|||
|
||||
obj-$(CONFIG_OMAP2_DSS) += dss/
|
||||
obj-y += displays/
|
||||
obj-y += displays-new/
|
||||
obj-$(CONFIG_FB_OMAP2) += omapfb/
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
menu "OMAP Display Device Drivers (new device model)"
|
||||
depends on OMAP2_DSS
|
||||
|
||||
config DISPLAY_ENCODER_TFP410
|
||||
tristate "TFP410 DPI to DVI Encoder"
|
||||
help
|
||||
Driver for TFP410 DPI to DVI encoder.
|
||||
|
||||
config DISPLAY_ENCODER_TPD12S015
|
||||
tristate "TPD12S015 HDMI ESD protection and level shifter"
|
||||
help
|
||||
Driver for TPD12S015, which offers HDMI ESD protection and level
|
||||
shifting.
|
||||
|
||||
config DISPLAY_CONNECTOR_DVI
|
||||
tristate "DVI Connector"
|
||||
depends on I2C
|
||||
help
|
||||
Driver for a generic DVI connector.
|
||||
|
||||
config DISPLAY_CONNECTOR_HDMI
|
||||
tristate "HDMI Connector"
|
||||
help
|
||||
Driver for a generic HDMI connector.
|
||||
|
||||
config DISPLAY_CONNECTOR_ANALOG_TV
|
||||
tristate "Analog TV Connector"
|
||||
help
|
||||
Driver for a generic analog TV connector.
|
||||
|
||||
config DISPLAY_PANEL_DPI
|
||||
tristate "Generic DPI panel"
|
||||
help
|
||||
Driver for generic DPI panels.
|
||||
|
||||
config DISPLAY_PANEL_DSI_CM
|
||||
tristate "Generic DSI Command Mode Panel"
|
||||
help
|
||||
Driver for generic DSI command mode panels.
|
||||
|
||||
config DISPLAY_PANEL_SONY_ACX565AKM
|
||||
tristate "ACX565AKM Panel"
|
||||
depends on SPI && BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
This is the LCD panel used on Nokia N900
|
||||
|
||||
config DISPLAY_PANEL_LGPHILIPS_LB035Q02
|
||||
tristate "LG.Philips LB035Q02 LCD Panel"
|
||||
depends on SPI
|
||||
help
|
||||
LCD Panel used on the Gumstix Overo Palo35
|
||||
|
||||
config DISPLAY_PANEL_SHARP_LS037V7DW01
|
||||
tristate "Sharp LS037V7DW01 LCD Panel"
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
LCD Panel used in TI's SDP3430 and EVM boards
|
||||
|
||||
config DISPLAY_PANEL_TPO_TD043MTEA1
|
||||
tristate "TPO TD043MTEA1 LCD Panel"
|
||||
depends on SPI
|
||||
help
|
||||
LCD Panel used in OMAP3 Pandora
|
||||
|
||||
config DISPLAY_PANEL_NEC_NL8048HL11
|
||||
tristate "NEC NL8048HL11 Panel"
|
||||
depends on SPI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
This NEC NL8048HL11 panel is TFT LCD used in the
|
||||
Zoom2/3/3630 sdp boards.
|
||||
|
||||
endmenu
|
|
@ -0,0 +1,12 @@
|
|||
obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
|
||||
obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
|
||||
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
|
||||
obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o
|
||||
obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
|
||||
obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o
|
||||
obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o
|
||||
obj-$(CONFIG_DISPLAY_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
|
||||
obj-$(CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
|
||||
obj-$(CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
|
||||
obj-$(CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
|
||||
obj-$(CONFIG_DISPLAY_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Analog TV Connector driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
|
||||
enum omap_dss_venc_type connector_type;
|
||||
bool invert_polarity;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static int tvc_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
dev_dbg(ddata->dev, "connect\n");
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.atv->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tvc_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(ddata->dev, "disconnect\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.atv->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int tvc_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
dev_dbg(ddata->dev, "enable\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.atv->set_timings(in, &ddata->timings);
|
||||
|
||||
in->ops.atv->set_type(in, ddata->connector_type);
|
||||
in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity);
|
||||
|
||||
r = in->ops.atv->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void tvc_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(ddata->dev, "disable\n");
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.atv->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void tvc_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->timings = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.atv->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void tvc_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->timings;
|
||||
}
|
||||
|
||||
static int tvc_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.atv->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static u32 tvc_get_wss(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.atv->get_wss(in);
|
||||
}
|
||||
|
||||
static int tvc_set_wss(struct omap_dss_device *dssdev, u32 wss)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.atv->set_wss(in, wss);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver tvc_driver = {
|
||||
.connect = tvc_connect,
|
||||
.disconnect = tvc_disconnect,
|
||||
|
||||
.enable = tvc_enable,
|
||||
.disable = tvc_disable,
|
||||
|
||||
.set_timings = tvc_set_timings,
|
||||
.get_timings = tvc_get_timings,
|
||||
.check_timings = tvc_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
|
||||
.get_wss = tvc_get_wss,
|
||||
.set_wss = tvc_set_wss,
|
||||
};
|
||||
|
||||
static int tvc_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct connector_atv_platform_data *pdata;
|
||||
struct omap_dss_device *in, *dssdev;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
ddata->connector_type = pdata->connector_type;
|
||||
ddata->invert_polarity = ddata->invert_polarity;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tvc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
ddata->dev = &pdev->dev;
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = tvc_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->timings = omap_dss_pal_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->driver = &tvc_driver;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = omap_dss_pal_timings;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_reg:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit tvc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_display(&ddata->dssdev);
|
||||
|
||||
tvc_disable(dssdev);
|
||||
tvc_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tvc_connector_driver = {
|
||||
.probe = tvc_probe,
|
||||
.remove = __exit_p(tvc_remove),
|
||||
.driver = {
|
||||
.name = "connector-analog-tv",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(tvc_connector_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("Analog TV Connector driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* Generic DVI Connector driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
static const struct omap_video_timings dvic_default_timings = {
|
||||
.x_res = 640,
|
||||
.y_res = 480,
|
||||
|
||||
.pixel_clock = 23500,
|
||||
|
||||
.hfp = 48,
|
||||
.hsw = 32,
|
||||
.hbp = 80,
|
||||
|
||||
.vfp = 3,
|
||||
.vsw = 4,
|
||||
.vbp = 7,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
|
||||
.de_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
|
||||
};
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
|
||||
struct i2c_adapter *i2c_adapter;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static int dvic_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.dvi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dvic_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dvi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int dvic_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.dvi->set_timings(in, &ddata->timings);
|
||||
|
||||
r = in->ops.dvi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dvic_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dvi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void dvic_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->timings = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.dvi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void dvic_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->timings;
|
||||
}
|
||||
|
||||
static int dvic_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.dvi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static int dvic_ddc_read(struct i2c_adapter *adapter,
|
||||
unsigned char *buf, u16 count, u8 offset)
|
||||
{
|
||||
int r, retries;
|
||||
|
||||
for (retries = 3; retries > 0; retries--) {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = DDC_ADDR,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &offset,
|
||||
}, {
|
||||
.addr = DDC_ADDR,
|
||||
.flags = I2C_M_RD,
|
||||
.len = count,
|
||||
.buf = buf,
|
||||
}
|
||||
};
|
||||
|
||||
r = i2c_transfer(adapter, msgs, 2);
|
||||
if (r == 2)
|
||||
return 0;
|
||||
|
||||
if (r != -EAGAIN)
|
||||
break;
|
||||
}
|
||||
|
||||
return r < 0 ? r : -EIO;
|
||||
}
|
||||
|
||||
static int dvic_read_edid(struct omap_dss_device *dssdev,
|
||||
u8 *edid, int len)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
int r, l, bytes_read;
|
||||
|
||||
if (!ddata->i2c_adapter)
|
||||
return -ENODEV;
|
||||
|
||||
l = min(EDID_LENGTH, len);
|
||||
r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
bytes_read = l;
|
||||
|
||||
/* if there are extensions, read second block */
|
||||
if (len > EDID_LENGTH && edid[0x7e] > 0) {
|
||||
l = min(EDID_LENGTH, len - EDID_LENGTH);
|
||||
|
||||
r = dvic_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH,
|
||||
l, EDID_LENGTH);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
bytes_read += l;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static bool dvic_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
unsigned char out;
|
||||
int r;
|
||||
|
||||
if (!ddata->i2c_adapter)
|
||||
return true;
|
||||
|
||||
r = dvic_ddc_read(ddata->i2c_adapter, &out, 1, 0);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
static struct omap_dss_driver dvic_driver = {
|
||||
.connect = dvic_connect,
|
||||
.disconnect = dvic_disconnect,
|
||||
|
||||
.enable = dvic_enable,
|
||||
.disable = dvic_disable,
|
||||
|
||||
.set_timings = dvic_set_timings,
|
||||
.get_timings = dvic_get_timings,
|
||||
.check_timings = dvic_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
|
||||
.read_edid = dvic_read_edid,
|
||||
.detect = dvic_detect,
|
||||
};
|
||||
|
||||
static int dvic_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct connector_dvi_platform_data *pdata;
|
||||
struct omap_dss_device *in, *dssdev;
|
||||
int i2c_bus_num;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
i2c_bus_num = pdata->i2c_bus_num;
|
||||
|
||||
if (i2c_bus_num != -1) {
|
||||
struct i2c_adapter *adapter;
|
||||
|
||||
adapter = i2c_get_adapter(i2c_bus_num);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get I2C adapter, bus %d\n",
|
||||
i2c_bus_num);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->i2c_adapter = adapter;
|
||||
}
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = dvic_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->timings = dvic_default_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->driver = &dvic_driver;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DVI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = dvic_default_timings;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit dvic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_display(&ddata->dssdev);
|
||||
|
||||
dvic_disable(dssdev);
|
||||
dvic_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
if (ddata->i2c_adapter)
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver dvi_connector_driver = {
|
||||
.probe = dvic_probe,
|
||||
.remove = __exit_p(dvic_remove),
|
||||
.driver = {
|
||||
.name = "connector-dvi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dvi_connector_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("Generic DVI Connector driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* HDMI Connector driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
static const struct omap_video_timings hdmic_default_timings = {
|
||||
.x_res = 640,
|
||||
.y_res = 480,
|
||||
.pixel_clock = 25175,
|
||||
.hsw = 96,
|
||||
.hfp = 16,
|
||||
.hbp = 48,
|
||||
.vsw = 2,
|
||||
.vfp = 11,
|
||||
.vbp = 31,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
|
||||
.interlace = false,
|
||||
};
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static int hdmic_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
dev_dbg(ddata->dev, "connect\n");
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.hdmi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmic_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(ddata->dev, "disconnect\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.hdmi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int hdmic_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
dev_dbg(ddata->dev, "enable\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.hdmi->set_timings(in, &ddata->timings);
|
||||
|
||||
r = in->ops.hdmi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmic_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(ddata->dev, "disable\n");
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.hdmi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void hdmic_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->timings = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.hdmi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void hdmic_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->timings;
|
||||
}
|
||||
|
||||
static int hdmic_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.hdmi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static int hdmic_read_edid(struct omap_dss_device *dssdev,
|
||||
u8 *edid, int len)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.hdmi->read_edid(in, edid, len);
|
||||
}
|
||||
|
||||
static bool hdmic_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.hdmi->detect(in);
|
||||
}
|
||||
|
||||
static int hdmic_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
/* enable audio only if the display is active */
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return -EPERM;
|
||||
|
||||
r = in->ops.hdmi->audio_enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmic_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
in->ops.hdmi->audio_disable(in);
|
||||
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
|
||||
}
|
||||
|
||||
static int hdmic_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* No need to check the panel state. It was checked when trasitioning
|
||||
* to AUDIO_ENABLED.
|
||||
*/
|
||||
if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED)
|
||||
return -EPERM;
|
||||
|
||||
r = in->ops.hdmi->audio_start(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmic_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
in->ops.hdmi->audio_stop(in);
|
||||
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
|
||||
}
|
||||
|
||||
static bool hdmic_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return false;
|
||||
|
||||
return in->ops.hdmi->audio_supported(in);
|
||||
}
|
||||
|
||||
static int hdmic_audio_config(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
/* config audio only if the display is active */
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return -EPERM;
|
||||
|
||||
r = in->ops.hdmi->audio_config(in, audio);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct omap_dss_driver hdmic_driver = {
|
||||
.connect = hdmic_connect,
|
||||
.disconnect = hdmic_disconnect,
|
||||
|
||||
.enable = hdmic_enable,
|
||||
.disable = hdmic_disable,
|
||||
|
||||
.set_timings = hdmic_set_timings,
|
||||
.get_timings = hdmic_get_timings,
|
||||
.check_timings = hdmic_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
|
||||
.read_edid = hdmic_read_edid,
|
||||
.detect = hdmic_detect,
|
||||
|
||||
.audio_enable = hdmic_audio_enable,
|
||||
.audio_disable = hdmic_audio_disable,
|
||||
.audio_start = hdmic_audio_start,
|
||||
.audio_stop = hdmic_audio_stop,
|
||||
.audio_supported = hdmic_audio_supported,
|
||||
.audio_config = hdmic_audio_config,
|
||||
};
|
||||
|
||||
static int hdmic_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct connector_hdmi_platform_data *pdata;
|
||||
struct omap_dss_device *in, *dssdev;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
ddata->dev = &pdev->dev;
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = hdmic_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->timings = hdmic_default_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->driver = &hdmic_driver;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = hdmic_default_timings;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_reg:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit hdmic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_display(&ddata->dssdev);
|
||||
|
||||
hdmic_disable(dssdev);
|
||||
hdmic_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hdmi_connector_driver = {
|
||||
.probe = hdmic_probe,
|
||||
.remove = __exit_p(hdmic_remove),
|
||||
.driver = {
|
||||
.name = "connector-hdmi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(hdmi_connector_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("HDMI Connector driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* TFP410 DPI-to-DVI encoder driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
int pd_gpio;
|
||||
int data_lines;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static int tfp410_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return -EBUSY;
|
||||
|
||||
r = in->ops.dpi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->output = dssdev;
|
||||
dssdev->device = dst;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tfp410_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
WARN_ON(!omapdss_device_is_connected(dssdev));
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
WARN_ON(dst != dssdev->device);
|
||||
if (dst != dssdev->device)
|
||||
return;
|
||||
|
||||
dst->output = NULL;
|
||||
dssdev->device = NULL;
|
||||
|
||||
in->ops.dpi->disconnect(in, &ddata->dssdev);
|
||||
}
|
||||
|
||||
static int tfp410_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.dpi->set_timings(in, &ddata->timings);
|
||||
in->ops.dpi->set_data_lines(in, ddata->data_lines);
|
||||
|
||||
r = in->ops.dpi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->pd_gpio))
|
||||
gpio_set_value_cansleep(ddata->pd_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tfp410_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(ddata->pd_gpio))
|
||||
gpio_set_value_cansleep(ddata->pd_gpio, 0);
|
||||
|
||||
in->ops.dpi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void tfp410_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->timings = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.dpi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void tfp410_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->timings;
|
||||
}
|
||||
|
||||
static int tfp410_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.dpi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static const struct omapdss_dvi_ops tfp410_dvi_ops = {
|
||||
.connect = tfp410_connect,
|
||||
.disconnect = tfp410_disconnect,
|
||||
|
||||
.enable = tfp410_enable,
|
||||
.disable = tfp410_disable,
|
||||
|
||||
.check_timings = tfp410_check_timings,
|
||||
.set_timings = tfp410_set_timings,
|
||||
.get_timings = tfp410_get_timings,
|
||||
};
|
||||
|
||||
static int tfp410_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct encoder_tfp410_platform_data *pdata;
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
ddata->pd_gpio = pdata->power_down_gpio;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tfp410_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = tfp410_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->pd_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "tfp410 PD");
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
|
||||
ddata->pd_gpio);
|
||||
goto err_gpio;
|
||||
}
|
||||
}
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->ops.dvi = &tfp410_dvi_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->phy.dpi.data_lines = ddata->data_lines;
|
||||
|
||||
r = omapdss_register_output(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register output\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_reg:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit tfp410_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_output(&ddata->dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_enabled(dssdev));
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
tfp410_disable(dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_connected(dssdev));
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
tfp410_disconnect(dssdev, dssdev->device);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tfp410_driver = {
|
||||
.probe = tfp410_probe,
|
||||
.remove = __exit_p(tfp410_remove),
|
||||
.driver = {
|
||||
.name = "tfp410",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(tfp410_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* TPD12S015 HDMI ESD protection & level shifter chip driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
int ct_cp_hpd_gpio;
|
||||
int ls_oe_gpio;
|
||||
int hpd_gpio;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
|
||||
struct completion hpd_completion;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static irqreturn_t tpd_hpd_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct panel_drv_data *ddata = data;
|
||||
bool hpd;
|
||||
|
||||
hpd = gpio_get_value_cansleep(ddata->hpd_gpio);
|
||||
|
||||
dev_dbg(ddata->dssdev.dev, "hpd %d\n", hpd);
|
||||
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio)) {
|
||||
if (hpd)
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
|
||||
else
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
|
||||
}
|
||||
|
||||
complete_all(&ddata->hpd_completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tpd_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
r = in->ops.hdmi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->output = dssdev;
|
||||
dssdev->device = dst;
|
||||
|
||||
INIT_COMPLETION(ddata->hpd_completion);
|
||||
|
||||
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
|
||||
/* DC-DC converter needs at max 300us to get to 90% of 5V */
|
||||
udelay(300);
|
||||
|
||||
/*
|
||||
* If there's a cable connected, wait for the hpd irq to trigger,
|
||||
* which turns on the level shifters.
|
||||
*/
|
||||
if (gpio_get_value_cansleep(ddata->hpd_gpio)) {
|
||||
unsigned long to;
|
||||
to = wait_for_completion_timeout(&ddata->hpd_completion,
|
||||
msecs_to_jiffies(250));
|
||||
WARN_ON_ONCE(to == 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpd_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
WARN_ON(dst != dssdev->device);
|
||||
|
||||
if (dst != dssdev->device)
|
||||
return;
|
||||
|
||||
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
|
||||
|
||||
dst->output = NULL;
|
||||
dssdev->device = NULL;
|
||||
|
||||
in->ops.hdmi->disconnect(in, &ddata->dssdev);
|
||||
}
|
||||
|
||||
static int tpd_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return 0;
|
||||
|
||||
in->ops.hdmi->set_timings(in, &ddata->timings);
|
||||
|
||||
r = in->ops.hdmi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void tpd_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return;
|
||||
|
||||
in->ops.hdmi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void tpd_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->timings = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.hdmi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void tpd_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->timings;
|
||||
}
|
||||
|
||||
static int tpd_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
r = in->ops.hdmi->check_timings(in, timings);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int tpd_read_edid(struct omap_dss_device *dssdev,
|
||||
u8 *edid, int len)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!gpio_get_value_cansleep(ddata->hpd_gpio))
|
||||
return -ENODEV;
|
||||
|
||||
return in->ops.hdmi->read_edid(in, edid, len);
|
||||
}
|
||||
|
||||
static bool tpd_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
return gpio_get_value_cansleep(ddata->hpd_gpio);
|
||||
}
|
||||
|
||||
static int tpd_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.hdmi->audio_enable(in);
|
||||
}
|
||||
|
||||
static void tpd_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
in->ops.hdmi->audio_disable(in);
|
||||
}
|
||||
|
||||
static int tpd_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.hdmi->audio_start(in);
|
||||
}
|
||||
|
||||
static void tpd_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
in->ops.hdmi->audio_stop(in);
|
||||
}
|
||||
|
||||
static bool tpd_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.hdmi->audio_supported(in);
|
||||
}
|
||||
|
||||
static int tpd_audio_config(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.hdmi->audio_config(in, audio);
|
||||
}
|
||||
|
||||
static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
|
||||
.connect = tpd_connect,
|
||||
.disconnect = tpd_disconnect,
|
||||
|
||||
.enable = tpd_enable,
|
||||
.disable = tpd_disable,
|
||||
|
||||
.check_timings = tpd_check_timings,
|
||||
.set_timings = tpd_set_timings,
|
||||
.get_timings = tpd_get_timings,
|
||||
|
||||
.read_edid = tpd_read_edid,
|
||||
.detect = tpd_detect,
|
||||
|
||||
.audio_enable = tpd_audio_enable,
|
||||
.audio_disable = tpd_audio_disable,
|
||||
.audio_start = tpd_audio_start,
|
||||
.audio_stop = tpd_audio_stop,
|
||||
.audio_supported = tpd_audio_supported,
|
||||
.audio_config = tpd_audio_config,
|
||||
};
|
||||
|
||||
static int tpd_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct encoder_tpd12s015_platform_data *pdata;
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
ddata->ct_cp_hpd_gpio = pdata->ct_cp_hpd_gpio;
|
||||
ddata->ls_oe_gpio = pdata->ls_oe_gpio;
|
||||
ddata->hpd_gpio = pdata->hpd_gpio;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *in, *dssdev;
|
||||
struct panel_drv_data *ddata;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
init_completion(&ddata->hpd_completion);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = tpd_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->ls_oe_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "hdmi_ls_oe");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
|
||||
GPIOF_DIR_IN, "hdmi_hpd");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
|
||||
r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio),
|
||||
NULL, tpd_hpd_irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT, "hpd", ddata);
|
||||
if (r)
|
||||
goto err_irq;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->ops.hdmi = &tpd_hdmi_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
|
||||
in = ddata->in;
|
||||
|
||||
r = omapdss_register_output(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register output\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_reg:
|
||||
err_irq:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit tpd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_output(&ddata->dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_enabled(dssdev));
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
tpd_disable(dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_connected(dssdev));
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
tpd_disconnect(dssdev, dssdev->device);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tpd_driver = {
|
||||
.probe = tpd_probe,
|
||||
.remove = __exit_p(tpd_remove),
|
||||
.driver = {
|
||||
.name = "tpd12s015",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(tpd_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("TPD12S015 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Generic MIPI DPI Panel Driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
int data_lines;
|
||||
|
||||
struct omap_video_timings videomode;
|
||||
|
||||
int backlight_gpio;
|
||||
int enable_gpio;
|
||||
};
|
||||
|
||||
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
|
||||
|
||||
static int panel_dpi_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.dpi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dpi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int panel_dpi_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.dpi->set_data_lines(in, ddata->data_lines);
|
||||
in->ops.dpi->set_timings(in, &ddata->videomode);
|
||||
|
||||
r = in->ops.dpi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->enable_gpio))
|
||||
gpio_set_value_cansleep(ddata->enable_gpio, 1);
|
||||
|
||||
if (gpio_is_valid(ddata->backlight_gpio))
|
||||
gpio_set_value_cansleep(ddata->backlight_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void panel_dpi_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(ddata->enable_gpio))
|
||||
gpio_set_value_cansleep(ddata->enable_gpio, 0);
|
||||
|
||||
if (gpio_is_valid(ddata->backlight_gpio))
|
||||
gpio_set_value_cansleep(ddata->backlight_gpio, 0);
|
||||
|
||||
in->ops.dpi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->videomode = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.dpi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->videomode;
|
||||
}
|
||||
|
||||
static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.dpi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver panel_dpi_ops = {
|
||||
.connect = panel_dpi_connect,
|
||||
.disconnect = panel_dpi_disconnect,
|
||||
|
||||
.enable = panel_dpi_enable,
|
||||
.disable = panel_dpi_disable,
|
||||
|
||||
.set_timings = panel_dpi_set_timings,
|
||||
.get_timings = panel_dpi_get_timings,
|
||||
.check_timings = panel_dpi_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
static int panel_dpi_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
const struct panel_dpi_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
struct videomode vm;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
videomode_from_timing(pdata->display_timing, &vm);
|
||||
videomode_to_omap_video_timings(&vm, &ddata->videomode);
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
ddata->enable_gpio = pdata->enable_gpio;
|
||||
ddata->backlight_gpio = pdata->backlight_gpio;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panel_dpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = panel_dpi_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->enable_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->enable_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "panel enable");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->backlight_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "panel backlight");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->driver = &panel_dpi_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = ddata->videomode;
|
||||
dssdev->phy.dpi.data_lines = ddata->data_lines;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit panel_dpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_display(dssdev);
|
||||
|
||||
panel_dpi_disable(dssdev);
|
||||
panel_dpi_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver panel_dpi_driver = {
|
||||
.probe = panel_dpi_probe,
|
||||
.remove = __exit_p(panel_dpi_remove),
|
||||
.driver = {
|
||||
.name = "panel-dpi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(panel_dpi_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
|
||||
MODULE_LICENSE("GPL");
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* LG.Philips LB035Q02 LCD Panel driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
* Based on a driver by: Steve Sakoman <steve@sakoman.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
static struct omap_video_timings lb035q02_timings = {
|
||||
.x_res = 320,
|
||||
.y_res = 240,
|
||||
|
||||
.pixel_clock = 6500,
|
||||
|
||||
.hsw = 2,
|
||||
.hfp = 20,
|
||||
.hbp = 68,
|
||||
|
||||
.vsw = 2,
|
||||
.vfp = 4,
|
||||
.vbp = 18,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
|
||||
.de_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
|
||||
};
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
struct spi_device *spi;
|
||||
|
||||
int data_lines;
|
||||
|
||||
struct omap_video_timings videomode;
|
||||
|
||||
int reset_gpio;
|
||||
int backlight_gpio;
|
||||
int enable_gpio;
|
||||
};
|
||||
|
||||
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
|
||||
|
||||
static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val)
|
||||
{
|
||||
struct spi_message msg;
|
||||
struct spi_transfer index_xfer = {
|
||||
.len = 3,
|
||||
.cs_change = 1,
|
||||
};
|
||||
struct spi_transfer value_xfer = {
|
||||
.len = 3,
|
||||
};
|
||||
u8 buffer[16];
|
||||
|
||||
spi_message_init(&msg);
|
||||
|
||||
/* register index */
|
||||
buffer[0] = 0x70;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = reg & 0x7f;
|
||||
index_xfer.tx_buf = buffer;
|
||||
spi_message_add_tail(&index_xfer, &msg);
|
||||
|
||||
/* register value */
|
||||
buffer[4] = 0x72;
|
||||
buffer[5] = val >> 8;
|
||||
buffer[6] = val;
|
||||
value_xfer.tx_buf = buffer + 4;
|
||||
spi_message_add_tail(&value_xfer, &msg);
|
||||
|
||||
return spi_sync(spi, &msg);
|
||||
}
|
||||
|
||||
static void init_lb035q02_panel(struct spi_device *spi)
|
||||
{
|
||||
/* Init sequence from page 28 of the lb035q02 spec */
|
||||
lb035q02_write_reg(spi, 0x01, 0x6300);
|
||||
lb035q02_write_reg(spi, 0x02, 0x0200);
|
||||
lb035q02_write_reg(spi, 0x03, 0x0177);
|
||||
lb035q02_write_reg(spi, 0x04, 0x04c7);
|
||||
lb035q02_write_reg(spi, 0x05, 0xffc0);
|
||||
lb035q02_write_reg(spi, 0x06, 0xe806);
|
||||
lb035q02_write_reg(spi, 0x0a, 0x4008);
|
||||
lb035q02_write_reg(spi, 0x0b, 0x0000);
|
||||
lb035q02_write_reg(spi, 0x0d, 0x0030);
|
||||
lb035q02_write_reg(spi, 0x0e, 0x2800);
|
||||
lb035q02_write_reg(spi, 0x0f, 0x0000);
|
||||
lb035q02_write_reg(spi, 0x16, 0x9f80);
|
||||
lb035q02_write_reg(spi, 0x17, 0x0a0f);
|
||||
lb035q02_write_reg(spi, 0x1e, 0x00c1);
|
||||
lb035q02_write_reg(spi, 0x30, 0x0300);
|
||||
lb035q02_write_reg(spi, 0x31, 0x0007);
|
||||
lb035q02_write_reg(spi, 0x32, 0x0000);
|
||||
lb035q02_write_reg(spi, 0x33, 0x0000);
|
||||
lb035q02_write_reg(spi, 0x34, 0x0707);
|
||||
lb035q02_write_reg(spi, 0x35, 0x0004);
|
||||
lb035q02_write_reg(spi, 0x36, 0x0302);
|
||||
lb035q02_write_reg(spi, 0x37, 0x0202);
|
||||
lb035q02_write_reg(spi, 0x3a, 0x0a0d);
|
||||
lb035q02_write_reg(spi, 0x3b, 0x0806);
|
||||
}
|
||||
|
||||
static int lb035q02_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.dpi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
init_lb035q02_panel(ddata->spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lb035q02_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dpi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int lb035q02_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.dpi->set_data_lines(in, ddata->data_lines);
|
||||
in->ops.dpi->set_timings(in, &ddata->videomode);
|
||||
|
||||
r = in->ops.dpi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->enable_gpio))
|
||||
gpio_set_value_cansleep(ddata->enable_gpio, 1);
|
||||
|
||||
if (gpio_is_valid(ddata->backlight_gpio))
|
||||
gpio_set_value_cansleep(ddata->backlight_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lb035q02_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(ddata->enable_gpio))
|
||||
gpio_set_value_cansleep(ddata->enable_gpio, 0);
|
||||
|
||||
if (gpio_is_valid(ddata->backlight_gpio))
|
||||
gpio_set_value_cansleep(ddata->backlight_gpio, 0);
|
||||
|
||||
in->ops.dpi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void lb035q02_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->videomode = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.dpi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void lb035q02_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->videomode;
|
||||
}
|
||||
|
||||
static int lb035q02_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.dpi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver lb035q02_ops = {
|
||||
.connect = lb035q02_connect,
|
||||
.disconnect = lb035q02_disconnect,
|
||||
|
||||
.enable = lb035q02_enable,
|
||||
.disable = lb035q02_disable,
|
||||
|
||||
.set_timings = lb035q02_set_timings,
|
||||
.get_timings = lb035q02_get_timings,
|
||||
.check_timings = lb035q02_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
static int lb035q02_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_lb035q02_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
ddata->enable_gpio = pdata->enable_gpio;
|
||||
ddata->backlight_gpio = pdata->backlight_gpio;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lb035q02_panel_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&spi->dev, ddata);
|
||||
|
||||
ddata->spi = spi;
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = lb035q02_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->enable_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev, ddata->enable_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "panel enable");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->backlight_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "panel backlight");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
ddata->videomode = lb035q02_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->dev = &spi->dev;
|
||||
dssdev->driver = &lb035q02_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = ddata->videomode;
|
||||
dssdev->phy.dpi.data_lines = ddata->data_lines;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&spi->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int lb035q02_panel_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_display(dssdev);
|
||||
|
||||
lb035q02_disable(dssdev);
|
||||
lb035q02_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver lb035q02_spi_driver = {
|
||||
.probe = lb035q02_panel_spi_probe,
|
||||
.remove = lb035q02_panel_spi_remove,
|
||||
.driver = {
|
||||
.name = "panel_lgphilips_lb035q02",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_spi_driver(lb035q02_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* NEC NL8048HL11 Panel driver
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments Inc.
|
||||
* Author: Erik Gilling <konkers@android.com>
|
||||
* Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
struct omap_video_timings videomode;
|
||||
|
||||
int data_lines;
|
||||
|
||||
int res_gpio;
|
||||
int qvga_gpio;
|
||||
|
||||
struct spi_device *spi;
|
||||
};
|
||||
|
||||
#define LCD_XRES 800
|
||||
#define LCD_YRES 480
|
||||
/*
|
||||
* NEC PIX Clock Ratings
|
||||
* MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz
|
||||
*/
|
||||
#define LCD_PIXEL_CLOCK 23800
|
||||
|
||||
static const struct {
|
||||
unsigned char addr;
|
||||
unsigned char dat;
|
||||
} nec_8048_init_seq[] = {
|
||||
{ 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 },
|
||||
{ 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 },
|
||||
{ 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 },
|
||||
{ 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F },
|
||||
{ 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F },
|
||||
{ 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F },
|
||||
{ 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F },
|
||||
{ 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 },
|
||||
{ 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 },
|
||||
{ 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C },
|
||||
{ 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 },
|
||||
{ 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 },
|
||||
{ 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 },
|
||||
{ 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 },
|
||||
{ 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC },
|
||||
{ 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 },
|
||||
{ 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 },
|
||||
{ 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 },
|
||||
};
|
||||
|
||||
static const struct omap_video_timings nec_8048_panel_timings = {
|
||||
.x_res = LCD_XRES,
|
||||
.y_res = LCD_YRES,
|
||||
.pixel_clock = LCD_PIXEL_CLOCK,
|
||||
.hfp = 6,
|
||||
.hsw = 1,
|
||||
.hbp = 4,
|
||||
.vfp = 3,
|
||||
.vsw = 1,
|
||||
.vbp = 4,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
|
||||
.de_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
|
||||
};
|
||||
|
||||
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
|
||||
|
||||
static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr,
|
||||
unsigned char reg_data)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int cmd = 0, data = 0;
|
||||
|
||||
cmd = 0x0000 | reg_addr; /* register address write */
|
||||
data = 0x0100 | reg_data; /* register data write */
|
||||
data = (cmd << 16) | data;
|
||||
|
||||
ret = spi_write(spi, (unsigned char *)&data, 4);
|
||||
if (ret)
|
||||
pr_err("error in spi_write %x\n", data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int init_nec_8048_wvga_lcd(struct spi_device *spi)
|
||||
{
|
||||
unsigned int i;
|
||||
/* Initialization Sequence */
|
||||
/* nec_8048_spi_send(spi, REG, VAL) */
|
||||
for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++)
|
||||
nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
|
||||
nec_8048_init_seq[i].dat);
|
||||
udelay(20);
|
||||
nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
|
||||
nec_8048_init_seq[i].dat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nec_8048_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.dpi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nec_8048_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dpi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int nec_8048_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.dpi->set_data_lines(in, ddata->data_lines);
|
||||
in->ops.dpi->set_timings(in, &ddata->videomode);
|
||||
|
||||
r = in->ops.dpi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->res_gpio))
|
||||
gpio_set_value_cansleep(ddata->res_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nec_8048_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(ddata->res_gpio))
|
||||
gpio_set_value_cansleep(ddata->res_gpio, 0);
|
||||
|
||||
in->ops.dpi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void nec_8048_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->videomode = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.dpi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void nec_8048_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->videomode;
|
||||
}
|
||||
|
||||
static int nec_8048_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.dpi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver nec_8048_ops = {
|
||||
.connect = nec_8048_connect,
|
||||
.disconnect = nec_8048_disconnect,
|
||||
|
||||
.enable = nec_8048_enable,
|
||||
.disable = nec_8048_disable,
|
||||
|
||||
.set_timings = nec_8048_set_timings,
|
||||
.get_timings = nec_8048_get_timings,
|
||||
.check_timings = nec_8048_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
|
||||
static int nec_8048_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_nec_nl8048hl11_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
ddata->qvga_gpio = pdata->qvga_gpio;
|
||||
ddata->res_gpio = pdata->res_gpio;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nec_8048_probe(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
dev_dbg(&spi->dev, "%s\n", __func__);
|
||||
|
||||
spi->mode = SPI_MODE_0;
|
||||
spi->bits_per_word = 32;
|
||||
|
||||
r = spi_setup(spi);
|
||||
if (r < 0) {
|
||||
dev_err(&spi->dev, "spi_setup failed: %d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
init_nec_8048_wvga_lcd(spi);
|
||||
|
||||
ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&spi->dev, ddata);
|
||||
|
||||
ddata->spi = spi;
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = nec_8048_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->qvga_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "lcd QVGA");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->res_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev, ddata->res_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd RES");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
ddata->videomode = nec_8048_panel_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->dev = &spi->dev;
|
||||
dssdev->driver = &nec_8048_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = ddata->videomode;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&spi->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int nec_8048_remove(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
|
||||
|
||||
omapdss_unregister_display(dssdev);
|
||||
|
||||
nec_8048_disable(dssdev);
|
||||
nec_8048_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int nec_8048_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
nec_8048_spi_send(spi, 2, 0x01);
|
||||
mdelay(40);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nec_8048_resume(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/* reinitialize the panel */
|
||||
spi_setup(spi);
|
||||
nec_8048_spi_send(spi, 2, 0x00);
|
||||
init_nec_8048_wvga_lcd(spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend,
|
||||
nec_8048_resume);
|
||||
#define NEC_8048_PM_OPS (&nec_8048_pm_ops)
|
||||
#else
|
||||
#define NEC_8048_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct spi_driver nec_8048_driver = {
|
||||
.driver = {
|
||||
.name = "panel-nec-nl8048hl11",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = NEC_8048_PM_OPS,
|
||||
},
|
||||
.probe = nec_8048_probe,
|
||||
.remove = nec_8048_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(nec_8048_driver);
|
||||
|
||||
MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
|
||||
MODULE_DESCRIPTION("NEC-NL8048HL11 Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* LCD panel driver for Sharp LS037V7DW01
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
int data_lines;
|
||||
|
||||
struct omap_video_timings videomode;
|
||||
|
||||
int resb_gpio;
|
||||
int ini_gpio;
|
||||
int mo_gpio;
|
||||
int lr_gpio;
|
||||
int ud_gpio;
|
||||
};
|
||||
|
||||
static const struct omap_video_timings sharp_ls_timings = {
|
||||
.x_res = 480,
|
||||
.y_res = 640,
|
||||
|
||||
.pixel_clock = 19200,
|
||||
|
||||
.hsw = 2,
|
||||
.hfp = 1,
|
||||
.hbp = 28,
|
||||
|
||||
.vsw = 1,
|
||||
.vfp = 1,
|
||||
.vbp = 1,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
|
||||
.de_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
|
||||
};
|
||||
|
||||
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
|
||||
|
||||
static int sharp_ls_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.dpi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sharp_ls_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dpi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int sharp_ls_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.dpi->set_data_lines(in, ddata->data_lines);
|
||||
in->ops.dpi->set_timings(in, &ddata->videomode);
|
||||
|
||||
r = in->ops.dpi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* wait couple of vsyncs until enabling the LCD */
|
||||
msleep(50);
|
||||
|
||||
if (gpio_is_valid(ddata->resb_gpio))
|
||||
gpio_set_value_cansleep(ddata->resb_gpio, 1);
|
||||
|
||||
if (gpio_is_valid(ddata->ini_gpio))
|
||||
gpio_set_value_cansleep(ddata->ini_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sharp_ls_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(ddata->ini_gpio))
|
||||
gpio_set_value_cansleep(ddata->ini_gpio, 0);
|
||||
|
||||
if (gpio_is_valid(ddata->resb_gpio))
|
||||
gpio_set_value_cansleep(ddata->resb_gpio, 0);
|
||||
|
||||
/* wait at least 5 vsyncs after disabling the LCD */
|
||||
|
||||
msleep(100);
|
||||
|
||||
in->ops.dpi->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void sharp_ls_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->videomode = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.dpi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->videomode;
|
||||
}
|
||||
|
||||
static int sharp_ls_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.dpi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver sharp_ls_ops = {
|
||||
.connect = sharp_ls_connect,
|
||||
.disconnect = sharp_ls_disconnect,
|
||||
|
||||
.enable = sharp_ls_enable,
|
||||
.disable = sharp_ls_disable,
|
||||
|
||||
.set_timings = sharp_ls_set_timings,
|
||||
.get_timings = sharp_ls_get_timings,
|
||||
.check_timings = sharp_ls_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
static int sharp_ls_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
const struct panel_sharp_ls037v7dw01_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
ddata->resb_gpio = pdata->resb_gpio;
|
||||
ddata->ini_gpio = pdata->ini_gpio;
|
||||
ddata->mo_gpio = pdata->mo_gpio;
|
||||
ddata->lr_gpio = pdata->lr_gpio;
|
||||
ddata->ud_gpio = pdata->ud_gpio;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_ls_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = sharp_ls_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->mo_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->mo_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd MO");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->lr_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->lr_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "lcd LR");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->ud_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->ud_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "lcd UD");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->resb_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->resb_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd RESB");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->ini_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->ini_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd INI");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
ddata->videomode = sharp_ls_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->driver = &sharp_ls_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = ddata->videomode;
|
||||
dssdev->phy.dpi.data_lines = ddata->data_lines;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit sharp_ls_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_display(dssdev);
|
||||
|
||||
sharp_ls_disable(dssdev);
|
||||
sharp_ls_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver sharp_ls_driver = {
|
||||
.probe = sharp_ls_probe,
|
||||
.remove = __exit_p(sharp_ls_remove),
|
||||
.driver = {
|
||||
.name = "panel-sharp-ls037v7dw01",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(sharp_ls_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,865 @@
|
|||
/*
|
||||
* Sony ACX565AKM LCD Panel driver
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*
|
||||
* Original Driver Author: Imre Deak <imre.deak@nokia.com>
|
||||
* Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
* Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#define MIPID_CMD_READ_DISP_ID 0x04
|
||||
#define MIPID_CMD_READ_RED 0x06
|
||||
#define MIPID_CMD_READ_GREEN 0x07
|
||||
#define MIPID_CMD_READ_BLUE 0x08
|
||||
#define MIPID_CMD_READ_DISP_STATUS 0x09
|
||||
#define MIPID_CMD_RDDSDR 0x0F
|
||||
#define MIPID_CMD_SLEEP_IN 0x10
|
||||
#define MIPID_CMD_SLEEP_OUT 0x11
|
||||
#define MIPID_CMD_DISP_OFF 0x28
|
||||
#define MIPID_CMD_DISP_ON 0x29
|
||||
#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
|
||||
#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
|
||||
#define MIPID_CMD_WRITE_CTRL_DISP 0x53
|
||||
|
||||
#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
|
||||
#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
|
||||
#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
|
||||
#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
|
||||
|
||||
#define MIPID_CMD_READ_CTRL_DISP 0x54
|
||||
#define MIPID_CMD_WRITE_CABC 0x55
|
||||
#define MIPID_CMD_READ_CABC 0x56
|
||||
|
||||
#define MIPID_VER_LPH8923 3
|
||||
#define MIPID_VER_LS041Y3 4
|
||||
#define MIPID_VER_L4F00311 8
|
||||
#define MIPID_VER_ACX565AKM 9
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
int reset_gpio;
|
||||
int datapairs;
|
||||
|
||||
struct omap_video_timings videomode;
|
||||
|
||||
char *name;
|
||||
int enabled;
|
||||
int model;
|
||||
int revision;
|
||||
u8 display_id[3];
|
||||
unsigned has_bc:1;
|
||||
unsigned has_cabc:1;
|
||||
unsigned cabc_mode;
|
||||
unsigned long hw_guard_end; /* next value of jiffies
|
||||
when we can issue the
|
||||
next sleep in/out command */
|
||||
unsigned long hw_guard_wait; /* max guard time in jiffies */
|
||||
|
||||
struct spi_device *spi;
|
||||
struct mutex mutex;
|
||||
|
||||
struct backlight_device *bl_dev;
|
||||
};
|
||||
|
||||
static const struct omap_video_timings acx565akm_panel_timings = {
|
||||
.x_res = 800,
|
||||
.y_res = 480,
|
||||
.pixel_clock = 24000,
|
||||
.hfp = 28,
|
||||
.hsw = 4,
|
||||
.hbp = 24,
|
||||
.vfp = 3,
|
||||
.vsw = 3,
|
||||
.vbp = 4,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
|
||||
.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
|
||||
.de_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
|
||||
};
|
||||
|
||||
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
|
||||
|
||||
static void acx565akm_transfer(struct panel_drv_data *ddata, int cmd,
|
||||
const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
|
||||
{
|
||||
struct spi_message m;
|
||||
struct spi_transfer *x, xfer[5];
|
||||
int r;
|
||||
|
||||
BUG_ON(ddata->spi == NULL);
|
||||
|
||||
spi_message_init(&m);
|
||||
|
||||
memset(xfer, 0, sizeof(xfer));
|
||||
x = &xfer[0];
|
||||
|
||||
cmd &= 0xff;
|
||||
x->tx_buf = &cmd;
|
||||
x->bits_per_word = 9;
|
||||
x->len = 2;
|
||||
|
||||
if (rlen > 1 && wlen == 0) {
|
||||
/*
|
||||
* Between the command and the response data there is a
|
||||
* dummy clock cycle. Add an extra bit after the command
|
||||
* word to account for this.
|
||||
*/
|
||||
x->bits_per_word = 10;
|
||||
cmd <<= 1;
|
||||
}
|
||||
spi_message_add_tail(x, &m);
|
||||
|
||||
if (wlen) {
|
||||
x++;
|
||||
x->tx_buf = wbuf;
|
||||
x->len = wlen;
|
||||
x->bits_per_word = 9;
|
||||
spi_message_add_tail(x, &m);
|
||||
}
|
||||
|
||||
if (rlen) {
|
||||
x++;
|
||||
x->rx_buf = rbuf;
|
||||
x->len = rlen;
|
||||
spi_message_add_tail(x, &m);
|
||||
}
|
||||
|
||||
r = spi_sync(ddata->spi, &m);
|
||||
if (r < 0)
|
||||
dev_dbg(&ddata->spi->dev, "spi_sync %d\n", r);
|
||||
}
|
||||
|
||||
static inline void acx565akm_cmd(struct panel_drv_data *ddata, int cmd)
|
||||
{
|
||||
acx565akm_transfer(ddata, cmd, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void acx565akm_write(struct panel_drv_data *ddata,
|
||||
int reg, const u8 *buf, int len)
|
||||
{
|
||||
acx565akm_transfer(ddata, reg, buf, len, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void acx565akm_read(struct panel_drv_data *ddata,
|
||||
int reg, u8 *buf, int len)
|
||||
{
|
||||
acx565akm_transfer(ddata, reg, NULL, 0, buf, len);
|
||||
}
|
||||
|
||||
static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
|
||||
{
|
||||
ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
|
||||
ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
|
||||
}
|
||||
|
||||
static void hw_guard_wait(struct panel_drv_data *ddata)
|
||||
{
|
||||
unsigned long wait = ddata->hw_guard_end - jiffies;
|
||||
|
||||
if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout(wait);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_sleep_mode(struct panel_drv_data *ddata, int on)
|
||||
{
|
||||
int cmd;
|
||||
|
||||
if (on)
|
||||
cmd = MIPID_CMD_SLEEP_IN;
|
||||
else
|
||||
cmd = MIPID_CMD_SLEEP_OUT;
|
||||
/*
|
||||
* We have to keep 120msec between sleep in/out commands.
|
||||
* (8.2.15, 8.2.16).
|
||||
*/
|
||||
hw_guard_wait(ddata);
|
||||
acx565akm_cmd(ddata, cmd);
|
||||
hw_guard_start(ddata, 120);
|
||||
}
|
||||
|
||||
static void set_display_state(struct panel_drv_data *ddata, int enabled)
|
||||
{
|
||||
int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
|
||||
|
||||
acx565akm_cmd(ddata, cmd);
|
||||
}
|
||||
|
||||
static int panel_enabled(struct panel_drv_data *ddata)
|
||||
{
|
||||
u32 disp_status;
|
||||
int enabled;
|
||||
|
||||
acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS,
|
||||
(u8 *)&disp_status, 4);
|
||||
disp_status = __be32_to_cpu(disp_status);
|
||||
enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
|
||||
dev_dbg(&ddata->spi->dev,
|
||||
"LCD panel %senabled by bootloader (status 0x%04x)\n",
|
||||
enabled ? "" : "not ", disp_status);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static int panel_detect(struct panel_drv_data *ddata)
|
||||
{
|
||||
acx565akm_read(ddata, MIPID_CMD_READ_DISP_ID, ddata->display_id, 3);
|
||||
dev_dbg(&ddata->spi->dev, "MIPI display ID: %02x%02x%02x\n",
|
||||
ddata->display_id[0],
|
||||
ddata->display_id[1],
|
||||
ddata->display_id[2]);
|
||||
|
||||
switch (ddata->display_id[0]) {
|
||||
case 0x10:
|
||||
ddata->model = MIPID_VER_ACX565AKM;
|
||||
ddata->name = "acx565akm";
|
||||
ddata->has_bc = 1;
|
||||
ddata->has_cabc = 1;
|
||||
break;
|
||||
case 0x29:
|
||||
ddata->model = MIPID_VER_L4F00311;
|
||||
ddata->name = "l4f00311";
|
||||
break;
|
||||
case 0x45:
|
||||
ddata->model = MIPID_VER_LPH8923;
|
||||
ddata->name = "lph8923";
|
||||
break;
|
||||
case 0x83:
|
||||
ddata->model = MIPID_VER_LS041Y3;
|
||||
ddata->name = "ls041y3";
|
||||
break;
|
||||
default:
|
||||
ddata->name = "unknown";
|
||||
dev_err(&ddata->spi->dev, "invalid display ID\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->revision = ddata->display_id[1];
|
||||
|
||||
dev_info(&ddata->spi->dev, "omapfb: %s rev %02x LCD detected\n",
|
||||
ddata->name, ddata->revision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------Backlight Control-------------------------*/
|
||||
|
||||
static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable)
|
||||
{
|
||||
u16 ctrl;
|
||||
|
||||
acx565akm_read(ddata, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
|
||||
if (enable) {
|
||||
ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
|
||||
CTRL_DISP_BACKLIGHT_ON;
|
||||
} else {
|
||||
ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
|
||||
CTRL_DISP_BACKLIGHT_ON);
|
||||
}
|
||||
|
||||
ctrl |= 1 << 8;
|
||||
acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
|
||||
}
|
||||
|
||||
static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode)
|
||||
{
|
||||
u16 cabc_ctrl;
|
||||
|
||||
ddata->cabc_mode = mode;
|
||||
if (!ddata->enabled)
|
||||
return;
|
||||
cabc_ctrl = 0;
|
||||
acx565akm_read(ddata, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
|
||||
cabc_ctrl &= ~3;
|
||||
cabc_ctrl |= (1 << 8) | (mode & 3);
|
||||
acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
|
||||
}
|
||||
|
||||
static unsigned get_cabc_mode(struct panel_drv_data *ddata)
|
||||
{
|
||||
return ddata->cabc_mode;
|
||||
}
|
||||
|
||||
static unsigned get_hw_cabc_mode(struct panel_drv_data *ddata)
|
||||
{
|
||||
u8 cabc_ctrl;
|
||||
|
||||
acx565akm_read(ddata, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
|
||||
return cabc_ctrl & 3;
|
||||
}
|
||||
|
||||
static void acx565akm_set_brightness(struct panel_drv_data *ddata, int level)
|
||||
{
|
||||
int bv;
|
||||
|
||||
bv = level | (1 << 8);
|
||||
acx565akm_write(ddata, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
|
||||
|
||||
if (level)
|
||||
enable_backlight_ctrl(ddata, 1);
|
||||
else
|
||||
enable_backlight_ctrl(ddata, 0);
|
||||
}
|
||||
|
||||
static int acx565akm_get_actual_brightness(struct panel_drv_data *ddata)
|
||||
{
|
||||
u8 bv;
|
||||
|
||||
acx565akm_read(ddata, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
|
||||
static int acx565akm_bl_update_status(struct backlight_device *dev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
|
||||
int r;
|
||||
int level;
|
||||
|
||||
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
|
||||
|
||||
mutex_lock(&ddata->mutex);
|
||||
|
||||
if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
|
||||
dev->props.power == FB_BLANK_UNBLANK)
|
||||
level = dev->props.brightness;
|
||||
else
|
||||
level = 0;
|
||||
|
||||
r = 0;
|
||||
if (ddata->has_bc)
|
||||
acx565akm_set_brightness(ddata, level);
|
||||
else
|
||||
r = -ENODEV;
|
||||
|
||||
mutex_unlock(&ddata->mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int acx565akm_bl_get_intensity(struct backlight_device *dev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
|
||||
|
||||
dev_dbg(&dev->dev, "%s\n", __func__);
|
||||
|
||||
if (!ddata->has_bc)
|
||||
return -ENODEV;
|
||||
|
||||
if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
|
||||
dev->props.power == FB_BLANK_UNBLANK) {
|
||||
if (ddata->has_bc)
|
||||
return acx565akm_get_actual_brightness(ddata);
|
||||
else
|
||||
return dev->props.brightness;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct backlight_ops acx565akm_bl_ops = {
|
||||
.get_brightness = acx565akm_bl_get_intensity,
|
||||
.update_status = acx565akm_bl_update_status,
|
||||
};
|
||||
|
||||
/*--------------------Auto Brightness control via Sysfs---------------------*/
|
||||
|
||||
static const char * const cabc_modes[] = {
|
||||
"off", /* always used when CABC is not supported */
|
||||
"ui",
|
||||
"still-image",
|
||||
"moving-image",
|
||||
};
|
||||
|
||||
static ssize_t show_cabc_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
const char *mode_str;
|
||||
int mode;
|
||||
int len;
|
||||
|
||||
if (!ddata->has_cabc)
|
||||
mode = 0;
|
||||
else
|
||||
mode = get_cabc_mode(ddata);
|
||||
mode_str = "unknown";
|
||||
if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
|
||||
mode_str = cabc_modes[mode];
|
||||
len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
|
||||
|
||||
return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
|
||||
}
|
||||
|
||||
static ssize_t store_cabc_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
|
||||
const char *mode_str = cabc_modes[i];
|
||||
int cmp_len = strlen(mode_str);
|
||||
|
||||
if (count > 0 && buf[count - 1] == '\n')
|
||||
count--;
|
||||
if (count != cmp_len)
|
||||
continue;
|
||||
|
||||
if (strncmp(buf, mode_str, cmp_len) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(cabc_modes))
|
||||
return -EINVAL;
|
||||
|
||||
if (!ddata->has_cabc && i != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ddata->mutex);
|
||||
set_cabc_mode(ddata, i);
|
||||
mutex_unlock(&ddata->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_cabc_available_modes(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
int len;
|
||||
int i;
|
||||
|
||||
if (!ddata->has_cabc)
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
|
||||
|
||||
for (i = 0, len = 0;
|
||||
len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
|
||||
len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
|
||||
i ? " " : "", cabc_modes[i],
|
||||
i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
|
||||
|
||||
return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
|
||||
show_cabc_mode, store_cabc_mode);
|
||||
static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
|
||||
show_cabc_available_modes, NULL);
|
||||
|
||||
static struct attribute *bldev_attrs[] = {
|
||||
&dev_attr_cabc_mode.attr,
|
||||
&dev_attr_cabc_available_modes.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group bldev_attr_group = {
|
||||
.attrs = bldev_attrs,
|
||||
};
|
||||
|
||||
static int acx565akm_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.sdi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acx565akm_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.sdi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
|
||||
|
||||
in->ops.sdi->set_timings(in, &ddata->videomode);
|
||||
in->ops.sdi->set_datapairs(in, ddata->datapairs);
|
||||
|
||||
r = in->ops.sdi->enable(in);
|
||||
if (r) {
|
||||
pr_err("%s sdi enable failed\n", __func__);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*FIXME tweak me */
|
||||
msleep(50);
|
||||
|
||||
if (gpio_is_valid(ddata->reset_gpio))
|
||||
gpio_set_value(ddata->reset_gpio, 1);
|
||||
|
||||
if (ddata->enabled) {
|
||||
dev_dbg(&ddata->spi->dev, "panel already enabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to meet all the following delay requirements:
|
||||
* 1. tRW: reset pulse width 10usec (7.12.1)
|
||||
* 2. tRT: reset cancel time 5msec (7.12.1)
|
||||
* 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
|
||||
* case (7.6.2)
|
||||
* 4. 120msec before the sleep out command (7.12.1)
|
||||
*/
|
||||
msleep(120);
|
||||
|
||||
set_sleep_mode(ddata, 0);
|
||||
ddata->enabled = 1;
|
||||
|
||||
/* 5msec between sleep out and the next command. (8.2.16) */
|
||||
usleep_range(5000, 10000);
|
||||
set_display_state(ddata, 1);
|
||||
set_cabc_mode(ddata, ddata->cabc_mode);
|
||||
|
||||
mutex_unlock(&ddata->mutex);
|
||||
|
||||
return acx565akm_bl_update_status(ddata->bl_dev);
|
||||
}
|
||||
|
||||
static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (!ddata->enabled)
|
||||
return;
|
||||
|
||||
set_display_state(ddata, 0);
|
||||
set_sleep_mode(ddata, 1);
|
||||
ddata->enabled = 0;
|
||||
/*
|
||||
* We have to provide PCLK,HS,VS signals for 2 frames (worst case
|
||||
* ~50msec) after sending the sleep in command and asserting the
|
||||
* reset signal. We probably could assert the reset w/o the delay
|
||||
* but we still delay to avoid possible artifacts. (7.6.1)
|
||||
*/
|
||||
msleep(50);
|
||||
|
||||
if (gpio_is_valid(ddata->reset_gpio))
|
||||
gpio_set_value(ddata->reset_gpio, 0);
|
||||
|
||||
/* FIXME need to tweak this delay */
|
||||
msleep(100);
|
||||
|
||||
in->ops.sdi->disable(in);
|
||||
}
|
||||
|
||||
static int acx565akm_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
int r;
|
||||
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&ddata->mutex);
|
||||
r = acx565akm_panel_power_on(dssdev);
|
||||
mutex_unlock(&ddata->mutex);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acx565akm_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
mutex_lock(&ddata->mutex);
|
||||
acx565akm_panel_power_off(dssdev);
|
||||
mutex_unlock(&ddata->mutex);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void acx565akm_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->videomode = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.sdi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void acx565akm_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->videomode;
|
||||
}
|
||||
|
||||
static int acx565akm_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.sdi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver acx565akm_ops = {
|
||||
.connect = acx565akm_connect,
|
||||
.disconnect = acx565akm_disconnect,
|
||||
|
||||
.enable = acx565akm_enable,
|
||||
.disable = acx565akm_disable,
|
||||
|
||||
.set_timings = acx565akm_set_timings,
|
||||
.get_timings = acx565akm_get_timings,
|
||||
.check_timings = acx565akm_check_timings,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
static int acx565akm_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_acx565akm_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
ddata->reset_gpio = pdata->reset_gpio;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
ddata->in = in;
|
||||
|
||||
ddata->datapairs = pdata->datapairs;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acx565akm_probe(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
struct backlight_device *bldev;
|
||||
int max_brightness, brightness;
|
||||
struct backlight_properties props;
|
||||
int r;
|
||||
|
||||
dev_dbg(&spi->dev, "%s\n", __func__);
|
||||
|
||||
spi->mode = SPI_MODE_3;
|
||||
|
||||
ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&spi->dev, ddata);
|
||||
|
||||
ddata->spi = spi;
|
||||
|
||||
mutex_init(&ddata->mutex);
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = acx565akm_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->reset_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev, ddata->reset_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd reset");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->reset_gpio))
|
||||
gpio_set_value(ddata->reset_gpio, 1);
|
||||
|
||||
/*
|
||||
* After reset we have to wait 5 msec before the first
|
||||
* command can be sent.
|
||||
*/
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
ddata->enabled = panel_enabled(ddata);
|
||||
|
||||
r = panel_detect(ddata);
|
||||
|
||||
if (!ddata->enabled && gpio_is_valid(ddata->reset_gpio))
|
||||
gpio_set_value(ddata->reset_gpio, 0);
|
||||
|
||||
if (r) {
|
||||
dev_err(&spi->dev, "%s panel detect error\n", __func__);
|
||||
goto err_detect;
|
||||
}
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.fb_blank = FB_BLANK_UNBLANK;
|
||||
props.power = FB_BLANK_UNBLANK;
|
||||
props.type = BACKLIGHT_RAW;
|
||||
|
||||
bldev = backlight_device_register("acx565akm", &ddata->spi->dev,
|
||||
ddata, &acx565akm_bl_ops, &props);
|
||||
ddata->bl_dev = bldev;
|
||||
if (ddata->has_cabc) {
|
||||
r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
|
||||
if (r) {
|
||||
dev_err(&bldev->dev,
|
||||
"%s failed to create sysfs files\n", __func__);
|
||||
goto err_sysfs;
|
||||
}
|
||||
ddata->cabc_mode = get_hw_cabc_mode(ddata);
|
||||
}
|
||||
|
||||
max_brightness = 255;
|
||||
|
||||
if (ddata->has_bc)
|
||||
brightness = acx565akm_get_actual_brightness(ddata);
|
||||
else
|
||||
brightness = 0;
|
||||
|
||||
bldev->props.max_brightness = max_brightness;
|
||||
bldev->props.brightness = brightness;
|
||||
|
||||
acx565akm_bl_update_status(bldev);
|
||||
|
||||
|
||||
ddata->videomode = acx565akm_panel_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->dev = &spi->dev;
|
||||
dssdev->driver = &acx565akm_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_SDI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = ddata->videomode;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&spi->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group);
|
||||
err_sysfs:
|
||||
backlight_device_unregister(bldev);
|
||||
err_detect:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int acx565akm_remove(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
|
||||
|
||||
sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group);
|
||||
backlight_device_unregister(ddata->bl_dev);
|
||||
|
||||
omapdss_unregister_display(dssdev);
|
||||
|
||||
acx565akm_disable(dssdev);
|
||||
acx565akm_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver acx565akm_driver = {
|
||||
.driver = {
|
||||
.name = "acx565akm",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = acx565akm_probe,
|
||||
.remove = acx565akm_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(acx565akm_driver);
|
||||
|
||||
MODULE_AUTHOR("Nokia Corporation");
|
||||
MODULE_DESCRIPTION("acx565akm LCD Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,646 @@
|
|||
/*
|
||||
* TPO TD043MTEA1 Panel driver
|
||||
*
|
||||
* Author: Gražvydas Ignotas <notasas@gmail.com>
|
||||
* Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#define TPO_R02_MODE(x) ((x) & 7)
|
||||
#define TPO_R02_MODE_800x480 7
|
||||
#define TPO_R02_NCLK_RISING BIT(3)
|
||||
#define TPO_R02_HSYNC_HIGH BIT(4)
|
||||
#define TPO_R02_VSYNC_HIGH BIT(5)
|
||||
|
||||
#define TPO_R03_NSTANDBY BIT(0)
|
||||
#define TPO_R03_EN_CP_CLK BIT(1)
|
||||
#define TPO_R03_EN_VGL_PUMP BIT(2)
|
||||
#define TPO_R03_EN_PWM BIT(3)
|
||||
#define TPO_R03_DRIVING_CAP_100 BIT(4)
|
||||
#define TPO_R03_EN_PRE_CHARGE BIT(6)
|
||||
#define TPO_R03_SOFTWARE_CTL BIT(7)
|
||||
|
||||
#define TPO_R04_NFLIP_H BIT(0)
|
||||
#define TPO_R04_NFLIP_V BIT(1)
|
||||
#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
|
||||
#define TPO_R04_VGL_FREQ_1H BIT(4)
|
||||
|
||||
#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
|
||||
TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \
|
||||
TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
|
||||
TPO_R03_SOFTWARE_CTL)
|
||||
|
||||
#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
|
||||
TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
|
||||
|
||||
static const u16 tpo_td043_def_gamma[12] = {
|
||||
105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023
|
||||
};
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
struct omap_video_timings videomode;
|
||||
|
||||
int data_lines;
|
||||
|
||||
struct spi_device *spi;
|
||||
struct regulator *vcc_reg;
|
||||
int nreset_gpio;
|
||||
u16 gamma[12];
|
||||
u32 mode;
|
||||
u32 hmirror:1;
|
||||
u32 vmirror:1;
|
||||
u32 powered_on:1;
|
||||
u32 spi_suspended:1;
|
||||
u32 power_on_resume:1;
|
||||
};
|
||||
|
||||
static const struct omap_video_timings tpo_td043_timings = {
|
||||
.x_res = 800,
|
||||
.y_res = 480,
|
||||
|
||||
.pixel_clock = 36000,
|
||||
|
||||
.hsw = 1,
|
||||
.hfp = 68,
|
||||
.hbp = 214,
|
||||
|
||||
.vsw = 1,
|
||||
.vfp = 39,
|
||||
.vbp = 34,
|
||||
|
||||
.vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
|
||||
.data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
|
||||
.de_level = OMAPDSS_SIG_ACTIVE_HIGH,
|
||||
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
|
||||
};
|
||||
|
||||
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
|
||||
|
||||
static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
|
||||
{
|
||||
struct spi_message m;
|
||||
struct spi_transfer xfer;
|
||||
u16 w;
|
||||
int r;
|
||||
|
||||
spi_message_init(&m);
|
||||
|
||||
memset(&xfer, 0, sizeof(xfer));
|
||||
|
||||
w = ((u16)addr << 10) | (1 << 8) | data;
|
||||
xfer.tx_buf = &w;
|
||||
xfer.bits_per_word = 16;
|
||||
xfer.len = 2;
|
||||
spi_message_add_tail(&xfer, &m);
|
||||
|
||||
r = spi_sync(spi, &m);
|
||||
if (r < 0)
|
||||
dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
|
||||
{
|
||||
u8 i, val;
|
||||
|
||||
/* gamma bits [9:8] */
|
||||
for (val = i = 0; i < 4; i++)
|
||||
val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
|
||||
tpo_td043_write(spi, 0x11, val);
|
||||
|
||||
for (val = i = 0; i < 4; i++)
|
||||
val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
|
||||
tpo_td043_write(spi, 0x12, val);
|
||||
|
||||
for (val = i = 0; i < 4; i++)
|
||||
val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
|
||||
tpo_td043_write(spi, 0x13, val);
|
||||
|
||||
/* gamma bits [7:0] */
|
||||
for (val = i = 0; i < 12; i++)
|
||||
tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
|
||||
}
|
||||
|
||||
static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
|
||||
{
|
||||
u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V |
|
||||
TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
|
||||
if (h)
|
||||
reg4 &= ~TPO_R04_NFLIP_H;
|
||||
if (v)
|
||||
reg4 &= ~TPO_R04_NFLIP_V;
|
||||
|
||||
return tpo_td043_write(spi, 4, reg4);
|
||||
}
|
||||
|
||||
static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
ddata->hmirror = enable;
|
||||
return tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
|
||||
ddata->vmirror);
|
||||
}
|
||||
|
||||
static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
return ddata->hmirror;
|
||||
}
|
||||
|
||||
static ssize_t tpo_td043_vmirror_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror);
|
||||
}
|
||||
|
||||
static ssize_t tpo_td043_vmirror_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoint(buf, 0, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = !!val;
|
||||
|
||||
ret = tpo_td043_write_mirror(ddata->spi, ddata->hmirror, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ddata->vmirror = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t tpo_td043_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode);
|
||||
}
|
||||
|
||||
static ssize_t tpo_td043_mode_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
long val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtol(buf, 0, &val);
|
||||
if (ret != 0 || val & ~7)
|
||||
return -EINVAL;
|
||||
|
||||
ddata->mode = val;
|
||||
|
||||
val |= TPO_R02_NCLK_RISING;
|
||||
tpo_td043_write(ddata->spi, 2, val);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t tpo_td043_gamma_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
ssize_t len = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++) {
|
||||
ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
|
||||
ddata->gamma[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret;
|
||||
}
|
||||
buf[len - 1] = '\n';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t tpo_td043_gamma_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
unsigned int g[12];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
|
||||
&g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
|
||||
&g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
|
||||
|
||||
if (ret != 12)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
ddata->gamma[i] = g[i];
|
||||
|
||||
tpo_td043_write_gamma(ddata->spi, ddata->gamma);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
|
||||
tpo_td043_vmirror_show, tpo_td043_vmirror_store);
|
||||
static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
|
||||
tpo_td043_mode_show, tpo_td043_mode_store);
|
||||
static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
|
||||
tpo_td043_gamma_show, tpo_td043_gamma_store);
|
||||
|
||||
static struct attribute *tpo_td043_attrs[] = {
|
||||
&dev_attr_vmirror.attr,
|
||||
&dev_attr_mode.attr,
|
||||
&dev_attr_gamma.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group tpo_td043_attr_group = {
|
||||
.attrs = tpo_td043_attrs,
|
||||
};
|
||||
|
||||
static int tpo_td043_power_on(struct panel_drv_data *ddata)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (ddata->powered_on)
|
||||
return 0;
|
||||
|
||||
r = regulator_enable(ddata->vcc_reg);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* wait for panel to stabilize */
|
||||
msleep(160);
|
||||
|
||||
if (gpio_is_valid(ddata->nreset_gpio))
|
||||
gpio_set_value(ddata->nreset_gpio, 1);
|
||||
|
||||
tpo_td043_write(ddata->spi, 2,
|
||||
TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING);
|
||||
tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL);
|
||||
tpo_td043_write(ddata->spi, 0x20, 0xf0);
|
||||
tpo_td043_write(ddata->spi, 0x21, 0xf0);
|
||||
tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
|
||||
ddata->vmirror);
|
||||
tpo_td043_write_gamma(ddata->spi, ddata->gamma);
|
||||
|
||||
ddata->powered_on = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpo_td043_power_off(struct panel_drv_data *ddata)
|
||||
{
|
||||
if (!ddata->powered_on)
|
||||
return;
|
||||
|
||||
tpo_td043_write(ddata->spi, 3,
|
||||
TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
|
||||
|
||||
if (gpio_is_valid(ddata->nreset_gpio))
|
||||
gpio_set_value(ddata->nreset_gpio, 0);
|
||||
|
||||
/* wait for at least 2 vsyncs before cutting off power */
|
||||
msleep(50);
|
||||
|
||||
tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_STANDBY);
|
||||
|
||||
regulator_disable(ddata->vcc_reg);
|
||||
|
||||
ddata->powered_on = 0;
|
||||
}
|
||||
|
||||
static int tpo_td043_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return 0;
|
||||
|
||||
r = in->ops.dpi->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpo_td043_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dpi->disconnect(in, dssdev);
|
||||
}
|
||||
|
||||
static int tpo_td043_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.dpi->set_data_lines(in, ddata->data_lines);
|
||||
in->ops.dpi->set_timings(in, &ddata->videomode);
|
||||
|
||||
r = in->ops.dpi->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* If we are resuming from system suspend, SPI clocks might not be
|
||||
* enabled yet, so we'll program the LCD from SPI PM resume callback.
|
||||
*/
|
||||
if (!ddata->spi_suspended) {
|
||||
r = tpo_td043_power_on(ddata);
|
||||
if (r) {
|
||||
in->ops.dpi->disable(in);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpo_td043_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
in->ops.dpi->disable(in);
|
||||
|
||||
if (!ddata->spi_suspended)
|
||||
tpo_td043_power_off(ddata);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
ddata->videomode = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.dpi->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*timings = ddata->videomode;
|
||||
}
|
||||
|
||||
static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
return in->ops.dpi->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver tpo_td043_ops = {
|
||||
.connect = tpo_td043_connect,
|
||||
.disconnect = tpo_td043_disconnect,
|
||||
|
||||
.enable = tpo_td043_enable,
|
||||
.disable = tpo_td043_disable,
|
||||
|
||||
.set_timings = tpo_td043_set_timings,
|
||||
.get_timings = tpo_td043_get_timings,
|
||||
.check_timings = tpo_td043_check_timings,
|
||||
|
||||
.set_mirror = tpo_td043_set_hmirror,
|
||||
.get_mirror = tpo_td043_get_hmirror,
|
||||
|
||||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
|
||||
static int tpo_td043_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_tpo_td043mtea1_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
ddata->nreset_gpio = pdata->nreset_gpio;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpo_td043_probe(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
dev_dbg(&spi->dev, "%s\n", __func__);
|
||||
|
||||
spi->bits_per_word = 16;
|
||||
spi->mode = SPI_MODE_0;
|
||||
|
||||
r = spi_setup(spi);
|
||||
if (r < 0) {
|
||||
dev_err(&spi->dev, "spi_setup failed: %d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&spi->dev, ddata);
|
||||
|
||||
ddata->spi = spi;
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = tpo_td043_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->mode = TPO_R02_MODE_800x480;
|
||||
memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma));
|
||||
|
||||
ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc");
|
||||
if (IS_ERR(ddata->vcc_reg)) {
|
||||
dev_err(&spi->dev, "failed to get LCD VCC regulator\n");
|
||||
r = PTR_ERR(ddata->vcc_reg);
|
||||
goto err_regulator;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ddata->nreset_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev,
|
||||
ddata->nreset_gpio, GPIOF_OUT_INIT_LOW,
|
||||
"lcd reset");
|
||||
if (r < 0) {
|
||||
dev_err(&spi->dev, "couldn't request reset GPIO\n");
|
||||
goto err_gpio_req;
|
||||
}
|
||||
}
|
||||
|
||||
r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group);
|
||||
if (r) {
|
||||
dev_err(&spi->dev, "failed to create sysfs files\n");
|
||||
goto err_sysfs;
|
||||
}
|
||||
|
||||
ddata->videomode = tpo_td043_timings;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->dev = &spi->dev;
|
||||
dssdev->driver = &tpo_td043_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->panel.timings = ddata->videomode;
|
||||
|
||||
r = omapdss_register_display(dssdev);
|
||||
if (r) {
|
||||
dev_err(&spi->dev, "Failed to register panel\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
|
||||
err_sysfs:
|
||||
err_gpio_req:
|
||||
err_regulator:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int tpo_td043_remove(struct spi_device *spi)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
|
||||
|
||||
omapdss_unregister_display(dssdev);
|
||||
|
||||
tpo_td043_disable(dssdev);
|
||||
tpo_td043_disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tpo_td043_spi_suspend(struct device *dev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", ddata);
|
||||
|
||||
ddata->power_on_resume = ddata->powered_on;
|
||||
tpo_td043_power_off(ddata);
|
||||
ddata->spi_suspended = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpo_td043_spi_resume(struct device *dev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "tpo_td043_spi_resume\n");
|
||||
|
||||
if (ddata->power_on_resume) {
|
||||
ret = tpo_td043_power_on(ddata);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ddata->spi_suspended = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
|
||||
tpo_td043_spi_suspend, tpo_td043_spi_resume);
|
||||
|
||||
static struct spi_driver tpo_td043_spi_driver = {
|
||||
.driver = {
|
||||
.name = "panel-tpo-td043mtea1",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &tpo_td043_spi_pm,
|
||||
},
|
||||
.probe = tpo_td043_probe,
|
||||
.remove = tpo_td043_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(tpo_td043_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
|
||||
MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,4 +1,4 @@
|
|||
menu "OMAP2/3 Display Device Drivers"
|
||||
menu "OMAP2/3 Display Device Drivers (old device model)"
|
||||
depends on OMAP2_DSS
|
||||
|
||||
config PANEL_GENERIC_DPI
|
||||
|
|
|
@ -510,7 +510,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
|
|||
int max_brightness, brightness;
|
||||
struct backlight_properties props;
|
||||
|
||||
dev_dbg(&dssdev->dev, "%s\n", __func__);
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (!panel_data)
|
||||
return -EINVAL;
|
||||
|
@ -519,7 +519,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
|
|||
dssdev->panel.timings = acx_panel_timings;
|
||||
|
||||
if (gpio_is_valid(panel_data->reset_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, panel_data->reset_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, panel_data->reset_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd reset");
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -538,7 +538,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
r = panel_detect(md);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "%s panel detect error\n", __func__);
|
||||
dev_err(dssdev->dev, "%s panel detect error\n", __func__);
|
||||
if (!md->enabled && gpio_is_valid(panel_data->reset_gpio))
|
||||
gpio_set_value(panel_data->reset_gpio, 0);
|
||||
|
||||
|
@ -593,7 +593,7 @@ static void acx_panel_remove(struct omap_dss_device *dssdev)
|
|||
{
|
||||
struct acx565akm_device *md = &acx_dev;
|
||||
|
||||
dev_dbg(&dssdev->dev, "%s\n", __func__);
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group);
|
||||
backlight_device_unregister(md->bl_dev);
|
||||
mutex_lock(&acx_dev.mutex);
|
||||
|
@ -607,7 +607,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
|
|||
struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "%s\n", __func__);
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return 0;
|
||||
|
@ -667,7 +667,7 @@ static void acx_panel_power_off(struct omap_dss_device *dssdev)
|
|||
struct acx565akm_device *md = &acx_dev;
|
||||
struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
|
||||
|
||||
dev_dbg(&dssdev->dev, "%s\n", __func__);
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return;
|
||||
|
@ -704,7 +704,7 @@ static int acx_panel_enable(struct omap_dss_device *dssdev)
|
|||
{
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "%s\n", __func__);
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
r = acx_panel_power_on(dssdev);
|
||||
|
||||
if (r)
|
||||
|
@ -716,7 +716,7 @@ static int acx_panel_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
static void acx_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "%s\n", __func__);
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
acx_panel_power_off(dssdev);
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
|
|
@ -536,7 +536,7 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
|
|||
{
|
||||
int r, i;
|
||||
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev);
|
||||
struct panel_config *panel_config = drv_data->panel_config;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
|
@ -567,7 +567,7 @@ err0:
|
|||
static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev);
|
||||
struct panel_config *panel_config = drv_data->panel_config;
|
||||
int i;
|
||||
|
||||
|
@ -593,7 +593,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
|
|||
struct panel_drv_data *drv_data = NULL;
|
||||
int i, r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "probe\n");
|
||||
dev_dbg(dssdev->dev, "probe\n");
|
||||
|
||||
if (!panel_data || !panel_data->name)
|
||||
return -EINVAL;
|
||||
|
@ -609,7 +609,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
|
|||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < panel_data->num_gpios; ++i) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i],
|
||||
r = devm_gpio_request_one(dssdev->dev, panel_data->gpios[i],
|
||||
panel_data->gpio_invert[i] ?
|
||||
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
|
||||
"panel gpio");
|
||||
|
@ -619,7 +619,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
dssdev->panel.timings = panel_config->timings;
|
||||
|
||||
drv_data = devm_kzalloc(&dssdev->dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
drv_data = devm_kzalloc(dssdev->dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -628,21 +628,21 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_init(&drv_data->lock);
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, drv_data);
|
||||
dev_set_drvdata(dssdev->dev, drv_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "remove\n");
|
||||
dev_dbg(dssdev->dev, "remove\n");
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, NULL);
|
||||
dev_set_drvdata(dssdev->dev, NULL);
|
||||
}
|
||||
|
||||
static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
mutex_lock(&drv_data->lock);
|
||||
|
@ -660,7 +660,7 @@ err:
|
|||
|
||||
static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&drv_data->lock);
|
||||
|
||||
|
@ -674,7 +674,7 @@ static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
|
|||
static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&drv_data->lock);
|
||||
|
||||
|
@ -688,7 +688,7 @@ static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
|
|||
static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&drv_data->lock);
|
||||
|
||||
|
@ -700,7 +700,7 @@ static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
|
|||
static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
mutex_lock(&drv_data->lock);
|
||||
|
|
|
@ -109,12 +109,12 @@ static int lb035q02_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
dssdev->panel.timings = lb035q02_timings;
|
||||
|
||||
ld = devm_kzalloc(&dssdev->dev, sizeof(*ld), GFP_KERNEL);
|
||||
ld = devm_kzalloc(dssdev->dev, sizeof(*ld), GFP_KERNEL);
|
||||
if (!ld)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < panel_data->num_gpios; ++i) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i],
|
||||
r = devm_gpio_request_one(dssdev->dev, panel_data->gpios[i],
|
||||
panel_data->gpio_invert[i] ?
|
||||
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
|
||||
"panel gpio");
|
||||
|
@ -123,7 +123,7 @@ static int lb035q02_panel_probe(struct omap_dss_device *dssdev)
|
|||
}
|
||||
|
||||
mutex_init(&ld->lock);
|
||||
dev_set_drvdata(&dssdev->dev, ld);
|
||||
dev_set_drvdata(dssdev->dev, ld);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ static void lb035q02_panel_remove(struct omap_dss_device *dssdev)
|
|||
|
||||
static int lb035q02_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
|
||||
struct lb035q02_data *ld = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
mutex_lock(&ld->lock);
|
||||
|
@ -153,7 +153,7 @@ err:
|
|||
|
||||
static void lb035q02_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
|
||||
struct lb035q02_data *ld = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&ld->lock);
|
||||
|
||||
|
|
|
@ -311,16 +311,16 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
|
|||
switch (rev & 0xfc) {
|
||||
case 0x9c:
|
||||
ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744;
|
||||
dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d "
|
||||
dev_info(dssdev->dev, "s1d13744 LCD controller rev %d "
|
||||
"initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
|
||||
break;
|
||||
case 0xa4:
|
||||
ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745;
|
||||
dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d "
|
||||
dev_info(dssdev->dev, "s1d13745 LCD controller rev %d "
|
||||
"initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
|
||||
break;
|
||||
default:
|
||||
dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev);
|
||||
dev_err(dssdev->dev, "invalid s1d1374x revision %02x\n", rev);
|
||||
r = -ENODEV;
|
||||
goto err_inv_chip;
|
||||
}
|
||||
|
@ -341,13 +341,13 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
|
|||
panel_name = "ls041y3";
|
||||
break;
|
||||
default:
|
||||
dev_err(&dssdev->dev, "invalid display ID 0x%x\n",
|
||||
dev_err(dssdev->dev, "invalid display ID 0x%x\n",
|
||||
display_id[0]);
|
||||
r = -ENODEV;
|
||||
goto err_inv_panel;
|
||||
}
|
||||
|
||||
dev_info(&dssdev->dev, "%s rev %02x LCD detected\n",
|
||||
dev_info(dssdev->dev, "%s rev %02x LCD detected\n",
|
||||
panel_name, display_id[1]);
|
||||
|
||||
send_sleep_out(spi);
|
||||
|
@ -416,7 +416,7 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)
|
|||
struct panel_drv_data *ddata;
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "probe\n");
|
||||
dev_dbg(dssdev->dev, "probe\n");
|
||||
|
||||
if (!bdata)
|
||||
return -EINVAL;
|
||||
|
@ -434,14 +434,14 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)
|
|||
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
|
||||
|
||||
if (gpio_is_valid(bdata->panel_reset)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, bdata->panel_reset,
|
||||
r = devm_gpio_request_one(dssdev->dev, bdata->panel_reset,
|
||||
GPIOF_OUT_INIT_LOW, "PANEL RESET");
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(bdata->ctrl_pwrdown)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, bdata->ctrl_pwrdown,
|
||||
r = devm_gpio_request_one(dssdev->dev, bdata->ctrl_pwrdown,
|
||||
GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN");
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -452,9 +452,9 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
static void n8x0_panel_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "remove\n");
|
||||
dev_dbg(dssdev->dev, "remove\n");
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, NULL);
|
||||
dev_set_drvdata(dssdev->dev, NULL);
|
||||
}
|
||||
|
||||
static int n8x0_panel_enable(struct omap_dss_device *dssdev)
|
||||
|
@ -462,7 +462,7 @@ static int n8x0_panel_enable(struct omap_dss_device *dssdev)
|
|||
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "enable\n");
|
||||
dev_dbg(dssdev->dev, "enable\n");
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
||||
|
@ -488,7 +488,7 @@ static void n8x0_panel_disable(struct omap_dss_device *dssdev)
|
|||
{
|
||||
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||||
|
||||
dev_dbg(&dssdev->dev, "disable\n");
|
||||
dev_dbg(dssdev->dev, "disable\n");
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
||||
|
@ -521,13 +521,13 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev,
|
|||
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||||
u16 dw, dh;
|
||||
|
||||
dev_dbg(&dssdev->dev, "update\n");
|
||||
dev_dbg(dssdev->dev, "update\n");
|
||||
|
||||
dw = dssdev->panel.timings.x_res;
|
||||
dh = dssdev->panel.timings.y_res;
|
||||
|
||||
if (x != 0 || y != 0 || w != dw || h != dh) {
|
||||
dev_err(&dssdev->dev, "invalid update region %d, %d, %d, %d\n",
|
||||
dev_err(dssdev->dev, "invalid update region %d, %d, %d, %d\n",
|
||||
x, y, w, h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -548,7 +548,7 @@ static int n8x0_panel_sync(struct omap_dss_device *dssdev)
|
|||
{
|
||||
struct panel_drv_data *ddata = get_drv_data(dssdev);
|
||||
|
||||
dev_dbg(&dssdev->dev, "sync\n");
|
||||
dev_dbg(dssdev->dev, "sync\n");
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
rfbi_bus_lock();
|
||||
|
|
|
@ -98,14 +98,14 @@ static int nec_8048_panel_probe(struct omap_dss_device *dssdev)
|
|||
dssdev->panel.timings = nec_8048_panel_timings;
|
||||
|
||||
if (gpio_is_valid(pd->qvga_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, pd->qvga_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, pd->qvga_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "lcd QVGA");
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pd->res_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, pd->res_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, pd->res_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd RES");
|
||||
if (r)
|
||||
return r;
|
||||
|
|
|
@ -351,7 +351,7 @@ static struct i2c_driver picodlp_i2c_driver = {
|
|||
static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r, trial = 100;
|
||||
struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
|
||||
struct picodlp_data *picod = dev_get_drvdata(dssdev->dev);
|
||||
struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
|
||||
|
||||
gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
|
||||
|
@ -360,7 +360,7 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
|
|||
|
||||
while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) {
|
||||
if (!trial--) {
|
||||
dev_err(&dssdev->dev, "emu_done signal not"
|
||||
dev_err(dssdev->dev, "emu_done signal not"
|
||||
" going high\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
|
|||
|
||||
r = omapdss_dpi_display_enable(dssdev);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to enable DPI\n");
|
||||
dev_err(dssdev->dev, "failed to enable DPI\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,7 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev)
|
|||
if (!picodlp_pdata)
|
||||
return -EINVAL;
|
||||
|
||||
picod = devm_kzalloc(&dssdev->dev, sizeof(*picod), GFP_KERNEL);
|
||||
picod = devm_kzalloc(dssdev->dev, sizeof(*picod), GFP_KERNEL);
|
||||
if (!picod)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -428,23 +428,23 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
adapter = i2c_get_adapter(picodlp_adapter_id);
|
||||
if (!adapter) {
|
||||
dev_err(&dssdev->dev, "can't get i2c adapter\n");
|
||||
dev_err(dssdev->dev, "can't get i2c adapter\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info);
|
||||
if (!picodlp_i2c_client) {
|
||||
dev_err(&dssdev->dev, "can't add i2c device::"
|
||||
dev_err(dssdev->dev, "can't add i2c device::"
|
||||
" picodlp_i2c_client is NULL\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
picod->picodlp_i2c_client = picodlp_i2c_client;
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, picod);
|
||||
dev_set_drvdata(dssdev->dev, picod);
|
||||
|
||||
if (gpio_is_valid(picodlp_pdata->emu_done_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev,
|
||||
r = devm_gpio_request_one(dssdev->dev,
|
||||
picodlp_pdata->emu_done_gpio,
|
||||
GPIOF_IN, "DLP EMU DONE");
|
||||
if (r)
|
||||
|
@ -452,7 +452,7 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev)
|
|||
}
|
||||
|
||||
if (gpio_is_valid(picodlp_pdata->pwrgood_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev,
|
||||
r = devm_gpio_request_one(dssdev->dev,
|
||||
picodlp_pdata->pwrgood_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "DLP PWRGOOD");
|
||||
if (r)
|
||||
|
@ -464,21 +464,19 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
static void picodlp_panel_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
|
||||
struct picodlp_data *picod = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
i2c_unregister_device(picod->picodlp_i2c_client);
|
||||
dev_set_drvdata(&dssdev->dev, NULL);
|
||||
dev_dbg(&dssdev->dev, "removing picodlp panel\n");
|
||||
|
||||
kfree(picod);
|
||||
dev_set_drvdata(dssdev->dev, NULL);
|
||||
dev_dbg(dssdev->dev, "removing picodlp panel\n");
|
||||
}
|
||||
|
||||
static int picodlp_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
|
||||
struct picodlp_data *picod = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "enabling picodlp panel\n");
|
||||
dev_dbg(dssdev->dev, "enabling picodlp panel\n");
|
||||
|
||||
mutex_lock(&picod->lock);
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
|
||||
|
@ -494,7 +492,7 @@ static int picodlp_panel_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
static void picodlp_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
|
||||
struct picodlp_data *picod = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&picod->lock);
|
||||
/* Turn off DLP Power */
|
||||
|
@ -504,7 +502,7 @@ static void picodlp_panel_disable(struct omap_dss_device *dssdev)
|
|||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
mutex_unlock(&picod->lock);
|
||||
|
||||
dev_dbg(&dssdev->dev, "disabling picodlp panel\n");
|
||||
dev_dbg(dssdev->dev, "disabling picodlp panel\n");
|
||||
}
|
||||
|
||||
static void picodlp_get_resolution(struct omap_dss_device *dssdev,
|
||||
|
|
|
@ -66,35 +66,35 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
|
|||
dssdev->panel.timings = sharp_ls_timings;
|
||||
|
||||
if (gpio_is_valid(pd->mo_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, pd->mo_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, pd->mo_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd MO");
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pd->lr_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, pd->lr_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, pd->lr_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "lcd LR");
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pd->ud_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, pd->ud_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, pd->ud_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "lcd UD");
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pd->resb_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, pd->resb_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, pd->resb_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd RESB");
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pd->ini_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, pd->ini_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, pd->ini_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "lcd INI");
|
||||
if (r)
|
||||
return r;
|
||||
|
|
|
@ -237,7 +237,7 @@ static int taal_set_update_window(struct taal_data *td,
|
|||
|
||||
static void taal_queue_esd_work(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
if (td->esd_interval > 0)
|
||||
queue_delayed_work(td->workqueue, &td->esd_work,
|
||||
|
@ -246,14 +246,14 @@ static void taal_queue_esd_work(struct omap_dss_device *dssdev)
|
|||
|
||||
static void taal_cancel_esd_work(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
cancel_delayed_work(&td->esd_work);
|
||||
}
|
||||
|
||||
static void taal_queue_ulps_work(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
if (td->ulps_timeout > 0)
|
||||
queue_delayed_work(td->workqueue, &td->ulps_work,
|
||||
|
@ -262,14 +262,14 @@ static void taal_queue_ulps_work(struct omap_dss_device *dssdev)
|
|||
|
||||
static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
cancel_delayed_work(&td->ulps_work);
|
||||
}
|
||||
|
||||
static int taal_enter_ulps(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
if (td->ulps_enabled)
|
||||
|
@ -291,7 +291,7 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev)
|
|||
return 0;
|
||||
|
||||
err:
|
||||
dev_err(&dssdev->dev, "enter ULPS failed");
|
||||
dev_err(dssdev->dev, "enter ULPS failed");
|
||||
taal_panel_reset(dssdev);
|
||||
|
||||
td->ulps_enabled = false;
|
||||
|
@ -303,7 +303,7 @@ err:
|
|||
|
||||
static int taal_exit_ulps(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
if (!td->ulps_enabled)
|
||||
|
@ -311,7 +311,7 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
|
|||
|
||||
r = omapdss_dsi_display_enable(dssdev);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to enable DSI\n");
|
||||
dev_err(dssdev->dev, "failed to enable DSI\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
|
@ -319,7 +319,7 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
|
|||
|
||||
r = _taal_enable_te(dssdev, true);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to re-enable TE");
|
||||
dev_err(dssdev->dev, "failed to re-enable TE");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
|
@ -333,7 +333,7 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
|
|||
return 0;
|
||||
|
||||
err2:
|
||||
dev_err(&dssdev->dev, "failed to exit ULPS");
|
||||
dev_err(dssdev->dev, "failed to exit ULPS");
|
||||
|
||||
r = taal_panel_reset(dssdev);
|
||||
if (!r) {
|
||||
|
@ -349,7 +349,7 @@ err1:
|
|||
|
||||
static int taal_wake_up(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
if (td->ulps_enabled)
|
||||
return taal_exit_ulps(dssdev);
|
||||
|
@ -362,7 +362,7 @@ static int taal_wake_up(struct omap_dss_device *dssdev)
|
|||
static int taal_bl_update_status(struct backlight_device *dev)
|
||||
{
|
||||
struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
int level;
|
||||
|
||||
|
@ -372,7 +372,7 @@ static int taal_bl_update_status(struct backlight_device *dev)
|
|||
else
|
||||
level = 0;
|
||||
|
||||
dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
|
||||
dev_dbg(dssdev->dev, "update brightness to %d\n", level);
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
||||
|
@ -418,7 +418,7 @@ static ssize_t taal_num_errors_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
u8 errors = 0;
|
||||
int r;
|
||||
|
||||
|
@ -448,7 +448,7 @@ static ssize_t taal_hw_revision_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
u8 id1, id2, id3;
|
||||
int r;
|
||||
|
||||
|
@ -486,7 +486,7 @@ static ssize_t show_cabc_mode(struct device *dev,
|
|||
char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
const char *mode_str;
|
||||
int mode;
|
||||
int len;
|
||||
|
@ -506,7 +506,7 @@ static ssize_t store_cabc_mode(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int i;
|
||||
int r;
|
||||
|
||||
|
@ -568,12 +568,12 @@ static ssize_t taal_store_esd_interval(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
unsigned long t;
|
||||
int r;
|
||||
|
||||
r = strict_strtoul(buf, 10, &t);
|
||||
r = kstrtoul(buf, 10, &t);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -592,7 +592,7 @@ static ssize_t taal_show_esd_interval(struct device *dev,
|
|||
char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
unsigned t;
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
@ -607,11 +607,11 @@ static ssize_t taal_store_ulps(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
unsigned long t;
|
||||
int r;
|
||||
|
||||
r = strict_strtoul(buf, 10, &t);
|
||||
r = kstrtoul(buf, 10, &t);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -641,7 +641,7 @@ static ssize_t taal_show_ulps(struct device *dev,
|
|||
char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
unsigned t;
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
@ -656,11 +656,11 @@ static ssize_t taal_store_ulps_timeout(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
unsigned long t;
|
||||
int r;
|
||||
|
||||
r = strict_strtoul(buf, 10, &t);
|
||||
r = kstrtoul(buf, 10, &t);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -687,7 +687,7 @@ static ssize_t taal_show_ulps_timeout(struct device *dev,
|
|||
char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
unsigned t;
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
@ -727,7 +727,7 @@ static struct attribute_group taal_attr_group = {
|
|||
|
||||
static void taal_hw_reset(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
if (!gpio_is_valid(td->reset_gpio))
|
||||
return;
|
||||
|
@ -768,13 +768,13 @@ static int taal_probe(struct omap_dss_device *dssdev)
|
|||
struct backlight_device *bldev = NULL;
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "probe\n");
|
||||
dev_dbg(dssdev->dev, "probe\n");
|
||||
|
||||
td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL);
|
||||
td = devm_kzalloc(dssdev->dev, sizeof(*td), GFP_KERNEL);
|
||||
if (!td)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, td);
|
||||
dev_set_drvdata(dssdev->dev, td);
|
||||
td->dssdev = dssdev;
|
||||
|
||||
if (dssdev->data) {
|
||||
|
@ -797,41 +797,41 @@ static int taal_probe(struct omap_dss_device *dssdev)
|
|||
atomic_set(&td->do_update, 0);
|
||||
|
||||
if (gpio_is_valid(td->reset_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, td->reset_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "taal rst");
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to request reset gpio\n");
|
||||
dev_err(dssdev->dev, "failed to request reset gpio\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio_is_valid(td->ext_te_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, td->ext_te_gpio,
|
||||
GPIOF_IN, "taal irq");
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "GPIO request failed\n");
|
||||
dev_err(dssdev->dev, "GPIO request failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio),
|
||||
r = devm_request_irq(dssdev->dev, gpio_to_irq(td->ext_te_gpio),
|
||||
taal_te_isr,
|
||||
IRQF_TRIGGER_RISING,
|
||||
"taal vsync", dssdev);
|
||||
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "IRQ request failed\n");
|
||||
dev_err(dssdev->dev, "IRQ request failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
INIT_DEFERRABLE_WORK(&td->te_timeout_work,
|
||||
taal_te_timeout_work_callback);
|
||||
|
||||
dev_dbg(&dssdev->dev, "Using GPIO TE\n");
|
||||
dev_dbg(dssdev->dev, "Using GPIO TE\n");
|
||||
}
|
||||
|
||||
td->workqueue = create_singlethread_workqueue("taal_esd");
|
||||
if (td->workqueue == NULL) {
|
||||
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
|
||||
dev_err(dssdev->dev, "can't create ESD workqueue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work);
|
||||
|
@ -844,8 +844,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
|
|||
props.max_brightness = 255;
|
||||
|
||||
props.type = BACKLIGHT_RAW;
|
||||
bldev = backlight_device_register(dev_name(&dssdev->dev),
|
||||
&dssdev->dev, dssdev, &taal_bl_ops, &props);
|
||||
bldev = backlight_device_register(dev_name(dssdev->dev),
|
||||
dssdev->dev, dssdev, &taal_bl_ops, &props);
|
||||
if (IS_ERR(bldev)) {
|
||||
r = PTR_ERR(bldev);
|
||||
goto err_bl;
|
||||
|
@ -862,19 +862,19 @@ static int taal_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
r = omap_dsi_request_vc(dssdev, &td->channel);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to get virtual channel\n");
|
||||
dev_err(dssdev->dev, "failed to get virtual channel\n");
|
||||
goto err_req_vc;
|
||||
}
|
||||
|
||||
r = omap_dsi_set_vc_id(dssdev, td->channel, TCH);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to set VC_ID\n");
|
||||
dev_err(dssdev->dev, "failed to set VC_ID\n");
|
||||
goto err_vc_id;
|
||||
}
|
||||
|
||||
r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
|
||||
r = sysfs_create_group(&dssdev->dev->kobj, &taal_attr_group);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to create sysfs files\n");
|
||||
dev_err(dssdev->dev, "failed to create sysfs files\n");
|
||||
goto err_vc_id;
|
||||
}
|
||||
|
||||
|
@ -892,12 +892,12 @@ err_bl:
|
|||
|
||||
static void __exit taal_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
struct backlight_device *bldev;
|
||||
|
||||
dev_dbg(&dssdev->dev, "remove\n");
|
||||
dev_dbg(dssdev->dev, "remove\n");
|
||||
|
||||
sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
|
||||
sysfs_remove_group(&dssdev->dev->kobj, &taal_attr_group);
|
||||
omap_dsi_release_vc(dssdev, td->channel);
|
||||
|
||||
bldev = td->bldev;
|
||||
|
@ -917,7 +917,7 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
|
|||
|
||||
static int taal_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
u8 id1, id2, id3;
|
||||
int r;
|
||||
struct omap_dss_dsi_config dsi_config = {
|
||||
|
@ -932,19 +932,19 @@ static int taal_power_on(struct omap_dss_device *dssdev)
|
|||
|
||||
r = omapdss_dsi_configure_pins(dssdev, &td->pin_config);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to configure DSI pins\n");
|
||||
dev_err(dssdev->dev, "failed to configure DSI pins\n");
|
||||
goto err0;
|
||||
};
|
||||
|
||||
r = omapdss_dsi_set_config(dssdev, &dsi_config);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to configure DSI\n");
|
||||
dev_err(dssdev->dev, "failed to configure DSI\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = omapdss_dsi_display_enable(dssdev);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to enable DSI\n");
|
||||
dev_err(dssdev->dev, "failed to enable DSI\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
|
@ -999,10 +999,10 @@ static int taal_power_on(struct omap_dss_device *dssdev)
|
|||
td->enabled = 1;
|
||||
|
||||
if (!td->intro_printed) {
|
||||
dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n",
|
||||
dev_info(dssdev->dev, "panel revision %02x.%02x.%02x\n",
|
||||
id1, id2, id3);
|
||||
if (td->cabc_broken)
|
||||
dev_info(&dssdev->dev,
|
||||
dev_info(dssdev->dev,
|
||||
"old Taal version, CABC disabled\n");
|
||||
td->intro_printed = true;
|
||||
}
|
||||
|
@ -1011,7 +1011,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
|
|||
|
||||
return 0;
|
||||
err:
|
||||
dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n");
|
||||
dev_err(dssdev->dev, "error while enabling panel, issuing HW reset\n");
|
||||
|
||||
taal_hw_reset(dssdev);
|
||||
|
||||
|
@ -1022,7 +1022,7 @@ err0:
|
|||
|
||||
static void taal_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
dsi_disable_video_output(dssdev, td->channel);
|
||||
|
@ -1032,7 +1032,7 @@ static void taal_power_off(struct omap_dss_device *dssdev)
|
|||
r = taal_sleep_in(td);
|
||||
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev,
|
||||
dev_err(dssdev->dev,
|
||||
"error disabling panel, issuing HW reset\n");
|
||||
taal_hw_reset(dssdev);
|
||||
}
|
||||
|
@ -1044,7 +1044,7 @@ static void taal_power_off(struct omap_dss_device *dssdev)
|
|||
|
||||
static int taal_panel_reset(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_err(&dssdev->dev, "performing LCD reset\n");
|
||||
dev_err(dssdev->dev, "performing LCD reset\n");
|
||||
|
||||
taal_power_off(dssdev);
|
||||
taal_hw_reset(dssdev);
|
||||
|
@ -1053,10 +1053,10 @@ static int taal_panel_reset(struct omap_dss_device *dssdev)
|
|||
|
||||
static int taal_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "enable\n");
|
||||
dev_dbg(dssdev->dev, "enable\n");
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
||||
|
@ -1082,16 +1082,16 @@ static int taal_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
return 0;
|
||||
err:
|
||||
dev_dbg(&dssdev->dev, "enable failed\n");
|
||||
dev_dbg(dssdev->dev, "enable failed\n");
|
||||
mutex_unlock(&td->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void taal_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
dev_dbg(&dssdev->dev, "disable\n");
|
||||
dev_dbg(dssdev->dev, "disable\n");
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
||||
|
@ -1118,14 +1118,14 @@ static void taal_disable(struct omap_dss_device *dssdev)
|
|||
static void taal_framedone_cb(int err, void *data)
|
||||
{
|
||||
struct omap_dss_device *dssdev = data;
|
||||
dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
|
||||
dev_dbg(dssdev->dev, "framedone, err %d\n", err);
|
||||
dsi_bus_unlock(dssdev);
|
||||
}
|
||||
|
||||
static irqreturn_t taal_te_isr(int irq, void *data)
|
||||
{
|
||||
struct omap_dss_device *dssdev = data;
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int old;
|
||||
int r;
|
||||
|
||||
|
@ -1142,7 +1142,7 @@ static irqreturn_t taal_te_isr(int irq, void *data)
|
|||
|
||||
return IRQ_HANDLED;
|
||||
err:
|
||||
dev_err(&dssdev->dev, "start update failed\n");
|
||||
dev_err(dssdev->dev, "start update failed\n");
|
||||
dsi_bus_unlock(dssdev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -1153,7 +1153,7 @@ static void taal_te_timeout_work_callback(struct work_struct *work)
|
|||
te_timeout_work.work);
|
||||
struct omap_dss_device *dssdev = td->dssdev;
|
||||
|
||||
dev_err(&dssdev->dev, "TE not received for 250ms!\n");
|
||||
dev_err(dssdev->dev, "TE not received for 250ms!\n");
|
||||
|
||||
atomic_set(&td->do_update, 0);
|
||||
dsi_bus_unlock(dssdev);
|
||||
|
@ -1162,10 +1162,10 @@ static void taal_te_timeout_work_callback(struct work_struct *work)
|
|||
static int taal_update(struct omap_dss_device *dssdev,
|
||||
u16 x, u16 y, u16 w, u16 h)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
|
||||
dev_dbg(dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
dsi_bus_lock(dssdev);
|
||||
|
@ -1208,23 +1208,23 @@ err:
|
|||
|
||||
static int taal_sync(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
dev_dbg(&dssdev->dev, "sync\n");
|
||||
dev_dbg(dssdev->dev, "sync\n");
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
dsi_bus_lock(dssdev);
|
||||
dsi_bus_unlock(dssdev);
|
||||
mutex_unlock(&td->lock);
|
||||
|
||||
dev_dbg(&dssdev->dev, "sync done\n");
|
||||
dev_dbg(dssdev->dev, "sync done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
if (enable)
|
||||
|
@ -1243,7 +1243,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
|
|||
|
||||
static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
@ -1279,7 +1279,7 @@ err:
|
|||
|
||||
static int taal_get_te(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
mutex_lock(&td->lock);
|
||||
|
@ -1291,7 +1291,7 @@ static int taal_get_te(struct omap_dss_device *dssdev)
|
|||
|
||||
static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
|
||||
{
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
u8 id1, id2, id3;
|
||||
int r;
|
||||
|
||||
|
@ -1336,7 +1336,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
|
|||
int first = 1;
|
||||
int plen;
|
||||
unsigned buf_used = 0;
|
||||
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
|
||||
struct taal_data *td = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
if (size < w * h * 3)
|
||||
return -ENOMEM;
|
||||
|
@ -1380,19 +1380,19 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
|
|||
buf + buf_used, size - buf_used);
|
||||
|
||||
if (r < 0) {
|
||||
dev_err(&dssdev->dev, "read error\n");
|
||||
dev_err(dssdev->dev, "read error\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
buf_used += r;
|
||||
|
||||
if (r < plen) {
|
||||
dev_err(&dssdev->dev, "short read\n");
|
||||
dev_err(dssdev->dev, "short read\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
dev_err(&dssdev->dev, "signal pending, "
|
||||
dev_err(dssdev->dev, "signal pending, "
|
||||
"aborting memory read\n");
|
||||
r = -ERESTARTSYS;
|
||||
goto err3;
|
||||
|
@ -1450,26 +1450,26 @@ static void taal_esd_work(struct work_struct *work)
|
|||
|
||||
r = taal_wake_up(dssdev);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to exit ULPS\n");
|
||||
dev_err(dssdev->dev, "failed to exit ULPS\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state1);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to read Taal status\n");
|
||||
dev_err(dssdev->dev, "failed to read Taal status\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Run self diagnostics */
|
||||
r = taal_sleep_out(td);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to run Taal self-diagnostics\n");
|
||||
dev_err(dssdev->dev, "failed to run Taal self-diagnostics\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state2);
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to read Taal status\n");
|
||||
dev_err(dssdev->dev, "failed to read Taal status\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -1477,7 +1477,7 @@ static void taal_esd_work(struct work_struct *work)
|
|||
* Bit6 if the test passes.
|
||||
*/
|
||||
if (!((state1 ^ state2) & (1 << 6))) {
|
||||
dev_err(&dssdev->dev, "LCD self diagnostics failed\n");
|
||||
dev_err(dssdev->dev, "LCD self diagnostics failed\n");
|
||||
goto err;
|
||||
}
|
||||
/* Self-diagnostics result is also shown on TE GPIO line. We need
|
||||
|
@ -1495,7 +1495,7 @@ static void taal_esd_work(struct work_struct *work)
|
|||
mutex_unlock(&td->lock);
|
||||
return;
|
||||
err:
|
||||
dev_err(&dssdev->dev, "performing LCD reset\n");
|
||||
dev_err(dssdev->dev, "performing LCD reset\n");
|
||||
|
||||
taal_panel_reset(dssdev);
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ struct panel_drv_data {
|
|||
|
||||
static int tfp410_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
|
@ -82,7 +82,7 @@ err0:
|
|||
|
||||
static void tfp410_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return;
|
||||
|
@ -99,7 +99,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
|
|||
int r;
|
||||
int i2c_bus_num;
|
||||
|
||||
ddata = devm_kzalloc(&dssdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
ddata = devm_kzalloc(dssdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -119,10 +119,10 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
|
|||
}
|
||||
|
||||
if (gpio_is_valid(ddata->pd_gpio)) {
|
||||
r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio,
|
||||
r = devm_gpio_request_one(dssdev->dev, ddata->pd_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "tfp410 pd");
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
|
||||
dev_err(dssdev->dev, "Failed to request PD GPIO %d\n",
|
||||
ddata->pd_gpio);
|
||||
return r;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
adapter = i2c_get_adapter(i2c_bus_num);
|
||||
if (!adapter) {
|
||||
dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
|
||||
dev_err(dssdev->dev, "Failed to get I2C adapter, bus %d\n",
|
||||
i2c_bus_num);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
@ -141,28 +141,28 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
|
|||
ddata->i2c_adapter = adapter;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, ddata);
|
||||
dev_set_drvdata(dssdev->dev, ddata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit tfp410_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
||||
if (ddata->i2c_adapter)
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, NULL);
|
||||
dev_set_drvdata(dssdev->dev, NULL);
|
||||
|
||||
mutex_unlock(&ddata->lock);
|
||||
}
|
||||
|
||||
static int tfp410_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
@ -178,7 +178,7 @@ static int tfp410_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
static void tfp410_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
||||
|
@ -192,7 +192,7 @@ static void tfp410_disable(struct omap_dss_device *dssdev)
|
|||
static void tfp410_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
omapdss_dpi_set_timings(dssdev, timings);
|
||||
|
@ -203,7 +203,7 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev,
|
|||
static void tfp410_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
*timings = dssdev->panel.timings;
|
||||
|
@ -213,7 +213,7 @@ static void tfp410_get_timings(struct omap_dss_device *dssdev,
|
|||
static int tfp410_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
@ -258,7 +258,7 @@ static int tfp410_ddc_read(struct i2c_adapter *adapter,
|
|||
static int tfp410_read_edid(struct omap_dss_device *dssdev,
|
||||
u8 *edid, int len)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
int r, l, bytes_read;
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
@ -298,7 +298,7 @@ err:
|
|||
|
||||
static bool tfp410_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
|
||||
unsigned char out;
|
||||
int r;
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
|
|||
|
||||
static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
|
||||
{
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
tpo_td043->hmirror = enable;
|
||||
return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
|
||||
|
@ -135,7 +135,7 @@ static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
|
|||
|
||||
static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
return tpo_td043->hmirror;
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043)
|
|||
|
||||
static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev);
|
||||
int r;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
|
@ -372,7 +372,7 @@ err0:
|
|||
|
||||
static void tpo_td043_disable_dss(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return;
|
||||
|
@ -385,14 +385,14 @@ static void tpo_td043_disable_dss(struct omap_dss_device *dssdev)
|
|||
|
||||
static int tpo_td043_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "enable\n");
|
||||
dev_dbg(dssdev->dev, "enable\n");
|
||||
|
||||
return tpo_td043_enable_dss(dssdev);
|
||||
}
|
||||
|
||||
static void tpo_td043_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "disable\n");
|
||||
dev_dbg(dssdev->dev, "disable\n");
|
||||
|
||||
tpo_td043_disable_dss(dssdev);
|
||||
|
||||
|
@ -405,10 +405,10 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
|
|||
struct panel_tpo_td043_data *pdata = get_panel_data(dssdev);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(&dssdev->dev, "probe\n");
|
||||
dev_dbg(dssdev->dev, "probe\n");
|
||||
|
||||
if (tpo_td043 == NULL) {
|
||||
dev_err(&dssdev->dev, "missing tpo_td043_device\n");
|
||||
dev_err(dssdev->dev, "missing tpo_td043_device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -423,28 +423,28 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
|
|||
tpo_td043->mode = TPO_R02_MODE_800x480;
|
||||
memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma));
|
||||
|
||||
tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc");
|
||||
tpo_td043->vcc_reg = regulator_get(dssdev->dev, "vcc");
|
||||
if (IS_ERR(tpo_td043->vcc_reg)) {
|
||||
dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n");
|
||||
dev_err(dssdev->dev, "failed to get LCD VCC regulator\n");
|
||||
ret = PTR_ERR(tpo_td043->vcc_reg);
|
||||
goto fail_regulator;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(tpo_td043->nreset_gpio)) {
|
||||
ret = devm_gpio_request_one(&dssdev->dev,
|
||||
ret = devm_gpio_request_one(dssdev->dev,
|
||||
tpo_td043->nreset_gpio, GPIOF_OUT_INIT_LOW,
|
||||
"lcd reset");
|
||||
if (ret < 0) {
|
||||
dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
|
||||
dev_err(dssdev->dev, "couldn't request reset GPIO\n");
|
||||
goto fail_gpio_req;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
|
||||
ret = sysfs_create_group(&dssdev->dev->kobj, &tpo_td043_attr_group);
|
||||
if (ret)
|
||||
dev_warn(&dssdev->dev, "failed to create sysfs files\n");
|
||||
dev_warn(dssdev->dev, "failed to create sysfs files\n");
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, tpo_td043);
|
||||
dev_set_drvdata(dssdev->dev, tpo_td043);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -457,11 +457,11 @@ fail_regulator:
|
|||
|
||||
static void tpo_td043_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
|
||||
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev);
|
||||
|
||||
dev_dbg(&dssdev->dev, "remove\n");
|
||||
dev_dbg(dssdev->dev, "remove\n");
|
||||
|
||||
sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
|
||||
sysfs_remove_group(&dssdev->dev->kobj, &tpo_td043_attr_group);
|
||||
regulator_put(tpo_td043->vcc_reg);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
menuconfig OMAP2_DSS
|
||||
tristate "OMAP2+ Display Subsystem support"
|
||||
select VIDEOMODE_HELPERS
|
||||
help
|
||||
OMAP2+ Display Subsystem support.
|
||||
|
||||
|
|
|
@ -420,16 +420,26 @@ static void wait_pending_extra_info_updates(void)
|
|||
DSSWARN("timeout in wait_pending_extra_info_updates\n");
|
||||
}
|
||||
|
||||
static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
|
||||
static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
return ovl->manager ?
|
||||
(ovl->manager->output ? ovl->manager->output->device : NULL) :
|
||||
NULL;
|
||||
struct omap_dss_device *dssdev;
|
||||
|
||||
dssdev = mgr->output;
|
||||
if (dssdev == NULL)
|
||||
return NULL;
|
||||
|
||||
while (dssdev->device)
|
||||
dssdev = dssdev->device;
|
||||
|
||||
if (dssdev->driver)
|
||||
return dssdev;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
|
||||
static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
|
||||
{
|
||||
return mgr->output ? mgr->output->device : NULL;
|
||||
return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;
|
||||
}
|
||||
|
||||
static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
|
||||
|
@ -792,6 +802,18 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
|
|||
}
|
||||
}
|
||||
|
||||
static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
return mgr->set_output(mgr, dst);
|
||||
}
|
||||
|
||||
static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
mgr->unset_output(mgr);
|
||||
}
|
||||
|
||||
static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
struct mgr_priv_data *mp = get_mgr_priv(mgr);
|
||||
|
@ -1156,7 +1178,7 @@ static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
|
|||
}
|
||||
|
||||
static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_output *output)
|
||||
struct omap_dss_device *output)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
@ -1554,6 +1576,8 @@ static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_mana
|
|||
}
|
||||
|
||||
static const struct dss_mgr_ops apply_mgr_ops = {
|
||||
.connect = dss_mgr_connect_compat,
|
||||
.disconnect = dss_mgr_disconnect_compat,
|
||||
.start_update = dss_mgr_start_update_compat,
|
||||
.enable = dss_mgr_enable_compat,
|
||||
.disable = dss_mgr_disable_compat,
|
||||
|
@ -1569,7 +1593,6 @@ static DEFINE_MUTEX(compat_init_lock);
|
|||
int omapdss_compat_init(void)
|
||||
{
|
||||
struct platform_device *pdev = dss_get_core_pdev();
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
int i, r;
|
||||
|
||||
mutex_lock(&compat_init_lock);
|
||||
|
@ -1579,7 +1602,7 @@ int omapdss_compat_init(void)
|
|||
|
||||
apply_init_priv();
|
||||
|
||||
dss_init_overlay_managers(pdev);
|
||||
dss_init_overlay_managers_sysfs(pdev);
|
||||
dss_init_overlays(pdev);
|
||||
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
|
||||
|
@ -1615,12 +1638,9 @@ int omapdss_compat_init(void)
|
|||
if (r)
|
||||
goto err_mgr_ops;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
r = display_init_sysfs(pdev, dssdev);
|
||||
/* XXX uninit sysfs files on error */
|
||||
if (r)
|
||||
goto err_disp_sysfs;
|
||||
}
|
||||
r = display_init_sysfs(pdev);
|
||||
if (r)
|
||||
goto err_disp_sysfs;
|
||||
|
||||
dispc_runtime_get();
|
||||
|
||||
|
@ -1637,12 +1657,13 @@ out:
|
|||
|
||||
err_init_irq:
|
||||
dispc_runtime_put();
|
||||
display_uninit_sysfs(pdev);
|
||||
|
||||
err_disp_sysfs:
|
||||
dss_uninstall_mgr_ops();
|
||||
|
||||
err_mgr_ops:
|
||||
dss_uninit_overlay_managers(pdev);
|
||||
dss_uninit_overlay_managers_sysfs(pdev);
|
||||
dss_uninit_overlays(pdev);
|
||||
|
||||
compat_refcnt--;
|
||||
|
@ -1656,7 +1677,6 @@ EXPORT_SYMBOL(omapdss_compat_init);
|
|||
void omapdss_compat_uninit(void)
|
||||
{
|
||||
struct platform_device *pdev = dss_get_core_pdev();
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
mutex_lock(&compat_init_lock);
|
||||
|
||||
|
@ -1665,12 +1685,11 @@ void omapdss_compat_uninit(void)
|
|||
|
||||
dss_dispc_uninitialize_irq();
|
||||
|
||||
for_each_dss_dev(dssdev)
|
||||
display_uninit_sysfs(pdev, dssdev);
|
||||
display_uninit_sysfs(pdev);
|
||||
|
||||
dss_uninstall_mgr_ops();
|
||||
|
||||
dss_uninit_overlay_managers(pdev);
|
||||
dss_uninit_overlay_managers_sysfs(pdev);
|
||||
dss_uninit_overlays(pdev);
|
||||
out:
|
||||
mutex_unlock(&compat_init_lock);
|
||||
|
|
|
@ -88,7 +88,7 @@ struct regulator *dss_get_vdds_dsi(void)
|
|||
if (core.vdds_dsi_reg != NULL)
|
||||
return core.vdds_dsi_reg;
|
||||
|
||||
reg = regulator_get(&core.pdev->dev, "vdds_dsi");
|
||||
reg = devm_regulator_get(&core.pdev->dev, "vdds_dsi");
|
||||
if (!IS_ERR(reg))
|
||||
core.vdds_dsi_reg = reg;
|
||||
|
||||
|
@ -102,7 +102,7 @@ struct regulator *dss_get_vdds_sdi(void)
|
|||
if (core.vdds_sdi_reg != NULL)
|
||||
return core.vdds_sdi_reg;
|
||||
|
||||
reg = regulator_get(&core.pdev->dev, "vdds_sdi");
|
||||
reg = devm_regulator_get(&core.pdev->dev, "vdds_sdi");
|
||||
if (!IS_ERR(reg))
|
||||
core.vdds_sdi_reg = reg;
|
||||
|
||||
|
@ -243,6 +243,8 @@ static int __init omap_dss_probe(struct platform_device *pdev)
|
|||
|
||||
if (def_disp_name)
|
||||
core.default_display_name = def_disp_name;
|
||||
else if (pdata->default_display_name)
|
||||
core.default_display_name = pdata->default_display_name;
|
||||
else if (pdata->default_device)
|
||||
core.default_display_name = pdata->default_device->name;
|
||||
|
||||
|
@ -290,37 +292,9 @@ static int dss_bus_match(struct device *dev, struct device_driver *driver)
|
|||
return strcmp(dssdev->driver_name, driver->name) == 0;
|
||||
}
|
||||
|
||||
static ssize_t device_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
dssdev->name ?
|
||||
dssdev->name : "");
|
||||
}
|
||||
|
||||
static struct device_attribute default_dev_attrs[] = {
|
||||
__ATTR(name, S_IRUGO, device_name_show, NULL),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static ssize_t driver_name_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
struct omap_dss_driver *dssdrv = to_dss_driver(drv);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
dssdrv->driver.name ?
|
||||
dssdrv->driver.name : "");
|
||||
}
|
||||
static struct driver_attribute default_drv_attrs[] = {
|
||||
__ATTR(name, S_IRUGO, driver_name_show, NULL),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static struct bus_type dss_bus_type = {
|
||||
.name = "omapdss",
|
||||
.match = dss_bus_match,
|
||||
.dev_attrs = default_dev_attrs,
|
||||
.drv_attrs = default_drv_attrs,
|
||||
};
|
||||
|
||||
static void dss_bus_release(struct device *dev)
|
||||
|
@ -377,6 +351,46 @@ static int dss_driver_remove(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int omapdss_default_connect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out;
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
out = dssdev->output;
|
||||
|
||||
if (out == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(out->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, out);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omapdss_default_disconnect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out;
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
out = dssdev->output;
|
||||
|
||||
if (out == NULL)
|
||||
return;
|
||||
|
||||
mgr = out->manager;
|
||||
|
||||
if (mgr == NULL)
|
||||
return;
|
||||
|
||||
dss_mgr_disconnect(mgr, out);
|
||||
}
|
||||
|
||||
int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
|
||||
{
|
||||
dssdriver->driver.bus = &dss_bus_type;
|
||||
|
@ -390,6 +404,10 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
|
|||
omapdss_default_get_recommended_bpp;
|
||||
if (dssdriver->get_timings == NULL)
|
||||
dssdriver->get_timings = omapdss_default_get_timings;
|
||||
if (dssdriver->connect == NULL)
|
||||
dssdriver->connect = omapdss_default_connect;
|
||||
if (dssdriver->disconnect == NULL)
|
||||
dssdriver->disconnect = omapdss_default_disconnect;
|
||||
|
||||
return driver_register(&dssdriver->driver);
|
||||
}
|
||||
|
@ -419,29 +437,33 @@ struct omap_dss_device *dss_alloc_and_init_device(struct device *parent)
|
|||
if (!dssdev)
|
||||
return NULL;
|
||||
|
||||
dssdev->dev.bus = &dss_bus_type;
|
||||
dssdev->dev.parent = parent;
|
||||
dssdev->dev.release = omap_dss_dev_release;
|
||||
dev_set_name(&dssdev->dev, "display%d", disp_num_counter++);
|
||||
dssdev->old_dev.bus = &dss_bus_type;
|
||||
dssdev->old_dev.parent = parent;
|
||||
dssdev->old_dev.release = omap_dss_dev_release;
|
||||
dev_set_name(&dssdev->old_dev, "display%d", disp_num_counter++);
|
||||
|
||||
device_initialize(&dssdev->dev);
|
||||
device_initialize(&dssdev->old_dev);
|
||||
|
||||
return dssdev;
|
||||
}
|
||||
|
||||
int dss_add_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return device_add(&dssdev->dev);
|
||||
dssdev->dev = &dssdev->old_dev;
|
||||
|
||||
omapdss_register_display(dssdev);
|
||||
return device_add(&dssdev->old_dev);
|
||||
}
|
||||
|
||||
void dss_put_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
put_device(&dssdev->dev);
|
||||
put_device(&dssdev->old_dev);
|
||||
}
|
||||
|
||||
void dss_unregister_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
device_unregister(&dssdev->dev);
|
||||
device_unregister(&dssdev->old_dev);
|
||||
omapdss_unregister_display(dssdev);
|
||||
}
|
||||
|
||||
static int dss_unregister_dss_dev(struct device *dev, void *data)
|
||||
|
@ -618,16 +640,6 @@ static int __init omap_dss_init(void)
|
|||
|
||||
static void __exit omap_dss_exit(void)
|
||||
{
|
||||
if (core.vdds_dsi_reg != NULL) {
|
||||
regulator_put(core.vdds_dsi_reg);
|
||||
core.vdds_dsi_reg = NULL;
|
||||
}
|
||||
|
||||
if (core.vdds_sdi_reg != NULL) {
|
||||
regulator_put(core.vdds_sdi_reg);
|
||||
core.vdds_sdi_reg = NULL;
|
||||
}
|
||||
|
||||
omap_dss_unregister_drivers();
|
||||
|
||||
omap_dss_bus_unregister();
|
||||
|
|
|
@ -360,8 +360,7 @@ static void dispc_error_worker(struct work_struct *work)
|
|||
if (bit & errors) {
|
||||
DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
|
||||
ovl->name);
|
||||
dispc_ovl_enable(ovl->id, false);
|
||||
dispc_mgr_go(ovl->manager->id);
|
||||
ovl->disable(ovl);
|
||||
msleep(50);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ static struct {
|
|||
int irq;
|
||||
|
||||
unsigned long core_clk_rate;
|
||||
unsigned long tv_pclk_rate;
|
||||
|
||||
u32 fifo_size[DISPC_MAX_NR_FIFOS];
|
||||
/* maps which plane is using a fifo. fifo-id -> plane-id */
|
||||
|
@ -3071,22 +3072,15 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
|
|||
|
||||
return r / pcd;
|
||||
} else {
|
||||
enum dss_hdmi_venc_clk_source_select source;
|
||||
|
||||
source = dss_get_hdmi_venc_clk_source();
|
||||
|
||||
switch (source) {
|
||||
case DSS_VENC_TV_CLK:
|
||||
return venc_get_pixel_clock();
|
||||
case DSS_HDMI_M_PCLK:
|
||||
return hdmi_get_pixel_clock();
|
||||
default:
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
return dispc.tv_pclk_rate;
|
||||
}
|
||||
}
|
||||
|
||||
void dispc_set_tv_pclk(unsigned long pclk)
|
||||
{
|
||||
dispc.tv_pclk_rate = pclk;
|
||||
}
|
||||
|
||||
unsigned long dispc_core_clk_rate(void)
|
||||
{
|
||||
return dispc.core_clk_rate;
|
||||
|
@ -3710,6 +3704,8 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
|||
|
||||
dispc_runtime_put();
|
||||
|
||||
dss_init_overlay_managers();
|
||||
|
||||
dss_debugfs_create_file("dispc", dispc_dump_regs);
|
||||
|
||||
return 0;
|
||||
|
@ -3723,6 +3719,8 @@ static int __exit omap_dispchw_remove(struct platform_device *pdev)
|
|||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
dss_uninit_overlay_managers();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,42 +22,69 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static struct omap_dss_device *to_dss_device_sysfs(struct device *dev)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (dssdev->dev == dev) {
|
||||
omap_dss_put_device(dssdev);
|
||||
return dssdev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t display_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
dssdev->name ?
|
||||
dssdev->name : "");
|
||||
}
|
||||
|
||||
static ssize_t display_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
omapdss_device_is_enabled(dssdev));
|
||||
}
|
||||
|
||||
static ssize_t display_enabled_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int r;
|
||||
bool enabled;
|
||||
bool enable;
|
||||
|
||||
r = strtobool(buf, &enabled);
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
|
||||
if (enabled) {
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
dssdev->driver->disable(dssdev);
|
||||
}
|
||||
if (enable == omapdss_device_is_enabled(dssdev))
|
||||
return size;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev) == false)
|
||||
return -ENODEV;
|
||||
|
||||
if (enable) {
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
dssdev->driver->disable(dssdev);
|
||||
}
|
||||
|
||||
return size;
|
||||
|
@ -66,7 +93,7 @@ static ssize_t display_enabled_store(struct device *dev,
|
|||
static ssize_t display_tear_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
dssdev->driver->get_te ?
|
||||
dssdev->driver->get_te(dssdev) : 0);
|
||||
|
@ -75,7 +102,7 @@ static ssize_t display_tear_show(struct device *dev,
|
|||
static ssize_t display_tear_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int r;
|
||||
bool te;
|
||||
|
||||
|
@ -96,7 +123,7 @@ static ssize_t display_tear_store(struct device *dev,
|
|||
static ssize_t display_timings_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
struct omap_video_timings t;
|
||||
|
||||
if (!dssdev->driver->get_timings)
|
||||
|
@ -113,7 +140,7 @@ static ssize_t display_timings_show(struct device *dev,
|
|||
static ssize_t display_timings_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
struct omap_video_timings t = dssdev->panel.timings;
|
||||
int r, found;
|
||||
|
||||
|
@ -152,7 +179,7 @@ static ssize_t display_timings_store(struct device *dev,
|
|||
static ssize_t display_rotate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int rotate;
|
||||
if (!dssdev->driver->get_rotate)
|
||||
return -ENOENT;
|
||||
|
@ -163,7 +190,7 @@ static ssize_t display_rotate_show(struct device *dev,
|
|||
static ssize_t display_rotate_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int rot, r;
|
||||
|
||||
if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
|
||||
|
@ -183,7 +210,7 @@ static ssize_t display_rotate_store(struct device *dev,
|
|||
static ssize_t display_mirror_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int mirror;
|
||||
if (!dssdev->driver->get_mirror)
|
||||
return -ENOENT;
|
||||
|
@ -194,7 +221,7 @@ static ssize_t display_mirror_show(struct device *dev,
|
|||
static ssize_t display_mirror_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
int r;
|
||||
bool mirror;
|
||||
|
||||
|
@ -215,7 +242,7 @@ static ssize_t display_mirror_store(struct device *dev,
|
|||
static ssize_t display_wss_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
unsigned int wss;
|
||||
|
||||
if (!dssdev->driver->get_wss)
|
||||
|
@ -229,7 +256,7 @@ static ssize_t display_wss_show(struct device *dev,
|
|||
static ssize_t display_wss_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
|
||||
u32 wss;
|
||||
int r;
|
||||
|
||||
|
@ -250,6 +277,7 @@ static ssize_t display_wss_store(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, display_name_show, NULL);
|
||||
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
|
||||
display_enabled_show, display_enabled_store);
|
||||
static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
|
||||
|
@ -263,59 +291,55 @@ static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
|
|||
static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
|
||||
display_wss_show, display_wss_store);
|
||||
|
||||
static struct device_attribute *display_sysfs_attrs[] = {
|
||||
&dev_attr_enabled,
|
||||
&dev_attr_tear_elim,
|
||||
&dev_attr_timings,
|
||||
&dev_attr_rotate,
|
||||
&dev_attr_mirror,
|
||||
&dev_attr_wss,
|
||||
static const struct attribute *display_sysfs_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_enabled.attr,
|
||||
&dev_attr_tear_elim.attr,
|
||||
&dev_attr_timings.attr,
|
||||
&dev_attr_rotate.attr,
|
||||
&dev_attr_mirror.attr,
|
||||
&dev_attr_wss.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
int display_init_sysfs(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev)
|
||||
int display_init_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
struct device_attribute *attr;
|
||||
int i, r;
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
int r;
|
||||
|
||||
/* create device sysfs files */
|
||||
i = 0;
|
||||
while ((attr = display_sysfs_attrs[i++]) != NULL) {
|
||||
r = device_create_file(&dssdev->dev, attr);
|
||||
for_each_dss_dev(dssdev) {
|
||||
struct kobject *kobj = &dssdev->dev->kobj;
|
||||
|
||||
r = sysfs_create_files(kobj, display_sysfs_attrs);
|
||||
if (r) {
|
||||
for (i = i - 2; i >= 0; i--) {
|
||||
attr = display_sysfs_attrs[i];
|
||||
device_remove_file(&dssdev->dev, attr);
|
||||
}
|
||||
DSSERR("failed to create sysfs files\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
return r;
|
||||
r = sysfs_create_link(&pdev->dev.kobj, kobj, dssdev->alias);
|
||||
if (r) {
|
||||
sysfs_remove_files(kobj, display_sysfs_attrs);
|
||||
|
||||
DSSERR("failed to create sysfs display link\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* create display? sysfs links */
|
||||
r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
|
||||
dev_name(&dssdev->dev));
|
||||
if (r) {
|
||||
while ((attr = display_sysfs_attrs[i++]) != NULL)
|
||||
device_remove_file(&dssdev->dev, attr);
|
||||
|
||||
DSSERR("failed to create sysfs display link\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
display_uninit_sysfs(pdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void display_uninit_sysfs(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev)
|
||||
void display_uninit_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
struct device_attribute *attr;
|
||||
int i = 0;
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
|
||||
|
||||
while ((attr = display_sysfs_attrs[i++]) != NULL)
|
||||
device_remove_file(&dssdev->dev, attr);
|
||||
for_each_dss_dev(dssdev) {
|
||||
sysfs_remove_link(&pdev->dev.kobj, dssdev->alias);
|
||||
sysfs_remove_files(&dssdev->dev->kobj,
|
||||
display_sysfs_attrs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
|
|||
case OMAP_DISPLAY_TYPE_VENC:
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
case OMAP_DISPLAY_TYPE_HDMI:
|
||||
case OMAP_DISPLAY_TYPE_DVI:
|
||||
return 24;
|
||||
default:
|
||||
BUG();
|
||||
|
@ -76,110 +77,154 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_default_get_timings);
|
||||
|
||||
static int dss_suspend_device(struct device *dev, void *data)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
dssdev->activate_after_resume = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dssdev->driver->disable(dssdev);
|
||||
|
||||
dssdev->activate_after_resume = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_suspend_all_devices(void)
|
||||
{
|
||||
int r;
|
||||
struct bus_type *bus = dss_get_bus();
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
|
||||
if (r) {
|
||||
/* resume all displays that were suspended */
|
||||
dss_resume_all_devices();
|
||||
return r;
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
dssdev->driver->disable(dssdev);
|
||||
dssdev->activate_after_resume = true;
|
||||
} else {
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_resume_device(struct device *dev, void *data)
|
||||
{
|
||||
int r;
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
|
||||
if (dssdev->activate_after_resume) {
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
dssdev->activate_after_resume = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_resume_all_devices(void)
|
||||
{
|
||||
struct bus_type *bus = dss_get_bus();
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
|
||||
}
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
static int dss_disable_device(struct device *dev, void *data)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
|
||||
dssdev->driver->disable(dssdev);
|
||||
if (dssdev->activate_after_resume) {
|
||||
dssdev->driver->enable(dssdev);
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dss_disable_all_devices(void)
|
||||
{
|
||||
struct bus_type *bus = dss_get_bus();
|
||||
bus_for_each_dev(bus, NULL, NULL, dss_disable_device);
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
dssdev->driver->disable(dssdev);
|
||||
}
|
||||
}
|
||||
|
||||
static LIST_HEAD(panel_list);
|
||||
static DEFINE_MUTEX(panel_list_mutex);
|
||||
static int disp_num_counter;
|
||||
|
||||
void omap_dss_get_device(struct omap_dss_device *dssdev)
|
||||
int omapdss_register_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
get_device(&dssdev->dev);
|
||||
struct omap_dss_driver *drv = dssdev->driver;
|
||||
|
||||
snprintf(dssdev->alias, sizeof(dssdev->alias),
|
||||
"display%d", disp_num_counter++);
|
||||
|
||||
if (drv && drv->get_resolution == NULL)
|
||||
drv->get_resolution = omapdss_default_get_resolution;
|
||||
if (drv && drv->get_recommended_bpp == NULL)
|
||||
drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
|
||||
if (drv && drv->get_timings == NULL)
|
||||
drv->get_timings = omapdss_default_get_timings;
|
||||
|
||||
mutex_lock(&panel_list_mutex);
|
||||
list_add_tail(&dssdev->panel_list, &panel_list);
|
||||
mutex_unlock(&panel_list_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_register_display);
|
||||
|
||||
void omapdss_unregister_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
mutex_lock(&panel_list_mutex);
|
||||
list_del(&dssdev->panel_list);
|
||||
mutex_unlock(&panel_list_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_unregister_display);
|
||||
|
||||
struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (!try_module_get(dssdev->owner))
|
||||
return NULL;
|
||||
|
||||
if (get_device(dssdev->dev) == NULL) {
|
||||
module_put(dssdev->owner);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dssdev;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_device);
|
||||
|
||||
void omap_dss_put_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
put_device(&dssdev->dev);
|
||||
put_device(dssdev->dev);
|
||||
module_put(dssdev->owner);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_put_device);
|
||||
|
||||
/* ref count of the found device is incremented. ref count
|
||||
* of from-device is decremented. */
|
||||
/*
|
||||
* ref count of the found device is incremented.
|
||||
* ref count of from-device is decremented.
|
||||
*/
|
||||
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
|
||||
{
|
||||
struct device *dev;
|
||||
struct device *dev_start = NULL;
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
struct list_head *l;
|
||||
struct omap_dss_device *dssdev;
|
||||
|
||||
int match(struct device *dev, void *data)
|
||||
{
|
||||
return 1;
|
||||
mutex_lock(&panel_list_mutex);
|
||||
|
||||
if (list_empty(&panel_list)) {
|
||||
dssdev = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (from)
|
||||
dev_start = &from->dev;
|
||||
dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
|
||||
if (dev)
|
||||
dssdev = to_dss_device(dev);
|
||||
if (from)
|
||||
put_device(&from->dev);
|
||||
if (from == NULL) {
|
||||
dssdev = list_first_entry(&panel_list, struct omap_dss_device,
|
||||
panel_list);
|
||||
omap_dss_get_device(dssdev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
omap_dss_put_device(from);
|
||||
|
||||
list_for_each(l, &panel_list) {
|
||||
dssdev = list_entry(l, struct omap_dss_device, panel_list);
|
||||
if (dssdev == from) {
|
||||
if (list_is_last(l, &panel_list)) {
|
||||
dssdev = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dssdev = list_entry(l->next, struct omap_dss_device,
|
||||
panel_list);
|
||||
omap_dss_get_device(dssdev);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
WARN(1, "'from' dssdev not found\n");
|
||||
|
||||
dssdev = NULL;
|
||||
out:
|
||||
mutex_unlock(&panel_list_mutex);
|
||||
return dssdev;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_next_device);
|
||||
|
@ -198,24 +243,72 @@ struct omap_dss_device *omap_dss_find_device(void *data,
|
|||
}
|
||||
EXPORT_SYMBOL(omap_dss_find_device);
|
||||
|
||||
int omap_dss_start_device(struct omap_dss_device *dssdev)
|
||||
void videomode_to_omap_video_timings(const struct videomode *vm,
|
||||
struct omap_video_timings *ovt)
|
||||
{
|
||||
if (!dssdev->driver) {
|
||||
DSSDBG("no driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
memset(ovt, 0, sizeof(*ovt));
|
||||
|
||||
if (!try_module_get(dssdev->dev.driver->owner)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
ovt->pixel_clock = vm->pixelclock / 1000;
|
||||
ovt->x_res = vm->hactive;
|
||||
ovt->hbp = vm->hback_porch;
|
||||
ovt->hfp = vm->hfront_porch;
|
||||
ovt->hsw = vm->hsync_len;
|
||||
ovt->y_res = vm->vactive;
|
||||
ovt->vbp = vm->vback_porch;
|
||||
ovt->vfp = vm->vfront_porch;
|
||||
ovt->vsw = vm->vsync_len;
|
||||
|
||||
return 0;
|
||||
ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
|
||||
OMAPDSS_SIG_ACTIVE_HIGH :
|
||||
OMAPDSS_SIG_ACTIVE_LOW;
|
||||
ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
|
||||
OMAPDSS_SIG_ACTIVE_HIGH :
|
||||
OMAPDSS_SIG_ACTIVE_LOW;
|
||||
ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
|
||||
OMAPDSS_SIG_ACTIVE_HIGH :
|
||||
OMAPDSS_SIG_ACTIVE_HIGH;
|
||||
ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
|
||||
OMAPDSS_DRIVE_SIG_RISING_EDGE :
|
||||
OMAPDSS_DRIVE_SIG_FALLING_EDGE;
|
||||
|
||||
ovt->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_start_device);
|
||||
EXPORT_SYMBOL(videomode_to_omap_video_timings);
|
||||
|
||||
void omap_dss_stop_device(struct omap_dss_device *dssdev)
|
||||
void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
|
||||
struct videomode *vm)
|
||||
{
|
||||
module_put(dssdev->dev.driver->owner);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_stop_device);
|
||||
memset(vm, 0, sizeof(*vm));
|
||||
|
||||
vm->pixelclock = ovt->pixel_clock * 1000;
|
||||
|
||||
vm->hactive = ovt->x_res;
|
||||
vm->hback_porch = ovt->hbp;
|
||||
vm->hfront_porch = ovt->hfp;
|
||||
vm->hsync_len = ovt->hsw;
|
||||
vm->vactive = ovt->y_res;
|
||||
vm->vback_porch = ovt->vbp;
|
||||
vm->vfront_porch = ovt->vfp;
|
||||
vm->vsync_len = ovt->vsw;
|
||||
|
||||
if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
|
||||
vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
|
||||
else
|
||||
vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
|
||||
|
||||
if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
|
||||
vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
|
||||
else
|
||||
vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
|
||||
|
||||
if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
|
||||
vm->flags |= DISPLAY_FLAGS_DE_HIGH;
|
||||
else
|
||||
vm->flags |= DISPLAY_FLAGS_DE_LOW;
|
||||
|
||||
if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
|
||||
vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
|
||||
else
|
||||
vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_video_timings_to_videomode);
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include "dss_features.h"
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
|
||||
struct regulator *vdds_dsi_reg;
|
||||
struct platform_device *dsidev;
|
||||
|
||||
|
@ -46,7 +48,7 @@ static struct {
|
|||
struct dss_lcd_mgr_config mgr_config;
|
||||
int data_lines;
|
||||
|
||||
struct omap_dss_output output;
|
||||
struct omap_dss_device output;
|
||||
} dpi;
|
||||
|
||||
static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
|
||||
|
@ -129,7 +131,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
|
|||
* shifted. So skip all odd dividers when the pixel clock is on the
|
||||
* higher side.
|
||||
*/
|
||||
if (ctx->pck_min >= 1000000) {
|
||||
if (ctx->pck_min >= 100000000) {
|
||||
if (lckd > 1 && lckd % 2 != 0)
|
||||
return false;
|
||||
|
||||
|
@ -156,7 +158,7 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
|
|||
* shifted. So skip all odd dividers when the pixel clock is on the
|
||||
* higher side.
|
||||
*/
|
||||
if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000)
|
||||
if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000)
|
||||
return false;
|
||||
|
||||
ctx->dsi_cinfo.regm_dispc = regm_dispc;
|
||||
|
@ -345,7 +347,7 @@ static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
|
|||
|
||||
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_output *out = &dpi.output;
|
||||
struct omap_dss_device *out = &dpi.output;
|
||||
int r;
|
||||
|
||||
mutex_lock(&dpi.lock);
|
||||
|
@ -362,12 +364,6 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
goto err_no_out_mgr;
|
||||
}
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err_start_dev;
|
||||
}
|
||||
|
||||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
|
||||
r = regulator_enable(dpi.vdds_dsi_reg);
|
||||
if (r)
|
||||
|
@ -422,8 +418,6 @@ err_get_dispc:
|
|||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
|
||||
regulator_disable(dpi.vdds_dsi_reg);
|
||||
err_reg_enable:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err_start_dev:
|
||||
err_no_out_mgr:
|
||||
err_no_reg:
|
||||
mutex_unlock(&dpi.lock);
|
||||
|
@ -450,8 +444,6 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
|
|||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
|
||||
regulator_disable(dpi.vdds_dsi_reg);
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_dpi_display_disable);
|
||||
|
@ -469,6 +461,16 @@ void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_dpi_set_timings);
|
||||
|
||||
static void dpi_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
mutex_lock(&dpi.lock);
|
||||
|
||||
*timings = dpi.timings;
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
}
|
||||
|
||||
int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
|
@ -542,6 +544,50 @@ static int dpi_verify_dsi_pll(struct platform_device *dsidev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_init_regulator(void)
|
||||
{
|
||||
struct regulator *vdds_dsi;
|
||||
|
||||
if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
|
||||
return 0;
|
||||
|
||||
if (dpi.vdds_dsi_reg)
|
||||
return 0;
|
||||
|
||||
vdds_dsi = dss_get_vdds_dsi();
|
||||
|
||||
if (IS_ERR(vdds_dsi)) {
|
||||
vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi");
|
||||
if (IS_ERR(vdds_dsi)) {
|
||||
DSSERR("can't get VDDS_DSI regulator\n");
|
||||
return PTR_ERR(vdds_dsi);
|
||||
}
|
||||
}
|
||||
|
||||
dpi.vdds_dsi_reg = vdds_dsi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpi_init_pll(void)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
|
||||
if (dpi.dsidev)
|
||||
return;
|
||||
|
||||
dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
|
||||
if (!dsidev)
|
||||
return;
|
||||
|
||||
if (dpi_verify_dsi_pll(dsidev)) {
|
||||
DSSWARN("DSI PLL not operational\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dpi.dsidev = dsidev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a hardcoded channel for the DPI output. This should work for
|
||||
* current use cases, but this can be later expanded to either resolve
|
||||
|
@ -572,41 +618,6 @@ static enum omap_channel dpi_get_channel(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int dpi_init_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
|
||||
DSSDBG("init_display\n");
|
||||
|
||||
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
|
||||
dpi.vdds_dsi_reg == NULL) {
|
||||
struct regulator *vdds_dsi;
|
||||
|
||||
vdds_dsi = dss_get_vdds_dsi();
|
||||
|
||||
if (IS_ERR(vdds_dsi)) {
|
||||
DSSERR("can't get VDDS_DSI regulator\n");
|
||||
return PTR_ERR(vdds_dsi);
|
||||
}
|
||||
|
||||
dpi.vdds_dsi_reg = vdds_dsi;
|
||||
}
|
||||
|
||||
dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
|
||||
|
||||
if (dsidev && dpi_verify_dsi_pll(dsidev)) {
|
||||
dsidev = NULL;
|
||||
DSSWARN("DSI PLL not operational\n");
|
||||
}
|
||||
|
||||
if (dsidev)
|
||||
DSSDBG("using DSI PLL for DPI clock\n");
|
||||
|
||||
dpi.dsidev = dsidev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct omap_dss_device *dpi_find_dssdev(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
||||
|
@ -646,19 +657,18 @@ static int dpi_probe_pdata(struct platform_device *dpidev)
|
|||
if (!plat_dssdev)
|
||||
return 0;
|
||||
|
||||
r = dpi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dpi_init_pll();
|
||||
|
||||
dssdev = dss_alloc_and_init_device(&dpidev->dev);
|
||||
if (!dssdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dss_copy_device_pdata(dssdev, plat_dssdev);
|
||||
|
||||
r = dpi_init_display(dssdev);
|
||||
if (r) {
|
||||
DSSERR("device %s init failed: %d\n", dssdev->name, r);
|
||||
dss_put_device(dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = omapdss_output_set_device(&dpi.output, dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
|
@ -678,41 +688,108 @@ static int dpi_probe_pdata(struct platform_device *dpidev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
r = dpi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dpi_init_pll();
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omapdss_output_set_device(dssdev, dst);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
WARN_ON(dst != dssdev->device);
|
||||
|
||||
if (dst != dssdev->device)
|
||||
return;
|
||||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_dpi_ops dpi_ops = {
|
||||
.connect = dpi_connect,
|
||||
.disconnect = dpi_disconnect,
|
||||
|
||||
.enable = omapdss_dpi_display_enable,
|
||||
.disable = omapdss_dpi_display_disable,
|
||||
|
||||
.check_timings = dpi_check_timings,
|
||||
.set_timings = omapdss_dpi_set_timings,
|
||||
.get_timings = dpi_get_timings,
|
||||
|
||||
.set_data_lines = omapdss_dpi_set_data_lines,
|
||||
};
|
||||
|
||||
static void dpi_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &dpi.output;
|
||||
struct omap_dss_device *out = &dpi.output;
|
||||
|
||||
out->pdev = pdev;
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_DPI;
|
||||
out->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_DPI;
|
||||
out->name = "dpi.0";
|
||||
out->dispc_channel = dpi_get_channel();
|
||||
out->ops.dpi = &dpi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
dss_register_output(out);
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit dpi_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &dpi.output;
|
||||
struct omap_dss_device *out = &dpi.output;
|
||||
|
||||
dss_unregister_output(out);
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
static int omap_dpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dpi.pdev = pdev;
|
||||
|
||||
mutex_init(&dpi.lock);
|
||||
|
||||
dpi_init_output(pdev);
|
||||
|
||||
r = dpi_probe_pdata(pdev);
|
||||
if (r) {
|
||||
dpi_uninit_output(pdev);
|
||||
return r;
|
||||
if (pdev->dev.platform_data) {
|
||||
r = dpi_probe_pdata(pdev);
|
||||
if (r)
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
dpi_uninit_output(pdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit omap_dpi_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -363,7 +363,7 @@ struct dsi_data {
|
|||
enum omap_dss_dsi_mode mode;
|
||||
struct omap_dss_dsi_videomode_timings vm_timings;
|
||||
|
||||
struct omap_dss_output output;
|
||||
struct omap_dss_device output;
|
||||
};
|
||||
|
||||
struct dsi_packet_sent_handler_data {
|
||||
|
@ -383,12 +383,21 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside
|
|||
|
||||
static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dssdev->output->pdev;
|
||||
/* HACK: dssdev can be either the panel device, when using old API, or
|
||||
* the dsi device itself, when using the new API. So we solve this for
|
||||
* now by checking the dssdev->id. This will be removed when the old API
|
||||
* is removed.
|
||||
*/
|
||||
if (dssdev->id == OMAP_DSS_OUTPUT_DSI1 ||
|
||||
dssdev->id == OMAP_DSS_OUTPUT_DSI2)
|
||||
return to_platform_device(dssdev->dev);
|
||||
|
||||
return to_platform_device(dssdev->output->dev);
|
||||
}
|
||||
|
||||
struct platform_device *dsi_get_dsidev_from_id(int module)
|
||||
{
|
||||
struct omap_dss_output *out;
|
||||
struct omap_dss_device *out;
|
||||
enum omap_dss_output_id id;
|
||||
|
||||
switch (module) {
|
||||
|
@ -404,7 +413,7 @@ struct platform_device *dsi_get_dsidev_from_id(int module)
|
|||
|
||||
out = omap_dss_get_output(id);
|
||||
|
||||
return out ? out->pdev : NULL;
|
||||
return out ? to_platform_device(out->dev) : NULL;
|
||||
}
|
||||
|
||||
static inline void dsi_write_reg(struct platform_device *dsidev,
|
||||
|
@ -1114,6 +1123,30 @@ void dsi_runtime_put(struct platform_device *dsidev)
|
|||
WARN_ON(r < 0 && r != -ENOSYS);
|
||||
}
|
||||
|
||||
static int dsi_regulator_init(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct regulator *vdds_dsi;
|
||||
|
||||
if (dsi->vdds_dsi_reg != NULL)
|
||||
return 0;
|
||||
|
||||
vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi");
|
||||
|
||||
/* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */
|
||||
if (IS_ERR(vdds_dsi))
|
||||
vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "VCXIO");
|
||||
|
||||
if (IS_ERR(vdds_dsi)) {
|
||||
DSSERR("can't get VDDS_DSI regulator\n");
|
||||
return PTR_ERR(vdds_dsi);
|
||||
}
|
||||
|
||||
dsi->vdds_dsi_reg = vdds_dsi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* source clock for DSI PLL. this could also be PCLKFREE */
|
||||
static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
|
||||
bool enable)
|
||||
|
@ -1592,22 +1625,9 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
|
|||
*/
|
||||
enable_hsclk = enable_hsdiv = true;
|
||||
|
||||
if (dsi->vdds_dsi_reg == NULL) {
|
||||
struct regulator *vdds_dsi;
|
||||
|
||||
vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
|
||||
|
||||
/* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */
|
||||
if (IS_ERR(vdds_dsi))
|
||||
vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO");
|
||||
|
||||
if (IS_ERR(vdds_dsi)) {
|
||||
DSSERR("can't get VDDS_DSI regulator\n");
|
||||
return PTR_ERR(vdds_dsi);
|
||||
}
|
||||
|
||||
dsi->vdds_dsi_reg = vdds_dsi;
|
||||
}
|
||||
r = dsi_regulator_init(dsidev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dsi_enable_pll_clock(dsidev, 1);
|
||||
/*
|
||||
|
@ -4122,7 +4142,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct omap_overlay_manager *mgr = dsi->output.manager;
|
||||
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
|
||||
struct omap_dss_output *out = &dsi->output;
|
||||
struct omap_dss_device *out = &dsi->output;
|
||||
u8 data_type;
|
||||
u16 word_count;
|
||||
int r;
|
||||
|
@ -4581,12 +4601,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_lock(&dsi->lock);
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err_start_dev;
|
||||
}
|
||||
|
||||
r = dsi_runtime_get(dsidev);
|
||||
if (r)
|
||||
goto err_get_dsi;
|
||||
|
@ -4607,8 +4621,6 @@ err_init_dsi:
|
|||
dsi_enable_pll_clock(dsidev, 0);
|
||||
dsi_runtime_put(dsidev);
|
||||
err_get_dsi:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err_start_dev:
|
||||
mutex_unlock(&dsi->lock);
|
||||
DSSDBG("dsi_display_enable FAILED\n");
|
||||
return r;
|
||||
|
@ -4637,8 +4649,6 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
|
|||
dsi_runtime_put(dsidev);
|
||||
dsi_enable_pll_clock(dsidev, 0);
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
||||
mutex_unlock(&dsi->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_dsi_display_disable);
|
||||
|
@ -5225,34 +5235,6 @@ static enum omap_channel dsi_get_channel(int module_id)
|
|||
}
|
||||
}
|
||||
|
||||
static int dsi_init_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct platform_device *dsidev =
|
||||
dsi_get_dsidev_from_id(dssdev->phy.dsi.module);
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
DSSDBG("DSI init\n");
|
||||
|
||||
if (dsi->vdds_dsi_reg == NULL) {
|
||||
struct regulator *vdds_dsi;
|
||||
|
||||
vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
|
||||
|
||||
/* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */
|
||||
if (IS_ERR(vdds_dsi))
|
||||
vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO");
|
||||
|
||||
if (IS_ERR(vdds_dsi)) {
|
||||
DSSERR("can't get VDDS_DSI regulator\n");
|
||||
return PTR_ERR(vdds_dsi);
|
||||
}
|
||||
|
||||
dsi->vdds_dsi_reg = vdds_dsi;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
|
||||
{
|
||||
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
||||
|
@ -5410,19 +5392,16 @@ static int dsi_probe_pdata(struct platform_device *dsidev)
|
|||
if (!plat_dssdev)
|
||||
return 0;
|
||||
|
||||
r = dsi_regulator_init(dsidev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev = dss_alloc_and_init_device(&dsidev->dev);
|
||||
if (!dssdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dss_copy_device_pdata(dssdev, plat_dssdev);
|
||||
|
||||
r = dsi_init_display(dssdev);
|
||||
if (r) {
|
||||
DSSERR("device %s init failed: %d\n", dssdev->name, r);
|
||||
dss_put_device(dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = omapdss_output_set_device(&dsi->output, dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
|
@ -5442,28 +5421,113 @@ static int dsi_probe_pdata(struct platform_device *dsidev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
r = dsi_regulator_init(dsidev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omapdss_output_set_device(dssdev, dst);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dssdev->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
WARN_ON(dst != dssdev->device);
|
||||
|
||||
if (dst != dssdev->device)
|
||||
return;
|
||||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_dsi_ops dsi_ops = {
|
||||
.connect = dsi_connect,
|
||||
.disconnect = dsi_disconnect,
|
||||
|
||||
.bus_lock = dsi_bus_lock,
|
||||
.bus_unlock = dsi_bus_unlock,
|
||||
|
||||
.enable = omapdss_dsi_display_enable,
|
||||
.disable = omapdss_dsi_display_disable,
|
||||
|
||||
.enable_hs = omapdss_dsi_vc_enable_hs,
|
||||
|
||||
.configure_pins = omapdss_dsi_configure_pins,
|
||||
.set_config = omapdss_dsi_set_config,
|
||||
|
||||
.enable_video_output = dsi_enable_video_output,
|
||||
.disable_video_output = dsi_disable_video_output,
|
||||
|
||||
.update = omap_dsi_update,
|
||||
|
||||
.enable_te = omapdss_dsi_enable_te,
|
||||
|
||||
.request_vc = omap_dsi_request_vc,
|
||||
.set_vc_id = omap_dsi_set_vc_id,
|
||||
.release_vc = omap_dsi_release_vc,
|
||||
|
||||
.dcs_write = dsi_vc_dcs_write,
|
||||
.dcs_write_nosync = dsi_vc_dcs_write_nosync,
|
||||
.dcs_read = dsi_vc_dcs_read,
|
||||
|
||||
.gen_write = dsi_vc_generic_write,
|
||||
.gen_write_nosync = dsi_vc_generic_write_nosync,
|
||||
.gen_read = dsi_vc_generic_read,
|
||||
|
||||
.bta_sync = dsi_vc_send_bta_sync,
|
||||
|
||||
.set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
|
||||
};
|
||||
|
||||
static void dsi_init_output(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct omap_dss_output *out = &dsi->output;
|
||||
struct omap_dss_device *out = &dsi->output;
|
||||
|
||||
out->pdev = dsidev;
|
||||
out->dev = &dsidev->dev;
|
||||
out->id = dsi->module_id == 0 ?
|
||||
OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
|
||||
|
||||
out->type = OMAP_DISPLAY_TYPE_DSI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_DSI;
|
||||
out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
|
||||
out->dispc_channel = dsi_get_channel(dsi->module_id);
|
||||
out->ops.dsi = &dsi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
dss_register_output(out);
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void dsi_uninit_output(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct omap_dss_output *out = &dsi->output;
|
||||
struct omap_dss_device *out = &dsi->output;
|
||||
|
||||
dss_unregister_output(out);
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
/* DSI1 HW IP initialisation */
|
||||
|
@ -5563,12 +5627,10 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
|
|||
|
||||
dsi_init_output(dsidev);
|
||||
|
||||
r = dsi_probe_pdata(dsidev);
|
||||
if (r) {
|
||||
dsi_runtime_put(dsidev);
|
||||
dsi_uninit_output(dsidev);
|
||||
pm_runtime_disable(&dsidev->dev);
|
||||
return r;
|
||||
if (dsidev->dev.platform_data) {
|
||||
r = dsi_probe_pdata(dsidev);
|
||||
if (r)
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
dsi_runtime_put(dsidev);
|
||||
|
@ -5586,6 +5648,9 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
|
|||
#endif
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
dsi_runtime_put(dsidev);
|
||||
dsi_uninit_output(dsidev);
|
||||
err_runtime_get:
|
||||
pm_runtime_disable(&dsidev->dev);
|
||||
return r;
|
||||
|
@ -5603,14 +5668,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
|
|||
|
||||
pm_runtime_disable(&dsidev->dev);
|
||||
|
||||
if (dsi->vdds_dsi_reg != NULL) {
|
||||
if (dsi->vdds_dsi_enabled) {
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
dsi->vdds_dsi_enabled = false;
|
||||
}
|
||||
|
||||
regulator_put(dsi->vdds_dsi_reg);
|
||||
dsi->vdds_dsi_reg = NULL;
|
||||
if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) {
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
dsi->vdds_dsi_enabled = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -157,7 +157,8 @@ static void dss_restore_context(void)
|
|||
|
||||
int dss_get_ctx_loss_count(void)
|
||||
{
|
||||
struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data;
|
||||
struct platform_device *core_pdev = dss_get_core_pdev();
|
||||
struct omap_dss_board_info *board_data = core_pdev->dev.platform_data;
|
||||
int cnt;
|
||||
|
||||
if (!board_data->get_context_loss_count)
|
||||
|
|
|
@ -179,23 +179,19 @@ void dss_put_device(struct omap_dss_device *dssdev);
|
|||
void dss_copy_device_pdata(struct omap_dss_device *dst,
|
||||
const struct omap_dss_device *src);
|
||||
|
||||
/* output */
|
||||
void dss_register_output(struct omap_dss_output *out);
|
||||
void dss_unregister_output(struct omap_dss_output *out);
|
||||
|
||||
/* display */
|
||||
int dss_suspend_all_devices(void);
|
||||
int dss_resume_all_devices(void);
|
||||
void dss_disable_all_devices(void);
|
||||
|
||||
int display_init_sysfs(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev);
|
||||
void display_uninit_sysfs(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev);
|
||||
int display_init_sysfs(struct platform_device *pdev);
|
||||
void display_uninit_sysfs(struct platform_device *pdev);
|
||||
|
||||
/* manager */
|
||||
int dss_init_overlay_managers(struct platform_device *pdev);
|
||||
void dss_uninit_overlay_managers(struct platform_device *pdev);
|
||||
int dss_init_overlay_managers(void);
|
||||
void dss_uninit_overlay_managers(void);
|
||||
int dss_init_overlay_managers_sysfs(struct platform_device *pdev);
|
||||
void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev);
|
||||
int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
|
||||
const struct omap_overlay_manager_info *info);
|
||||
int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
|
||||
|
@ -426,6 +422,7 @@ void dispc_mgr_set_clock_div(enum omap_channel channel,
|
|||
const struct dispc_clock_info *cinfo);
|
||||
int dispc_mgr_get_clock_div(enum omap_channel channel,
|
||||
struct dispc_clock_info *cinfo);
|
||||
void dispc_set_tv_pclk(unsigned long pclk);
|
||||
|
||||
u32 dispc_wb_get_framedone_irq(void);
|
||||
bool dispc_wb_go_busy(void);
|
||||
|
@ -437,17 +434,8 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
|
|||
bool mem_to_mem, const struct omap_video_timings *timings);
|
||||
|
||||
/* VENC */
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
int venc_init_platform_driver(void) __init;
|
||||
void venc_uninit_platform_driver(void) __exit;
|
||||
unsigned long venc_get_pixel_clock(void);
|
||||
#else
|
||||
static inline unsigned long venc_get_pixel_clock(void)
|
||||
{
|
||||
WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
int omapdss_venc_display_enable(struct omap_dss_device *dssdev);
|
||||
void omapdss_venc_display_disable(struct omap_dss_device *dssdev);
|
||||
void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
|
||||
|
@ -464,17 +452,8 @@ int venc_panel_init(void);
|
|||
void venc_panel_exit(void);
|
||||
|
||||
/* HDMI */
|
||||
#ifdef CONFIG_OMAP4_DSS_HDMI
|
||||
int hdmi_init_platform_driver(void) __init;
|
||||
void hdmi_uninit_platform_driver(void) __exit;
|
||||
unsigned long hdmi_get_pixel_clock(void);
|
||||
#else
|
||||
static inline unsigned long hdmi_get_pixel_clock(void)
|
||||
{
|
||||
WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
|
||||
void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
|
||||
int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev);
|
||||
|
|
|
@ -797,7 +797,6 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
|
|||
.phy_enable = ti_hdmi_4xxx_phy_enable,
|
||||
.phy_disable = ti_hdmi_4xxx_phy_disable,
|
||||
.read_edid = ti_hdmi_4xxx_read_edid,
|
||||
.detect = ti_hdmi_4xxx_detect,
|
||||
.pll_enable = ti_hdmi_4xxx_pll_enable,
|
||||
.pll_disable = ti_hdmi_4xxx_pll_disable,
|
||||
.video_enable = ti_hdmi_4xxx_wp_video_start,
|
||||
|
|
|
@ -70,7 +70,9 @@ static struct {
|
|||
int ls_oe_gpio;
|
||||
int hpd_gpio;
|
||||
|
||||
struct omap_dss_output output;
|
||||
bool core_enabled;
|
||||
|
||||
struct omap_dss_device output;
|
||||
} hdmi;
|
||||
|
||||
/*
|
||||
|
@ -328,6 +330,29 @@ static void hdmi_runtime_put(void)
|
|||
WARN_ON(r < 0 && r != -ENOSYS);
|
||||
}
|
||||
|
||||
static int hdmi_init_regulator(void)
|
||||
{
|
||||
struct regulator *reg;
|
||||
|
||||
if (hdmi.vdda_hdmi_dac_reg != NULL)
|
||||
return 0;
|
||||
|
||||
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
|
||||
|
||||
/* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */
|
||||
if (IS_ERR(reg))
|
||||
reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC");
|
||||
|
||||
if (IS_ERR(reg)) {
|
||||
DSSERR("can't get VDDA_HDMI_DAC regulator\n");
|
||||
return PTR_ERR(reg);
|
||||
}
|
||||
|
||||
hdmi.vdda_hdmi_dac_reg = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_init_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
@ -342,22 +367,9 @@ static int hdmi_init_display(struct omap_dss_device *dssdev)
|
|||
|
||||
dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version());
|
||||
|
||||
if (hdmi.vdda_hdmi_dac_reg == NULL) {
|
||||
struct regulator *reg;
|
||||
|
||||
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
|
||||
|
||||
/* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */
|
||||
if (IS_ERR(reg))
|
||||
reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC");
|
||||
|
||||
if (IS_ERR(reg)) {
|
||||
DSSERR("can't get VDDA_HDMI_DAC regulator\n");
|
||||
return PTR_ERR(reg);
|
||||
}
|
||||
|
||||
hdmi.vdda_hdmi_dac_reg = reg;
|
||||
}
|
||||
r = hdmi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
|
||||
if (r)
|
||||
|
@ -455,12 +467,6 @@ end: return cm;
|
|||
|
||||
}
|
||||
|
||||
unsigned long hdmi_get_pixel_clock(void)
|
||||
{
|
||||
/* HDMI Pixel Clock in Mhz */
|
||||
return hdmi.ip_data.cfg.timings.pixel_clock * 1000;
|
||||
}
|
||||
|
||||
static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
|
||||
struct hdmi_pll_info *pi)
|
||||
{
|
||||
|
@ -511,8 +517,10 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
|
|||
{
|
||||
int r;
|
||||
|
||||
gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
|
||||
gpio_set_value(hdmi.ls_oe_gpio, 1);
|
||||
if (gpio_is_valid(hdmi.ct_cp_hpd_gpio))
|
||||
gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
|
||||
if (gpio_is_valid(hdmi.ls_oe_gpio))
|
||||
gpio_set_value(hdmi.ls_oe_gpio, 1);
|
||||
|
||||
/* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
|
||||
udelay(300);
|
||||
|
@ -528,29 +536,37 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
|
|||
/* Make selection of HDMI in DSS */
|
||||
dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
|
||||
|
||||
hdmi.core_enabled = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_runtime_get:
|
||||
regulator_disable(hdmi.vdda_hdmi_dac_reg);
|
||||
err_vdac_enable:
|
||||
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
|
||||
gpio_set_value(hdmi.ls_oe_gpio, 0);
|
||||
if (gpio_is_valid(hdmi.ct_cp_hpd_gpio))
|
||||
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
|
||||
if (gpio_is_valid(hdmi.ls_oe_gpio))
|
||||
gpio_set_value(hdmi.ls_oe_gpio, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_power_off_core(struct omap_dss_device *dssdev)
|
||||
{
|
||||
hdmi.core_enabled = false;
|
||||
|
||||
hdmi_runtime_put();
|
||||
regulator_disable(hdmi.vdda_hdmi_dac_reg);
|
||||
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
|
||||
gpio_set_value(hdmi.ls_oe_gpio, 0);
|
||||
if (gpio_is_valid(hdmi.ct_cp_hpd_gpio))
|
||||
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
|
||||
if (gpio_is_valid(hdmi.ls_oe_gpio))
|
||||
gpio_set_value(hdmi.ls_oe_gpio, 0);
|
||||
}
|
||||
|
||||
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
struct omap_video_timings *p;
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
unsigned long phy;
|
||||
|
||||
r = hdmi_power_on_core(dssdev);
|
||||
|
@ -613,7 +629,7 @@ err_pll_enable:
|
|||
|
||||
static void hdmi_power_off_full(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
|
@ -653,9 +669,23 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
|
|||
if (t != NULL)
|
||||
hdmi.ip_data.cfg = *t;
|
||||
|
||||
dispc_set_tv_pclk(t->timings.pixel_clock * 1000);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
static void omapdss_hdmi_display_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
const struct hdmi_config *cfg;
|
||||
|
||||
cfg = hdmi_get_timings();
|
||||
if (cfg == NULL)
|
||||
cfg = &vesa_timings[0];
|
||||
|
||||
memcpy(timings, &cfg->timings, sizeof(cfg->timings));
|
||||
}
|
||||
|
||||
static void hdmi_dump_regs(struct seq_file *s)
|
||||
{
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
@ -700,7 +730,7 @@ bool omapdss_hdmi_detect(void)
|
|||
r = hdmi_runtime_get();
|
||||
BUG_ON(r);
|
||||
|
||||
r = hdmi.ip_data.ops->detect(&hdmi.ip_data);
|
||||
r = gpio_get_value(hdmi.hpd_gpio);
|
||||
|
||||
hdmi_runtime_put();
|
||||
mutex_unlock(&hdmi.lock);
|
||||
|
@ -710,7 +740,7 @@ bool omapdss_hdmi_detect(void)
|
|||
|
||||
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_output *out = dssdev->output;
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("ENTER hdmi_display_enable\n");
|
||||
|
@ -723,25 +753,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
|
|||
goto err0;
|
||||
}
|
||||
|
||||
hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = hdmi_power_on_full(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to power on device\n");
|
||||
goto err1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
|
@ -755,8 +775,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
|
|||
|
||||
hdmi_power_off_full(dssdev);
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
|
@ -768,8 +786,6 @@ int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
|
||||
|
||||
r = hdmi_power_on_core(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to power on device\n");
|
||||
|
@ -1033,24 +1049,219 @@ static int hdmi_probe_pdata(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version());
|
||||
|
||||
r = hdmi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omapdss_output_set_device(dssdev, dst);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
WARN_ON(dst != dssdev->device);
|
||||
|
||||
if (dst != dssdev->device)
|
||||
return;
|
||||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
}
|
||||
|
||||
static int hdmi_read_edid(struct omap_dss_device *dssdev,
|
||||
u8 *edid, int len)
|
||||
{
|
||||
bool need_enable;
|
||||
int r;
|
||||
|
||||
need_enable = hdmi.core_enabled == false;
|
||||
|
||||
if (need_enable) {
|
||||
r = omapdss_hdmi_core_enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = omapdss_hdmi_read_edid(edid, len);
|
||||
|
||||
if (need_enable)
|
||||
omapdss_hdmi_core_disable(dssdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (!hdmi_mode_has_audio()) {
|
||||
r = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = hdmi_audio_enable();
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
hdmi_audio_disable();
|
||||
}
|
||||
|
||||
static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return hdmi_audio_start();
|
||||
}
|
||||
|
||||
static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
hdmi_audio_stop();
|
||||
}
|
||||
|
||||
static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
bool r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
r = hdmi_mode_has_audio();
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
int r;
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (!hdmi_mode_has_audio()) {
|
||||
r = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = hdmi_audio_config(audio);
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct omapdss_hdmi_ops hdmi_ops = {
|
||||
.connect = hdmi_connect,
|
||||
.disconnect = hdmi_disconnect,
|
||||
|
||||
.enable = omapdss_hdmi_display_enable,
|
||||
.disable = omapdss_hdmi_display_disable,
|
||||
|
||||
.check_timings = omapdss_hdmi_display_check_timing,
|
||||
.set_timings = omapdss_hdmi_display_set_timing,
|
||||
.get_timings = omapdss_hdmi_display_get_timings,
|
||||
|
||||
.read_edid = hdmi_read_edid,
|
||||
|
||||
.audio_enable = omapdss_hdmi_audio_enable,
|
||||
.audio_disable = omapdss_hdmi_audio_disable,
|
||||
.audio_start = omapdss_hdmi_audio_start,
|
||||
.audio_stop = omapdss_hdmi_audio_stop,
|
||||
.audio_supported = omapdss_hdmi_audio_supported,
|
||||
.audio_config = omapdss_hdmi_audio_config,
|
||||
};
|
||||
|
||||
static void hdmi_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &hdmi.output;
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
|
||||
out->pdev = pdev;
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_HDMI;
|
||||
out->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
out->name = "hdmi.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
|
||||
out->ops.hdmi = &hdmi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
dss_register_output(out);
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit hdmi_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &hdmi.output;
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
|
||||
dss_unregister_output(out);
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
/* HDMI HW IP initialisation */
|
||||
|
@ -1071,6 +1282,12 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(hdmi.ip_data.base_wp))
|
||||
return PTR_ERR(hdmi.ip_data.base_wp);
|
||||
|
||||
hdmi.ip_data.irq = platform_get_irq(pdev, 0);
|
||||
if (hdmi.ip_data.irq < 0) {
|
||||
DSSERR("platform_get_irq failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = hdmi_get_clocks(pdev);
|
||||
if (r) {
|
||||
DSSERR("can't get clocks\n");
|
||||
|
@ -1084,6 +1301,10 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
|||
hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
|
||||
hdmi.ip_data.phy_offset = HDMI_PHY;
|
||||
|
||||
hdmi.ct_cp_hpd_gpio = -1;
|
||||
hdmi.ls_oe_gpio = -1;
|
||||
hdmi.hpd_gpio = -1;
|
||||
|
||||
hdmi_init_output(pdev);
|
||||
|
||||
r = hdmi_panel_init();
|
||||
|
@ -1094,15 +1315,19 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
|||
|
||||
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
|
||||
|
||||
r = hdmi_probe_pdata(pdev);
|
||||
if (r) {
|
||||
hdmi_panel_exit();
|
||||
hdmi_uninit_output(pdev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return r;
|
||||
if (pdev->dev.platform_data) {
|
||||
r = hdmi_probe_pdata(pdev);
|
||||
if (r)
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
hdmi_panel_exit();
|
||||
hdmi_uninit_output(pdev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit hdmi_remove_child(struct device *dev, void *data)
|
||||
|
|
|
@ -50,6 +50,7 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
|
|||
int r = 0;
|
||||
size_t len = size;
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
struct omap_dss_device *old_dssdev;
|
||||
|
||||
int match(struct omap_dss_device *dssdev, void *data)
|
||||
{
|
||||
|
@ -66,32 +67,44 @@ static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
|
|||
if (len > 0 && dssdev == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (dssdev)
|
||||
if (dssdev) {
|
||||
DSSDBG("display %s found\n", dssdev->name);
|
||||
|
||||
if (mgr->output) {
|
||||
r = mgr->unset_output(mgr);
|
||||
if (r) {
|
||||
DSSERR("failed to unset current output\n");
|
||||
if (omapdss_device_is_connected(dssdev)) {
|
||||
DSSERR("new display is already connected\n");
|
||||
r = -EINVAL;
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev)) {
|
||||
DSSERR("new display is not disabled\n");
|
||||
r = -EINVAL;
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
if (dssdev) {
|
||||
struct omap_dss_output *out = dssdev->output;
|
||||
|
||||
/*
|
||||
* a registered device should have an output connected to it
|
||||
* already
|
||||
*/
|
||||
if (!out) {
|
||||
DSSERR("device has no output connected to it\n");
|
||||
old_dssdev = mgr->get_device(mgr);
|
||||
if (old_dssdev) {
|
||||
if (omapdss_device_is_enabled(old_dssdev)) {
|
||||
DSSERR("old display is not disabled\n");
|
||||
r = -EINVAL;
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
r = mgr->set_output(mgr, out);
|
||||
old_dssdev->driver->disconnect(old_dssdev);
|
||||
}
|
||||
|
||||
if (dssdev) {
|
||||
r = dssdev->driver->connect(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to set manager output\n");
|
||||
DSSERR("failed to connect new device\n");
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
old_dssdev = mgr->get_device(mgr);
|
||||
if (old_dssdev != dssdev) {
|
||||
DSSERR("failed to connect device to this manager\n");
|
||||
dssdev->driver->disconnect(dssdev);
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
|
@ -509,4 +522,6 @@ void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
|
|||
{
|
||||
kobject_del(&mgr->kobj);
|
||||
kobject_put(&mgr->kobj);
|
||||
|
||||
memset(&mgr->kobj, 0, sizeof(mgr->kobj));
|
||||
}
|
||||
|
|
|
@ -36,9 +36,9 @@
|
|||
static int num_managers;
|
||||
static struct omap_overlay_manager *managers;
|
||||
|
||||
int dss_init_overlay_managers(struct platform_device *pdev)
|
||||
int dss_init_overlay_managers(void)
|
||||
{
|
||||
int i, r;
|
||||
int i;
|
||||
|
||||
num_managers = dss_feat_get_num_mgrs();
|
||||
|
||||
|
@ -76,6 +76,17 @@ int dss_init_overlay_managers(struct platform_device *pdev)
|
|||
dss_feat_get_supported_outputs(mgr->id);
|
||||
|
||||
INIT_LIST_HEAD(&mgr->overlays);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < num_managers; ++i) {
|
||||
struct omap_overlay_manager *mgr = &managers[i];
|
||||
|
||||
r = dss_manager_kobj_init(mgr, pdev);
|
||||
if (r)
|
||||
|
@ -85,18 +96,22 @@ int dss_init_overlay_managers(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void dss_uninit_overlay_managers(struct platform_device *pdev)
|
||||
void dss_uninit_overlay_managers(void)
|
||||
{
|
||||
kfree(managers);
|
||||
managers = NULL;
|
||||
num_managers = 0;
|
||||
}
|
||||
|
||||
void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_managers; ++i) {
|
||||
struct omap_overlay_manager *mgr = &managers[i];
|
||||
|
||||
dss_manager_kobj_uninit(mgr);
|
||||
}
|
||||
|
||||
kfree(managers);
|
||||
managers = NULL;
|
||||
num_managers = 0;
|
||||
}
|
||||
|
||||
int omap_dss_get_num_overlay_managers(void)
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
static LIST_HEAD(output_list);
|
||||
static DEFINE_MUTEX(output_lock);
|
||||
|
||||
int omapdss_output_set_device(struct omap_dss_output *out,
|
||||
int omapdss_output_set_device(struct omap_dss_device *out,
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
@ -41,7 +41,7 @@ int omapdss_output_set_device(struct omap_dss_output *out,
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (out->type != dssdev->type) {
|
||||
if (out->output_type != dssdev->type) {
|
||||
DSSERR("output type and display type don't match\n");
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
|
@ -60,7 +60,7 @@ err:
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_output_set_device);
|
||||
|
||||
int omapdss_output_unset_device(struct omap_dss_output *out)
|
||||
int omapdss_output_unset_device(struct omap_dss_device *out)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
@ -92,19 +92,22 @@ err:
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_output_unset_device);
|
||||
|
||||
void dss_register_output(struct omap_dss_output *out)
|
||||
int omapdss_register_output(struct omap_dss_device *out)
|
||||
{
|
||||
list_add_tail(&out->list, &output_list);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_register_output);
|
||||
|
||||
void dss_unregister_output(struct omap_dss_output *out)
|
||||
void omapdss_unregister_output(struct omap_dss_device *out)
|
||||
{
|
||||
list_del(&out->list);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_unregister_output);
|
||||
|
||||
struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
|
||||
struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id)
|
||||
{
|
||||
struct omap_dss_output *out;
|
||||
struct omap_dss_device *out;
|
||||
|
||||
list_for_each_entry(out, &output_list, list) {
|
||||
if (out->id == id)
|
||||
|
@ -115,6 +118,62 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
|
|||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_output);
|
||||
|
||||
struct omap_dss_device *omap_dss_find_output(const char *name)
|
||||
{
|
||||
struct omap_dss_device *out;
|
||||
|
||||
list_for_each_entry(out, &output_list, list) {
|
||||
if (strcmp(out->name, name) == 0)
|
||||
return omap_dss_get_device(out);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_find_output);
|
||||
|
||||
struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node)
|
||||
{
|
||||
struct omap_dss_device *out;
|
||||
|
||||
list_for_each_entry(out, &output_list, list) {
|
||||
if (out->dev->of_node == node)
|
||||
return omap_dss_get_device(out);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_find_output_by_node);
|
||||
|
||||
struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
while (dssdev->output)
|
||||
dssdev = dssdev->output;
|
||||
|
||||
if (dssdev->id != 0)
|
||||
return omap_dss_get_device(dssdev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_find_output_from_display);
|
||||
|
||||
struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out;
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
out = omapdss_find_output_from_display(dssdev);
|
||||
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
mgr = out->manager;
|
||||
|
||||
omap_dss_put_device(out);
|
||||
|
||||
return mgr;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_find_mgr_from_display);
|
||||
|
||||
static const struct dss_mgr_ops *dss_mgr_ops;
|
||||
|
||||
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops)
|
||||
|
@ -134,6 +193,20 @@ void dss_uninstall_mgr_ops(void)
|
|||
}
|
||||
EXPORT_SYMBOL(dss_uninstall_mgr_ops);
|
||||
|
||||
int dss_mgr_connect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
return dss_mgr_ops->connect(mgr, dst);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_connect);
|
||||
|
||||
void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dss_mgr_ops->disconnect(mgr, dst);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_disconnect);
|
||||
|
||||
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings)
|
||||
{
|
||||
|
|
|
@ -117,7 +117,7 @@ static struct {
|
|||
int data_lines;
|
||||
struct rfbi_timings intf_timings;
|
||||
|
||||
struct omap_dss_output output;
|
||||
struct omap_dss_device output;
|
||||
} rfbi;
|
||||
|
||||
static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
|
||||
|
@ -312,7 +312,7 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev,
|
|||
{
|
||||
u32 l;
|
||||
int r;
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = rfbi.output.manager;
|
||||
u16 width = rfbi.timings.x_res;
|
||||
u16 height = rfbi.timings.y_res;
|
||||
|
||||
|
@ -852,7 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s)
|
|||
|
||||
static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = rfbi.output.manager;
|
||||
struct dss_lcd_mgr_config mgr_config;
|
||||
|
||||
mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
|
||||
|
@ -890,7 +890,7 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
|
|||
|
||||
int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_output *out = dssdev->output;
|
||||
struct omap_dss_device *out = &rfbi.output;
|
||||
int r;
|
||||
|
||||
if (out == NULL || out->manager == NULL) {
|
||||
|
@ -902,12 +902,6 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = dss_mgr_register_framedone_handler(out->manager,
|
||||
framedone_callback, NULL);
|
||||
if (r) {
|
||||
|
@ -924,8 +918,6 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
return 0;
|
||||
err1:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
rfbi_runtime_put();
|
||||
return r;
|
||||
}
|
||||
|
@ -933,11 +925,10 @@ EXPORT_SYMBOL(omapdss_rfbi_display_enable);
|
|||
|
||||
void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_output *out = dssdev->output;
|
||||
struct omap_dss_device *out = &rfbi.output;
|
||||
|
||||
dss_mgr_unregister_framedone_handler(out->manager,
|
||||
framedone_callback, NULL);
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
||||
rfbi_runtime_put();
|
||||
}
|
||||
|
@ -1022,22 +1013,23 @@ static int rfbi_probe_pdata(struct platform_device *rfbidev)
|
|||
|
||||
static void rfbi_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &rfbi.output;
|
||||
struct omap_dss_device *out = &rfbi.output;
|
||||
|
||||
out->pdev = pdev;
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_DBI;
|
||||
out->type = OMAP_DISPLAY_TYPE_DBI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_DBI;
|
||||
out->name = "rfbi.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
dss_register_output(out);
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit rfbi_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &rfbi.output;
|
||||
struct omap_dss_device *out = &rfbi.output;
|
||||
|
||||
dss_unregister_output(out);
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
/* RFBI HW IP initialisation */
|
||||
|
@ -1093,15 +1085,16 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
|
|||
|
||||
rfbi_init_output(pdev);
|
||||
|
||||
r = rfbi_probe_pdata(pdev);
|
||||
if (r) {
|
||||
rfbi_uninit_output(pdev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return r;
|
||||
if (pdev->dev.platform_data) {
|
||||
r = rfbi_probe_pdata(pdev);
|
||||
if (r)
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
rfbi_uninit_output(pdev);
|
||||
err_runtime_get:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return r;
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
|
||||
bool update_enabled;
|
||||
struct regulator *vdds_sdi_reg;
|
||||
|
||||
|
@ -38,7 +40,7 @@ static struct {
|
|||
struct omap_video_timings timings;
|
||||
int datapairs;
|
||||
|
||||
struct omap_dss_output output;
|
||||
struct omap_dss_device output;
|
||||
} sdi;
|
||||
|
||||
struct sdi_clk_calc_ctx {
|
||||
|
@ -109,7 +111,7 @@ static int sdi_calc_clock_div(unsigned long pclk,
|
|||
|
||||
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
|
||||
sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
|
||||
|
||||
|
@ -124,7 +126,7 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
|
|||
|
||||
int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_output *out = dssdev->output;
|
||||
struct omap_dss_device *out = &sdi.output;
|
||||
struct omap_video_timings *t = &sdi.timings;
|
||||
struct dss_clock_info dss_cinfo;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
|
@ -136,12 +138,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err_start_dev;
|
||||
}
|
||||
|
||||
r = regulator_enable(sdi.vdds_sdi_reg);
|
||||
if (r)
|
||||
goto err_reg_enable;
|
||||
|
@ -213,15 +209,13 @@ err_calc_clock_div:
|
|||
err_get_dispc:
|
||||
regulator_disable(sdi.vdds_sdi_reg);
|
||||
err_reg_enable:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err_start_dev:
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_sdi_display_enable);
|
||||
|
||||
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
|
@ -230,8 +224,6 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
|
|||
dispc_runtime_put();
|
||||
|
||||
regulator_disable(sdi.vdds_sdi_reg);
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_sdi_display_disable);
|
||||
|
||||
|
@ -242,29 +234,51 @@ void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_sdi_set_timings);
|
||||
|
||||
static void sdi_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
*timings = sdi.timings;
|
||||
}
|
||||
|
||||
static int sdi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
|
||||
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->pixel_clock == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
|
||||
{
|
||||
sdi.datapairs = datapairs;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_sdi_set_datapairs);
|
||||
|
||||
static int sdi_init_display(struct omap_dss_device *dssdev)
|
||||
static int sdi_init_regulator(void)
|
||||
{
|
||||
DSSDBG("SDI init\n");
|
||||
struct regulator *vdds_sdi;
|
||||
|
||||
if (sdi.vdds_sdi_reg == NULL) {
|
||||
struct regulator *vdds_sdi;
|
||||
if (sdi.vdds_sdi_reg)
|
||||
return 0;
|
||||
|
||||
vdds_sdi = dss_get_vdds_sdi();
|
||||
vdds_sdi = dss_get_vdds_sdi();
|
||||
|
||||
if (IS_ERR(vdds_sdi)) {
|
||||
vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi");
|
||||
if (IS_ERR(vdds_sdi)) {
|
||||
DSSERR("can't get VDDS_SDI regulator\n");
|
||||
return PTR_ERR(vdds_sdi);
|
||||
}
|
||||
|
||||
sdi.vdds_sdi_reg = vdds_sdi;
|
||||
}
|
||||
|
||||
sdi.vdds_sdi_reg = vdds_sdi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -313,7 +327,7 @@ static int sdi_probe_pdata(struct platform_device *sdidev)
|
|||
|
||||
dss_copy_device_pdata(dssdev, plat_dssdev);
|
||||
|
||||
r = sdi_init_display(dssdev);
|
||||
r = sdi_init_regulator();
|
||||
if (r) {
|
||||
DSSERR("device %s init failed: %d\n", dssdev->name, r);
|
||||
dss_put_device(dssdev);
|
||||
|
@ -339,39 +353,104 @@ static int sdi_probe_pdata(struct platform_device *sdidev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sdi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
r = sdi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omapdss_output_set_device(dssdev, dst);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
WARN_ON(dst != dssdev->device);
|
||||
|
||||
if (dst != dssdev->device)
|
||||
return;
|
||||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_sdi_ops sdi_ops = {
|
||||
.connect = sdi_connect,
|
||||
.disconnect = sdi_disconnect,
|
||||
|
||||
.enable = omapdss_sdi_display_enable,
|
||||
.disable = omapdss_sdi_display_disable,
|
||||
|
||||
.check_timings = sdi_check_timings,
|
||||
.set_timings = omapdss_sdi_set_timings,
|
||||
.get_timings = sdi_get_timings,
|
||||
|
||||
.set_datapairs = omapdss_sdi_set_datapairs,
|
||||
};
|
||||
|
||||
static void sdi_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &sdi.output;
|
||||
struct omap_dss_device *out = &sdi.output;
|
||||
|
||||
out->pdev = pdev;
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_SDI;
|
||||
out->type = OMAP_DISPLAY_TYPE_SDI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_SDI;
|
||||
out->name = "sdi.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
|
||||
out->ops.sdi = &sdi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
dss_register_output(out);
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit sdi_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &sdi.output;
|
||||
struct omap_dss_device *out = &sdi.output;
|
||||
|
||||
dss_unregister_output(out);
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
static int omap_sdi_probe(struct platform_device *pdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
sdi.pdev = pdev;
|
||||
|
||||
sdi_init_output(pdev);
|
||||
|
||||
r = sdi_probe_pdata(pdev);
|
||||
if (r) {
|
||||
sdi_uninit_output(pdev);
|
||||
return r;
|
||||
if (pdev->dev.platform_data) {
|
||||
r = sdi_probe_pdata(pdev);
|
||||
if (r)
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
sdi_uninit_output(pdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit omap_sdi_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -73,8 +73,6 @@ struct ti_hdmi_ip_ops {
|
|||
|
||||
int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len);
|
||||
|
||||
bool (*detect)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
int (*pll_enable)(struct hdmi_ip_data *ip_data);
|
||||
|
||||
void (*pll_disable)(struct hdmi_ip_data *ip_data);
|
||||
|
@ -155,19 +153,18 @@ struct hdmi_ip_data {
|
|||
unsigned long core_av_offset;
|
||||
unsigned long pll_offset;
|
||||
unsigned long phy_offset;
|
||||
int irq;
|
||||
const struct ti_hdmi_ip_ops *ops;
|
||||
struct hdmi_config cfg;
|
||||
struct hdmi_pll_info pll_data;
|
||||
struct hdmi_core_infoframe_avi avi_cfg;
|
||||
|
||||
/* ti_hdmi_4xxx_ip private data. These should be in a separate struct */
|
||||
int hpd_gpio;
|
||||
struct mutex lock;
|
||||
};
|
||||
int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data);
|
||||
int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len);
|
||||
bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data);
|
||||
int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data);
|
||||
void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data);
|
||||
int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data);
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/gpio.h>
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
#include <sound/asound.h>
|
||||
#include <sound/asoundef.h>
|
||||
|
@ -38,6 +37,9 @@
|
|||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
#define HDMI_IRQ_LINK_CONNECT (1 << 25)
|
||||
#define HDMI_IRQ_LINK_DISCONNECT (1 << 26)
|
||||
|
||||
static inline void hdmi_write_reg(void __iomem *base_addr,
|
||||
const u16 idx, u32 val)
|
||||
{
|
||||
|
@ -233,36 +235,38 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data)
|
|||
hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF);
|
||||
}
|
||||
|
||||
static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
bool hpd;
|
||||
int r;
|
||||
|
||||
mutex_lock(&ip_data->lock);
|
||||
|
||||
hpd = gpio_get_value(ip_data->hpd_gpio);
|
||||
|
||||
if (hpd)
|
||||
r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);
|
||||
else
|
||||
r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
|
||||
|
||||
if (r) {
|
||||
DSSERR("Failed to %s PHY TX power\n",
|
||||
hpd ? "enable" : "disable");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
mutex_unlock(&ip_data->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static irqreturn_t hpd_irq_handler(int irq, void *data)
|
||||
static irqreturn_t hdmi_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct hdmi_ip_data *ip_data = data;
|
||||
void __iomem *wp_base = hdmi_wp_base(ip_data);
|
||||
u32 irqstatus;
|
||||
|
||||
hdmi_check_hpd_state(ip_data);
|
||||
irqstatus = hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS);
|
||||
hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS, irqstatus);
|
||||
/* flush posted write */
|
||||
hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS);
|
||||
|
||||
if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
|
||||
irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
|
||||
/*
|
||||
* If we get both connect and disconnect interrupts at the same
|
||||
* time, turn off the PHY, clear interrupts, and restart, which
|
||||
* raises connect interrupt if a cable is connected, or nothing
|
||||
* if cable is not connected.
|
||||
*/
|
||||
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
|
||||
|
||||
hdmi_write_reg(wp_base, HDMI_WP_IRQSTATUS,
|
||||
HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
|
||||
/* flush posted write */
|
||||
hdmi_read_reg(wp_base, HDMI_WP_IRQSTATUS);
|
||||
|
||||
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
|
||||
} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
|
||||
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);
|
||||
} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
|
||||
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -272,6 +276,12 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
|
|||
u16 r = 0;
|
||||
void __iomem *phy_base = hdmi_phy_base(ip_data);
|
||||
|
||||
hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_CLR,
|
||||
0xffffffff);
|
||||
|
||||
hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQSTATUS,
|
||||
HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
|
||||
|
||||
r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -297,29 +307,23 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
|
|||
/* Write to phy address 3 to change the polarity control */
|
||||
REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
|
||||
|
||||
r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio),
|
||||
NULL, hpd_irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT, "hpd", ip_data);
|
||||
r = request_threaded_irq(ip_data->irq, NULL, hdmi_irq_handler,
|
||||
IRQF_ONESHOT, "OMAP HDMI", ip_data);
|
||||
if (r) {
|
||||
DSSERR("HPD IRQ request failed\n");
|
||||
DSSERR("HDMI IRQ request failed\n");
|
||||
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = hdmi_check_hpd_state(ip_data);
|
||||
if (r) {
|
||||
free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data);
|
||||
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
|
||||
return r;
|
||||
}
|
||||
hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_IRQENABLE_SET,
|
||||
HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data);
|
||||
free_irq(ip_data->irq, ip_data);
|
||||
|
||||
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
|
||||
}
|
||||
|
@ -476,11 +480,6 @@ int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data,
|
|||
return l;
|
||||
}
|
||||
|
||||
bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data)
|
||||
{
|
||||
return gpio_get_value(ip_data->hpd_gpio);
|
||||
}
|
||||
|
||||
static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
|
||||
struct hdmi_core_infoframe_avi *avi_cfg,
|
||||
struct hdmi_core_packet_enable_repeat *repeat_cfg)
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#define HDMI_WP_IRQSTATUS 0x28
|
||||
#define HDMI_WP_PWR_CTRL 0x40
|
||||
#define HDMI_WP_IRQENABLE_SET 0x2C
|
||||
#define HDMI_WP_IRQENABLE_CLR 0x30
|
||||
#define HDMI_WP_VIDEO_CFG 0x50
|
||||
#define HDMI_WP_VIDEO_SIZE 0x60
|
||||
#define HDMI_WP_VIDEO_TIMING_H 0x68
|
||||
|
|
|
@ -304,7 +304,7 @@ static struct {
|
|||
enum omap_dss_venc_type type;
|
||||
bool invert_polarity;
|
||||
|
||||
struct omap_dss_output output;
|
||||
struct omap_dss_device output;
|
||||
} venc;
|
||||
|
||||
static inline void venc_write_reg(int idx, u32 val)
|
||||
|
@ -429,7 +429,7 @@ static const struct venc_config *venc_timings_to_config(
|
|||
|
||||
static int venc_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = venc.output.manager;
|
||||
u32 l;
|
||||
int r;
|
||||
|
||||
|
@ -480,7 +480,7 @@ err0:
|
|||
|
||||
static void venc_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = dssdev->output->manager;
|
||||
struct omap_overlay_manager *mgr = venc.output.manager;
|
||||
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
|
||||
dss_set_dac_pwrdn_bgz(0);
|
||||
|
@ -492,15 +492,9 @@ static void venc_power_off(struct omap_dss_device *dssdev)
|
|||
venc_runtime_put();
|
||||
}
|
||||
|
||||
unsigned long venc_get_pixel_clock(void)
|
||||
{
|
||||
/* VENC Pixel Clock in Mhz */
|
||||
return 13500000;
|
||||
}
|
||||
|
||||
int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_output *out = dssdev->output;
|
||||
struct omap_dss_device *out = &venc.output;
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_display_enable\n");
|
||||
|
@ -513,23 +507,15 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
|
|||
goto err0;
|
||||
}
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = venc_power_on(dssdev);
|
||||
if (r)
|
||||
goto err1;
|
||||
goto err0;
|
||||
|
||||
venc.wss_data = 0;
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
return r;
|
||||
|
@ -543,8 +529,6 @@ void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
|
|||
|
||||
venc_power_off(dssdev);
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
|
@ -561,6 +545,8 @@ void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
|
|||
|
||||
venc.timings = *timings;
|
||||
|
||||
dispc_set_tv_pclk(13500000);
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
|
@ -578,6 +564,16 @@ int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void venc_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
*timings = venc.timings;
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev)
|
||||
{
|
||||
/* Invert due to VENC_L21_WC_CTL:INV=1 */
|
||||
|
@ -633,23 +629,22 @@ void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
|
|||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
static int venc_init_display(struct omap_dss_device *dssdev)
|
||||
static int venc_init_regulator(void)
|
||||
{
|
||||
DSSDBG("init_display\n");
|
||||
struct regulator *vdda_dac;
|
||||
|
||||
if (venc.vdda_dac_reg == NULL) {
|
||||
struct regulator *vdda_dac;
|
||||
if (venc.vdda_dac_reg != NULL)
|
||||
return 0;
|
||||
|
||||
vdda_dac = regulator_get(&venc.pdev->dev, "vdda_dac");
|
||||
vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
|
||||
|
||||
if (IS_ERR(vdda_dac)) {
|
||||
DSSERR("can't get VDDA_DAC regulator\n");
|
||||
return PTR_ERR(vdda_dac);
|
||||
}
|
||||
|
||||
venc.vdda_dac_reg = vdda_dac;
|
||||
if (IS_ERR(vdda_dac)) {
|
||||
DSSERR("can't get VDDA_DAC regulator\n");
|
||||
return PTR_ERR(vdda_dac);
|
||||
}
|
||||
|
||||
venc.vdda_dac_reg = vdda_dac;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -765,19 +760,16 @@ static int venc_probe_pdata(struct platform_device *vencdev)
|
|||
if (!plat_dssdev)
|
||||
return 0;
|
||||
|
||||
r = venc_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev = dss_alloc_and_init_device(&vencdev->dev);
|
||||
if (!dssdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dss_copy_device_pdata(dssdev, plat_dssdev);
|
||||
|
||||
r = venc_init_display(dssdev);
|
||||
if (r) {
|
||||
DSSERR("device %s init failed: %d\n", dssdev->name, r);
|
||||
dss_put_device(dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = omapdss_output_set_device(&venc.output, dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
|
@ -797,24 +789,87 @@ static int venc_probe_pdata(struct platform_device *vencdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int venc_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
r = venc_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omapdss_output_set_device(dssdev, dst);
|
||||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void venc_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
WARN_ON(dst != dssdev->device);
|
||||
|
||||
if (dst != dssdev->device)
|
||||
return;
|
||||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_atv_ops venc_ops = {
|
||||
.connect = venc_connect,
|
||||
.disconnect = venc_disconnect,
|
||||
|
||||
.enable = omapdss_venc_display_enable,
|
||||
.disable = omapdss_venc_display_disable,
|
||||
|
||||
.check_timings = omapdss_venc_check_timings,
|
||||
.set_timings = omapdss_venc_set_timings,
|
||||
.get_timings = venc_get_timings,
|
||||
|
||||
.set_type = omapdss_venc_set_type,
|
||||
.invert_vid_out_polarity = omapdss_venc_invert_vid_out_polarity,
|
||||
|
||||
.set_wss = omapdss_venc_set_wss,
|
||||
.get_wss = omapdss_venc_get_wss,
|
||||
};
|
||||
|
||||
static void venc_init_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &venc.output;
|
||||
struct omap_dss_device *out = &venc.output;
|
||||
|
||||
out->pdev = pdev;
|
||||
out->dev = &pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_VENC;
|
||||
out->type = OMAP_DISPLAY_TYPE_VENC;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_VENC;
|
||||
out->name = "venc.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
|
||||
out->ops.atv = &venc_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
dss_register_output(out);
|
||||
omapdss_register_output(out);
|
||||
}
|
||||
|
||||
static void __exit venc_uninit_output(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_output *out = &venc.output;
|
||||
struct omap_dss_device *out = &venc.output;
|
||||
|
||||
dss_unregister_output(out);
|
||||
omapdss_unregister_output(out);
|
||||
}
|
||||
|
||||
/* VENC HW IP initialisation */
|
||||
|
@ -866,16 +921,17 @@ static int omap_venchw_probe(struct platform_device *pdev)
|
|||
|
||||
venc_init_output(pdev);
|
||||
|
||||
r = venc_probe_pdata(pdev);
|
||||
if (r) {
|
||||
venc_panel_exit();
|
||||
venc_uninit_output(pdev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return r;
|
||||
if (pdev->dev.platform_data) {
|
||||
r = venc_probe_pdata(pdev);
|
||||
if (r)
|
||||
goto err_probe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
venc_panel_exit();
|
||||
venc_uninit_output(pdev);
|
||||
err_panel_init:
|
||||
err_runtime_get:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
@ -886,11 +942,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev)
|
|||
{
|
||||
dss_unregister_child_devices(&pdev->dev);
|
||||
|
||||
if (venc.vdda_dac_reg != NULL) {
|
||||
regulator_put(venc.vdda_dac_reg);
|
||||
venc.vdda_dac_reg = NULL;
|
||||
}
|
||||
|
||||
venc_panel_exit();
|
||||
|
||||
venc_uninit_output(pdev);
|
||||
|
|
|
@ -107,19 +107,19 @@ static int venc_panel_probe(struct omap_dss_device *dssdev)
|
|||
|
||||
dssdev->panel.timings = default_timings;
|
||||
|
||||
return device_create_file(&dssdev->dev, &dev_attr_output_type);
|
||||
return device_create_file(dssdev->dev, &dev_attr_output_type);
|
||||
}
|
||||
|
||||
static void venc_panel_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
device_remove_file(&dssdev->dev, &dev_attr_output_type);
|
||||
device_remove_file(dssdev->dev, &dev_attr_output_type);
|
||||
}
|
||||
|
||||
static int venc_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_dbg(&dssdev->dev, "venc_panel_enable\n");
|
||||
dev_dbg(dssdev->dev, "venc_panel_enable\n");
|
||||
|
||||
mutex_lock(&venc_panel.lock);
|
||||
|
||||
|
@ -150,7 +150,7 @@ err:
|
|||
|
||||
static void venc_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "venc_panel_disable\n");
|
||||
dev_dbg(dssdev->dev, "venc_panel_disable\n");
|
||||
|
||||
mutex_lock(&venc_panel.lock);
|
||||
|
||||
|
@ -167,7 +167,7 @@ end:
|
|||
static void venc_panel_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "venc_panel_set_timings\n");
|
||||
dev_dbg(dssdev->dev, "venc_panel_set_timings\n");
|
||||
|
||||
mutex_lock(&venc_panel.lock);
|
||||
|
||||
|
@ -180,21 +180,21 @@ static void venc_panel_set_timings(struct omap_dss_device *dssdev,
|
|||
static int venc_panel_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "venc_panel_check_timings\n");
|
||||
dev_dbg(dssdev->dev, "venc_panel_check_timings\n");
|
||||
|
||||
return omapdss_venc_check_timings(dssdev, timings);
|
||||
}
|
||||
|
||||
static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "venc_panel_get_wss\n");
|
||||
dev_dbg(dssdev->dev, "venc_panel_get_wss\n");
|
||||
|
||||
return omapdss_venc_get_wss(dssdev);
|
||||
}
|
||||
|
||||
static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
|
||||
{
|
||||
dev_dbg(&dssdev->dev, "venc_panel_set_wss\n");
|
||||
dev_dbg(dssdev->dev, "venc_panel_set_wss\n");
|
||||
|
||||
return omapdss_venc_set_wss(dssdev, wss);
|
||||
}
|
||||
|
|
|
@ -770,12 +770,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
|
|||
|
||||
case OMAPFB_WAITFORVSYNC:
|
||||
DBG("ioctl WAITFORVSYNC\n");
|
||||
if (!display || !display->output || !display->output->manager) {
|
||||
|
||||
if (!display) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
mgr = display->output->manager;
|
||||
mgr = omapdss_find_mgr_from_display(display);
|
||||
if (!mgr) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
r = mgr->wait_for_vsync(mgr);
|
||||
break;
|
||||
|
|
|
@ -1853,6 +1853,8 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
|
|||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
|
||||
dssdev->driver->disable(dssdev);
|
||||
|
||||
dssdev->driver->disconnect(dssdev);
|
||||
|
||||
omap_dss_put_device(dssdev);
|
||||
}
|
||||
|
||||
|
@ -2363,27 +2365,26 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev,
|
|||
int i, r;
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
if (!def_dssdev->output) {
|
||||
dev_err(fbdev->dev, "no output for the default display\n");
|
||||
return -EINVAL;
|
||||
r = def_dssdev->driver->connect(def_dssdev);
|
||||
if (r) {
|
||||
dev_err(fbdev->dev, "failed to connect default display\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
for (i = 0; i < fbdev->num_displays; ++i) {
|
||||
struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
|
||||
struct omap_dss_output *out = dssdev->output;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(out->dispc_channel);
|
||||
|
||||
if (!mgr || !out)
|
||||
if (dssdev == def_dssdev)
|
||||
continue;
|
||||
|
||||
if (mgr->output)
|
||||
mgr->unset_output(mgr);
|
||||
|
||||
mgr->set_output(mgr, out);
|
||||
/*
|
||||
* We don't care if the connect succeeds or not. We just want to
|
||||
* connect as many displays as possible.
|
||||
*/
|
||||
dssdev->driver->connect(dssdev);
|
||||
}
|
||||
|
||||
mgr = def_dssdev->output->manager;
|
||||
mgr = omapdss_find_mgr_from_display(def_dssdev);
|
||||
|
||||
if (!mgr) {
|
||||
dev_err(fbdev->dev, "no ovl manager for the default display\n");
|
||||
|
@ -2502,7 +2503,7 @@ static int omapfb_probe(struct platform_device *pdev)
|
|||
|
||||
if (def_display == NULL) {
|
||||
dev_err(fbdev->dev, "failed to find default display\n");
|
||||
r = -EINVAL;
|
||||
r = -EPROBE_DEFER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
|
|
@ -710,7 +710,6 @@ err_misc_deregister:
|
|||
misc_deregister(&priv->misc_dev);
|
||||
|
||||
err_free_priv:
|
||||
platform_set_drvdata(dev, NULL);
|
||||
free_buffers(dev, priv);
|
||||
kfree(priv);
|
||||
return ret;
|
||||
|
@ -728,7 +727,6 @@ static int pxa3xx_gcu_remove(struct platform_device *dev)
|
|||
priv->shared, priv->shared_phys);
|
||||
iounmap(priv->mmio_base);
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
platform_set_drvdata(dev, NULL);
|
||||
clk_disable(priv->clk);
|
||||
free_buffers(dev, priv);
|
||||
kfree(priv);
|
||||
|
|
|
@ -2256,7 +2256,6 @@ failed_free_res:
|
|||
release_mem_region(r->start, resource_size(r));
|
||||
failed_fbi:
|
||||
clk_put(fbi->clk);
|
||||
platform_set_drvdata(dev, NULL);
|
||||
kfree(fbi);
|
||||
failed:
|
||||
return ret;
|
||||
|
|
|
@ -1005,7 +1005,6 @@ release_regs:
|
|||
release_mem:
|
||||
release_mem_region(res->start, size);
|
||||
dealloc_fb:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
framebuffer_release(fbinfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1051,7 +1050,6 @@ static int s3c2410fb_remove(struct platform_device *pdev)
|
|||
|
||||
release_mem_region(info->mem->start, resource_size(info->mem));
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
framebuffer_release(fbinfo);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1271,7 +1271,6 @@ static int sa1100fb_probe(struct platform_device *pdev)
|
|||
failed:
|
||||
if (fbi)
|
||||
iounmap(fbi->base);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(fbi);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
return ret;
|
||||
|
|
|
@ -571,7 +571,6 @@ static int sh7760fb_remove(struct platform_device *dev)
|
|||
iounmap(par->base);
|
||||
release_mem_region(par->ioarea->start, resource_size(par->ioarea));
|
||||
framebuffer_release(info);
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -567,7 +567,6 @@ static int sh_mipi_remove(struct platform_device *pdev)
|
|||
iounmap(mipi->base);
|
||||
if (res)
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(mipi);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1622,7 +1622,7 @@ static int ufx_usb_probe(struct usb_interface *interface,
|
|||
{
|
||||
struct usb_device *usbdev;
|
||||
struct ufx_data *dev;
|
||||
struct fb_info *info = 0;
|
||||
struct fb_info *info = NULL;
|
||||
int retval = -ENOMEM;
|
||||
u32 id_rev, fpga_rev;
|
||||
|
||||
|
|
|
@ -16,24 +16,50 @@
|
|||
#include <linux/pwm.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define SSD1307FB_WIDTH 96
|
||||
#define SSD1307FB_HEIGHT 16
|
||||
|
||||
#define SSD1307FB_DATA 0x40
|
||||
#define SSD1307FB_COMMAND 0x80
|
||||
|
||||
#define SSD1307FB_SET_ADDRESS_MODE 0x20
|
||||
#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00)
|
||||
#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01)
|
||||
#define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02)
|
||||
#define SSD1307FB_SET_COL_RANGE 0x21
|
||||
#define SSD1307FB_SET_PAGE_RANGE 0x22
|
||||
#define SSD1307FB_CONTRAST 0x81
|
||||
#define SSD1307FB_CHARGE_PUMP 0x8d
|
||||
#define SSD1307FB_SEG_REMAP_ON 0xa1
|
||||
#define SSD1307FB_DISPLAY_OFF 0xae
|
||||
#define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8
|
||||
#define SSD1307FB_DISPLAY_ON 0xaf
|
||||
#define SSD1307FB_START_PAGE_ADDRESS 0xb0
|
||||
#define SSD1307FB_SET_DISPLAY_OFFSET 0xd3
|
||||
#define SSD1307FB_SET_CLOCK_FREQ 0xd5
|
||||
#define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9
|
||||
#define SSD1307FB_SET_COM_PINS_CONFIG 0xda
|
||||
#define SSD1307FB_SET_VCOMH 0xdb
|
||||
|
||||
struct ssd1307fb_par;
|
||||
|
||||
struct ssd1307fb_ops {
|
||||
int (*init)(struct ssd1307fb_par *);
|
||||
int (*remove)(struct ssd1307fb_par *);
|
||||
};
|
||||
|
||||
struct ssd1307fb_par {
|
||||
struct i2c_client *client;
|
||||
u32 height;
|
||||
struct fb_info *info;
|
||||
struct ssd1307fb_ops *ops;
|
||||
u32 page_offset;
|
||||
struct pwm_device *pwm;
|
||||
u32 pwm_period;
|
||||
int reset;
|
||||
u32 width;
|
||||
};
|
||||
|
||||
struct ssd1307fb_array {
|
||||
u8 type;
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
static struct fb_fix_screeninfo ssd1307fb_fix = {
|
||||
|
@ -43,68 +69,87 @@ static struct fb_fix_screeninfo ssd1307fb_fix = {
|
|||
.xpanstep = 0,
|
||||
.ypanstep = 0,
|
||||
.ywrapstep = 0,
|
||||
.line_length = SSD1307FB_WIDTH / 8,
|
||||
.accel = FB_ACCEL_NONE,
|
||||
};
|
||||
|
||||
static struct fb_var_screeninfo ssd1307fb_var = {
|
||||
.xres = SSD1307FB_WIDTH,
|
||||
.yres = SSD1307FB_HEIGHT,
|
||||
.xres_virtual = SSD1307FB_WIDTH,
|
||||
.yres_virtual = SSD1307FB_HEIGHT,
|
||||
.bits_per_pixel = 1,
|
||||
};
|
||||
|
||||
static int ssd1307fb_write_array(struct i2c_client *client, u8 type, u8 *cmd, u32 len)
|
||||
static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
|
||||
{
|
||||
u8 *buf;
|
||||
int ret = 0;
|
||||
struct ssd1307fb_array *array;
|
||||
|
||||
buf = kzalloc(len + 1, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
dev_err(&client->dev, "Couldn't allocate sending buffer.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL);
|
||||
if (!array)
|
||||
return NULL;
|
||||
|
||||
buf[0] = type;
|
||||
memcpy(buf + 1, cmd, len);
|
||||
array->type = type;
|
||||
|
||||
ret = i2c_master_send(client, buf, len + 1);
|
||||
if (ret != len + 1) {
|
||||
dev_err(&client->dev, "Couldn't send I2C command.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
return array;
|
||||
}
|
||||
|
||||
static inline int ssd1307fb_write_cmd_array(struct i2c_client *client, u8 *cmd, u32 len)
|
||||
static int ssd1307fb_write_array(struct i2c_client *client,
|
||||
struct ssd1307fb_array *array, u32 len)
|
||||
{
|
||||
return ssd1307fb_write_array(client, SSD1307FB_COMMAND, cmd, len);
|
||||
int ret;
|
||||
|
||||
len += sizeof(struct ssd1307fb_array);
|
||||
|
||||
ret = i2c_master_send(client, (u8 *)array, len);
|
||||
if (ret != len) {
|
||||
dev_err(&client->dev, "Couldn't send I2C command.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
|
||||
{
|
||||
return ssd1307fb_write_cmd_array(client, &cmd, 1);
|
||||
}
|
||||
struct ssd1307fb_array *array;
|
||||
int ret;
|
||||
|
||||
static inline int ssd1307fb_write_data_array(struct i2c_client *client, u8 *cmd, u32 len)
|
||||
{
|
||||
return ssd1307fb_write_array(client, SSD1307FB_DATA, cmd, len);
|
||||
array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND);
|
||||
if (!array)
|
||||
return -ENOMEM;
|
||||
|
||||
array->data[0] = cmd;
|
||||
|
||||
ret = ssd1307fb_write_array(client, array, 1);
|
||||
kfree(array);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int ssd1307fb_write_data(struct i2c_client *client, u8 data)
|
||||
{
|
||||
return ssd1307fb_write_data_array(client, &data, 1);
|
||||
struct ssd1307fb_array *array;
|
||||
int ret;
|
||||
|
||||
array = ssd1307fb_alloc_array(1, SSD1307FB_DATA);
|
||||
if (!array)
|
||||
return -ENOMEM;
|
||||
|
||||
array->data[0] = data;
|
||||
|
||||
ret = ssd1307fb_write_array(client, array, 1);
|
||||
kfree(array);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ssd1307fb_update_display(struct ssd1307fb_par *par)
|
||||
{
|
||||
struct ssd1307fb_array *array;
|
||||
u8 *vmem = par->info->screen_base;
|
||||
int i, j, k;
|
||||
|
||||
array = ssd1307fb_alloc_array(par->width * par->height / 8,
|
||||
SSD1307FB_DATA);
|
||||
if (!array)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The screen is divided in pages, each having a height of 8
|
||||
* pixels, and the width of the screen. When sending a byte of
|
||||
|
@ -134,24 +179,23 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par)
|
|||
* (5) A4 B4 C4 D4 E4 F4 G4 H4
|
||||
*/
|
||||
|
||||
for (i = 0; i < (SSD1307FB_HEIGHT / 8); i++) {
|
||||
ssd1307fb_write_cmd(par->client, SSD1307FB_START_PAGE_ADDRESS + (i + 1));
|
||||
ssd1307fb_write_cmd(par->client, 0x00);
|
||||
ssd1307fb_write_cmd(par->client, 0x10);
|
||||
|
||||
for (j = 0; j < SSD1307FB_WIDTH; j++) {
|
||||
u8 buf = 0;
|
||||
for (i = 0; i < (par->height / 8); i++) {
|
||||
for (j = 0; j < par->width; j++) {
|
||||
u32 array_idx = i * par->width + j;
|
||||
array->data[array_idx] = 0;
|
||||
for (k = 0; k < 8; k++) {
|
||||
u32 page_length = SSD1307FB_WIDTH * i;
|
||||
u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8;
|
||||
u32 page_length = par->width * i;
|
||||
u32 index = page_length + (par->width * k + j) / 8;
|
||||
u8 byte = *(vmem + index);
|
||||
u8 bit = byte & (1 << (j % 8));
|
||||
bit = bit >> (j % 8);
|
||||
buf |= bit << k;
|
||||
array->data[array_idx] |= bit << k;
|
||||
}
|
||||
ssd1307fb_write_data(par->client, buf);
|
||||
}
|
||||
}
|
||||
|
||||
ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
|
||||
kfree(array);
|
||||
}
|
||||
|
||||
|
||||
|
@ -227,16 +271,167 @@ static struct fb_deferred_io ssd1307fb_defio = {
|
|||
.deferred_io = ssd1307fb_deferred_io,
|
||||
};
|
||||
|
||||
static int ssd1307fb_ssd1307_init(struct ssd1307fb_par *par)
|
||||
{
|
||||
int ret;
|
||||
|
||||
par->pwm = pwm_get(&par->client->dev, NULL);
|
||||
if (IS_ERR(par->pwm)) {
|
||||
dev_err(&par->client->dev, "Could not get PWM from device tree!\n");
|
||||
return PTR_ERR(par->pwm);
|
||||
}
|
||||
|
||||
par->pwm_period = pwm_get_period(par->pwm);
|
||||
/* Enable the PWM */
|
||||
pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
|
||||
pwm_enable(par->pwm);
|
||||
|
||||
dev_dbg(&par->client->dev, "Using PWM%d with a %dns period.\n",
|
||||
par->pwm->pwm, par->pwm_period);
|
||||
|
||||
/* Map column 127 of the OLED to segment 0 */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Turn on the display */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssd1307fb_ssd1307_remove(struct ssd1307fb_par *par)
|
||||
{
|
||||
pwm_disable(par->pwm);
|
||||
pwm_put(par->pwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ssd1307fb_ops ssd1307fb_ssd1307_ops = {
|
||||
.init = ssd1307fb_ssd1307_init,
|
||||
.remove = ssd1307fb_ssd1307_remove,
|
||||
};
|
||||
|
||||
static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Set initial contrast */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0x7f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set COM direction */
|
||||
ret = ssd1307fb_write_cmd(par->client, 0xc8);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set segment re-map */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set multiplex ratio value */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, par->height - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set display offset value */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
|
||||
ret = ssd1307fb_write_cmd(par->client, 0x20);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set clock frequency */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0xf0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set precharge period in number of ticks from the internal clock */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0x22);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set COM pins configuration */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0x22);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set VCOMH */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0x49);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Turn on the DC-DC Charge Pump */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0x14);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Switch to horizontal addressing mode */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client,
|
||||
SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0x0);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, par->width - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client, 0x0);
|
||||
ret = ret & ssd1307fb_write_cmd(par->client,
|
||||
par->page_offset + (par->height / 8) - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Turn on the display */
|
||||
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ssd1307fb_ops ssd1307fb_ssd1306_ops = {
|
||||
.init = ssd1307fb_ssd1306_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id ssd1307fb_of_match[] = {
|
||||
{
|
||||
.compatible = "solomon,ssd1306fb-i2c",
|
||||
.data = (void *)&ssd1307fb_ssd1306_ops,
|
||||
},
|
||||
{
|
||||
.compatible = "solomon,ssd1307fb-i2c",
|
||||
.data = (void *)&ssd1307fb_ssd1307_ops,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
|
||||
|
||||
static int ssd1307fb_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct fb_info *info;
|
||||
u32 vmem_size = SSD1307FB_WIDTH * SSD1307FB_HEIGHT / 8;
|
||||
struct device_node *node = client->dev.of_node;
|
||||
u32 vmem_size;
|
||||
struct ssd1307fb_par *par;
|
||||
u8 *vmem;
|
||||
int ret;
|
||||
|
||||
if (!client->dev.of_node) {
|
||||
if (!node) {
|
||||
dev_err(&client->dev, "No device tree data found!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -247,6 +442,31 @@ static int ssd1307fb_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
par = info->par;
|
||||
par->info = info;
|
||||
par->client = client;
|
||||
|
||||
par->ops = (struct ssd1307fb_ops *)of_match_device(ssd1307fb_of_match,
|
||||
&client->dev)->data;
|
||||
|
||||
par->reset = of_get_named_gpio(client->dev.of_node,
|
||||
"reset-gpios", 0);
|
||||
if (!gpio_is_valid(par->reset)) {
|
||||
ret = -EINVAL;
|
||||
goto fb_alloc_error;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(node, "solomon,width", &par->width))
|
||||
par->width = 96;
|
||||
|
||||
if (of_property_read_u32(node, "solomon,height", &par->height))
|
||||
par->width = 16;
|
||||
|
||||
if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
|
||||
par->page_offset = 1;
|
||||
|
||||
vmem_size = par->width * par->height / 8;
|
||||
|
||||
vmem = devm_kzalloc(&client->dev, vmem_size, GFP_KERNEL);
|
||||
if (!vmem) {
|
||||
dev_err(&client->dev, "Couldn't allocate graphical memory.\n");
|
||||
|
@ -256,9 +476,15 @@ static int ssd1307fb_probe(struct i2c_client *client,
|
|||
|
||||
info->fbops = &ssd1307fb_ops;
|
||||
info->fix = ssd1307fb_fix;
|
||||
info->fix.line_length = par->width / 8;
|
||||
info->fbdefio = &ssd1307fb_defio;
|
||||
|
||||
info->var = ssd1307fb_var;
|
||||
info->var.xres = par->width;
|
||||
info->var.xres_virtual = par->width;
|
||||
info->var.yres = par->height;
|
||||
info->var.yres_virtual = par->height;
|
||||
|
||||
info->var.red.length = 1;
|
||||
info->var.red.offset = 0;
|
||||
info->var.green.length = 1;
|
||||
|
@ -272,17 +498,6 @@ static int ssd1307fb_probe(struct i2c_client *client,
|
|||
|
||||
fb_deferred_io_init(info);
|
||||
|
||||
par = info->par;
|
||||
par->info = info;
|
||||
par->client = client;
|
||||
|
||||
par->reset = of_get_named_gpio(client->dev.of_node,
|
||||
"reset-gpios", 0);
|
||||
if (!gpio_is_valid(par->reset)) {
|
||||
ret = -EINVAL;
|
||||
goto reset_oled_error;
|
||||
}
|
||||
|
||||
ret = devm_gpio_request_one(&client->dev, par->reset,
|
||||
GPIOF_OUT_INIT_HIGH,
|
||||
"oled-reset");
|
||||
|
@ -293,23 +508,6 @@ static int ssd1307fb_probe(struct i2c_client *client,
|
|||
goto reset_oled_error;
|
||||
}
|
||||
|
||||
par->pwm = pwm_get(&client->dev, NULL);
|
||||
if (IS_ERR(par->pwm)) {
|
||||
dev_err(&client->dev, "Could not get PWM from device tree!\n");
|
||||
ret = PTR_ERR(par->pwm);
|
||||
goto pwm_error;
|
||||
}
|
||||
|
||||
par->pwm_period = pwm_get_period(par->pwm);
|
||||
|
||||
dev_dbg(&client->dev, "Using PWM%d with a %dns period.\n", par->pwm->pwm, par->pwm_period);
|
||||
|
||||
ret = register_framebuffer(info);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Couldn't register the framebuffer\n");
|
||||
goto fbreg_error;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, info);
|
||||
|
||||
/* Reset the screen */
|
||||
|
@ -318,34 +516,25 @@ static int ssd1307fb_probe(struct i2c_client *client,
|
|||
gpio_set_value(par->reset, 1);
|
||||
udelay(4);
|
||||
|
||||
/* Enable the PWM */
|
||||
pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
|
||||
pwm_enable(par->pwm);
|
||||
|
||||
/* Map column 127 of the OLED to segment 0 */
|
||||
ret = ssd1307fb_write_cmd(client, SSD1307FB_SEG_REMAP_ON);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Couldn't remap the screen.\n");
|
||||
goto remap_error;
|
||||
if (par->ops->init) {
|
||||
ret = par->ops->init(par);
|
||||
if (ret)
|
||||
goto reset_oled_error;
|
||||
}
|
||||
|
||||
/* Turn on the display */
|
||||
ret = ssd1307fb_write_cmd(client, SSD1307FB_DISPLAY_ON);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Couldn't turn the display on.\n");
|
||||
goto remap_error;
|
||||
ret = register_framebuffer(info);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Couldn't register the framebuffer\n");
|
||||
goto panel_init_error;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size);
|
||||
|
||||
return 0;
|
||||
|
||||
remap_error:
|
||||
unregister_framebuffer(info);
|
||||
pwm_disable(par->pwm);
|
||||
fbreg_error:
|
||||
pwm_put(par->pwm);
|
||||
pwm_error:
|
||||
panel_init_error:
|
||||
if (par->ops->remove)
|
||||
par->ops->remove(par);
|
||||
reset_oled_error:
|
||||
fb_deferred_io_cleanup(info);
|
||||
fb_alloc_error:
|
||||
|
@ -359,8 +548,8 @@ static int ssd1307fb_remove(struct i2c_client *client)
|
|||
struct ssd1307fb_par *par = info->par;
|
||||
|
||||
unregister_framebuffer(info);
|
||||
pwm_disable(par->pwm);
|
||||
pwm_put(par->pwm);
|
||||
if (par->ops->remove)
|
||||
par->ops->remove(par);
|
||||
fb_deferred_io_cleanup(info);
|
||||
framebuffer_release(info);
|
||||
|
||||
|
@ -368,17 +557,12 @@ static int ssd1307fb_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id ssd1307fb_i2c_id[] = {
|
||||
{ "ssd1306fb", 0 },
|
||||
{ "ssd1307fb", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id);
|
||||
|
||||
static const struct of_device_id ssd1307fb_of_match[] = {
|
||||
{ .compatible = "solomon,ssd1307fb-i2c" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
|
||||
|
||||
static struct i2c_driver ssd1307fb_driver = {
|
||||
.probe = ssd1307fb_probe,
|
||||
.remove = ssd1307fb_remove,
|
||||
|
|
|
@ -794,7 +794,6 @@ err_hw_init:
|
|||
cell->disable(dev);
|
||||
err_enable:
|
||||
err_find_mode:
|
||||
platform_set_drvdata(dev, NULL);
|
||||
free_irq(irq, info);
|
||||
err_request_irq:
|
||||
iounmap(info->screen_base);
|
||||
|
@ -823,8 +822,6 @@ static int tmiofb_remove(struct platform_device *dev)
|
|||
if (cell->disable)
|
||||
cell->disable(dev);
|
||||
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
||||
free_irq(irq, info);
|
||||
|
||||
iounmap(info->screen_base);
|
||||
|
|
|
@ -434,10 +434,10 @@ static void dlfb_compress_hline(
|
|||
|
||||
while ((pixel_end > pixel) &&
|
||||
(cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
|
||||
uint8_t *raw_pixels_count_byte = 0;
|
||||
uint8_t *cmd_pixels_count_byte = 0;
|
||||
const uint16_t *raw_pixel_start = 0;
|
||||
const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0;
|
||||
uint8_t *raw_pixels_count_byte = NULL;
|
||||
uint8_t *cmd_pixels_count_byte = NULL;
|
||||
const uint16_t *raw_pixel_start = NULL;
|
||||
const uint16_t *cmd_pixel_start, *cmd_pixel_end = NULL;
|
||||
|
||||
prefetchw((void *) cmd); /* pull in one cache line at least */
|
||||
|
||||
|
@ -573,7 +573,7 @@ static int dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
|
||||
static int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
|
||||
int width, int height, char *data)
|
||||
{
|
||||
int i, ret;
|
||||
|
@ -1588,7 +1588,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
|
|||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *usbdev;
|
||||
struct dlfb_data *dev = 0;
|
||||
struct dlfb_data *dev = NULL;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
/* usb initialization */
|
||||
|
|
|
@ -819,8 +819,8 @@ static int uvesafb_vbe_init(struct fb_info *info)
|
|||
if (par->pmi_setpal || par->ypan) {
|
||||
if (__supported_pte_mask & _PAGE_NX) {
|
||||
par->pmi_setpal = par->ypan = 0;
|
||||
printk(KERN_WARNING "uvesafb: NX protection is actively."
|
||||
"We have better not to use the PMI.\n");
|
||||
printk(KERN_WARNING "uvesafb: NX protection is active, "
|
||||
"better not use the PMI.\n");
|
||||
} else {
|
||||
uvesafb_vbe_getpmi(task, par);
|
||||
}
|
||||
|
|
|
@ -1269,7 +1269,6 @@ static void vga16fb_destroy(struct fb_info *info)
|
|||
iounmap(info->screen_base);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
/* XXX unshare VGA regions */
|
||||
platform_set_drvdata(dev, NULL);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
|
||||
|
|
|
@ -448,7 +448,6 @@ failed_free_io:
|
|||
failed_free_res:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
failed_fbi:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(fbi);
|
||||
failed:
|
||||
return ret;
|
||||
|
|
|
@ -173,7 +173,7 @@ static ssize_t contrast_store(struct device *dev,
|
|||
struct wm8505fb_info *fbi = to_wm8505fb_info(info);
|
||||
unsigned long tmp;
|
||||
|
||||
if (strict_strtoul(buf, 10, &tmp) || (tmp > 0xff))
|
||||
if (kstrtoul(buf, 10, &tmp) || (tmp > 0xff))
|
||||
return -EINVAL;
|
||||
fbi->contrast = tmp;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
|
||||
/*
|
||||
* Xilinx calls it "PLB TFT LCD Controller" though it can also be used for
|
||||
* Xilinx calls it "TFT LCD Controller" though it can also be used for
|
||||
* the VGA port on the Xilinx ML40x board. This is a hardware display
|
||||
* controller for a 640x480 resolution TFT or VGA screen.
|
||||
*
|
||||
|
@ -54,11 +54,11 @@
|
|||
* don't start thinking about scrolling). The second allows the LCD to
|
||||
* be turned on or off as well as rotated 180 degrees.
|
||||
*
|
||||
* In case of direct PLB access the second control register will be at
|
||||
* In case of direct BUS access the second control register will be at
|
||||
* an offset of 4 as compared to the DCR access where the offset is 1
|
||||
* i.e. REG_CTRL. So this is taken care in the function
|
||||
* xilinx_fb_out_be32 where it left shifts the offset 2 times in case of
|
||||
* direct PLB access.
|
||||
* xilinx_fb_out32 where it left shifts the offset 2 times in case of
|
||||
* direct BUS access.
|
||||
*/
|
||||
#define NUM_REGS 2
|
||||
#define REG_FB_ADDR 0
|
||||
|
@ -116,7 +116,8 @@ static struct fb_var_screeninfo xilinx_fb_var = {
|
|||
};
|
||||
|
||||
|
||||
#define PLB_ACCESS_FLAG 0x1 /* 1 = PLB, 0 = DCR */
|
||||
#define BUS_ACCESS_FLAG 0x1 /* 1 = BUS, 0 = DCR */
|
||||
#define LITTLE_ENDIAN_ACCESS 0x2 /* LITTLE ENDIAN IO functions */
|
||||
|
||||
struct xilinxfb_drvdata {
|
||||
|
||||
|
@ -146,21 +147,40 @@ struct xilinxfb_drvdata {
|
|||
container_of(_info, struct xilinxfb_drvdata, info)
|
||||
|
||||
/*
|
||||
* The XPS TFT Controller can be accessed through PLB or DCR interface.
|
||||
* The XPS TFT Controller can be accessed through BUS or DCR interface.
|
||||
* To perform the read/write on the registers we need to check on
|
||||
* which bus its connected and call the appropriate write API.
|
||||
*/
|
||||
static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset,
|
||||
static void xilinx_fb_out32(struct xilinxfb_drvdata *drvdata, u32 offset,
|
||||
u32 val)
|
||||
{
|
||||
if (drvdata->flags & PLB_ACCESS_FLAG)
|
||||
out_be32(drvdata->regs + (offset << 2), val);
|
||||
if (drvdata->flags & BUS_ACCESS_FLAG) {
|
||||
if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
|
||||
iowrite32(val, drvdata->regs + (offset << 2));
|
||||
else
|
||||
iowrite32be(val, drvdata->regs + (offset << 2));
|
||||
}
|
||||
#ifdef CONFIG_PPC_DCR
|
||||
else
|
||||
dcr_write(drvdata->dcr_host, offset, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 xilinx_fb_in32(struct xilinxfb_drvdata *drvdata, u32 offset)
|
||||
{
|
||||
if (drvdata->flags & BUS_ACCESS_FLAG) {
|
||||
if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
|
||||
return ioread32(drvdata->regs + (offset << 2));
|
||||
else
|
||||
return ioread32be(drvdata->regs + (offset << 2));
|
||||
}
|
||||
#ifdef CONFIG_PPC_DCR
|
||||
else
|
||||
return dcr_read(drvdata->dcr_host, offset);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
|
||||
unsigned transp, struct fb_info *fbi)
|
||||
|
@ -197,7 +217,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
|
|||
switch (blank_mode) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
/* turn on panel */
|
||||
xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
|
||||
xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
|
||||
break;
|
||||
|
||||
case FB_BLANK_NORMAL:
|
||||
|
@ -205,7 +225,7 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
|
|||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
case FB_BLANK_POWERDOWN:
|
||||
/* turn off panel */
|
||||
xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
|
||||
xilinx_fb_out32(drvdata, REG_CTRL, 0);
|
||||
default:
|
||||
break;
|
||||
|
||||
|
@ -227,33 +247,23 @@ static struct fb_ops xilinxfb_ops =
|
|||
* Bus independent setup/teardown
|
||||
*/
|
||||
|
||||
static int xilinxfb_assign(struct device *dev,
|
||||
static int xilinxfb_assign(struct platform_device *pdev,
|
||||
struct xilinxfb_drvdata *drvdata,
|
||||
unsigned long physaddr,
|
||||
struct xilinxfb_platform_data *pdata)
|
||||
{
|
||||
int rc;
|
||||
struct device *dev = &pdev->dev;
|
||||
int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
|
||||
|
||||
if (drvdata->flags & PLB_ACCESS_FLAG) {
|
||||
/*
|
||||
* Map the control registers in if the controller
|
||||
* is on direct PLB interface.
|
||||
*/
|
||||
if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
|
||||
dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
|
||||
physaddr);
|
||||
rc = -ENODEV;
|
||||
goto err_region;
|
||||
}
|
||||
if (drvdata->flags & BUS_ACCESS_FLAG) {
|
||||
struct resource *res;
|
||||
|
||||
drvdata->regs_phys = physaddr;
|
||||
drvdata->regs = ioremap(physaddr, 8);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
drvdata->regs_phys = res->start;
|
||||
drvdata->regs = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!drvdata->regs) {
|
||||
dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
|
||||
physaddr);
|
||||
rc = -ENODEV;
|
||||
goto err_map;
|
||||
rc = -EADDRNOTAVAIL;
|
||||
goto err_region;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +280,7 @@ static int xilinxfb_assign(struct device *dev,
|
|||
if (!drvdata->fb_virt) {
|
||||
dev_err(dev, "Could not allocate frame buffer memory\n");
|
||||
rc = -ENOMEM;
|
||||
if (drvdata->flags & PLB_ACCESS_FLAG)
|
||||
if (drvdata->flags & BUS_ACCESS_FLAG)
|
||||
goto err_fbmem;
|
||||
else
|
||||
goto err_region;
|
||||
|
@ -280,13 +290,19 @@ static int xilinxfb_assign(struct device *dev,
|
|||
memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
|
||||
|
||||
/* Tell the hardware where the frame buffer is */
|
||||
xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
|
||||
xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
|
||||
rc = xilinx_fb_in32(drvdata, REG_FB_ADDR);
|
||||
/* Endianess detection */
|
||||
if (rc != drvdata->fb_phys) {
|
||||
drvdata->flags |= LITTLE_ENDIAN_ACCESS;
|
||||
xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
|
||||
}
|
||||
|
||||
/* Turn on the display */
|
||||
drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
|
||||
if (pdata->rotate_screen)
|
||||
drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
|
||||
xilinx_fb_out_be32(drvdata, REG_CTRL,
|
||||
xilinx_fb_out32(drvdata, REG_CTRL,
|
||||
drvdata->reg_ctrl_default);
|
||||
|
||||
/* Fill struct fb_info */
|
||||
|
@ -323,9 +339,9 @@ static int xilinxfb_assign(struct device *dev,
|
|||
goto err_regfb;
|
||||
}
|
||||
|
||||
if (drvdata->flags & PLB_ACCESS_FLAG) {
|
||||
if (drvdata->flags & BUS_ACCESS_FLAG) {
|
||||
/* Put a banner in the log (for DEBUG) */
|
||||
dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr,
|
||||
dev_dbg(dev, "regs: phys=%x, virt=%p\n", drvdata->regs_phys,
|
||||
drvdata->regs);
|
||||
}
|
||||
/* Put a banner in the log (for DEBUG) */
|
||||
|
@ -345,15 +361,11 @@ err_cmap:
|
|||
iounmap(drvdata->fb_virt);
|
||||
|
||||
/* Turn off the display */
|
||||
xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
|
||||
xilinx_fb_out32(drvdata, REG_CTRL, 0);
|
||||
|
||||
err_fbmem:
|
||||
if (drvdata->flags & PLB_ACCESS_FLAG)
|
||||
iounmap(drvdata->regs);
|
||||
|
||||
err_map:
|
||||
if (drvdata->flags & PLB_ACCESS_FLAG)
|
||||
release_mem_region(physaddr, 8);
|
||||
if (drvdata->flags & BUS_ACCESS_FLAG)
|
||||
devm_iounmap(dev, drvdata->regs);
|
||||
|
||||
err_region:
|
||||
kfree(drvdata);
|
||||
|
@ -381,13 +393,11 @@ static int xilinxfb_release(struct device *dev)
|
|||
iounmap(drvdata->fb_virt);
|
||||
|
||||
/* Turn off the display */
|
||||
xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
|
||||
xilinx_fb_out32(drvdata, REG_CTRL, 0);
|
||||
|
||||
/* Release the resources, as allocated based on interface */
|
||||
if (drvdata->flags & PLB_ACCESS_FLAG) {
|
||||
iounmap(drvdata->regs);
|
||||
release_mem_region(drvdata->regs_phys, 8);
|
||||
}
|
||||
if (drvdata->flags & BUS_ACCESS_FLAG)
|
||||
devm_iounmap(dev, drvdata->regs);
|
||||
#ifdef CONFIG_PPC_DCR
|
||||
else
|
||||
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
|
||||
|
@ -406,11 +416,9 @@ static int xilinxfb_release(struct device *dev)
|
|||
static int xilinxfb_of_probe(struct platform_device *op)
|
||||
{
|
||||
const u32 *prop;
|
||||
u32 *p;
|
||||
u32 tft_access;
|
||||
u32 tft_access = 0;
|
||||
struct xilinxfb_platform_data pdata;
|
||||
struct resource res;
|
||||
int size, rc;
|
||||
int size;
|
||||
struct xilinxfb_drvdata *drvdata;
|
||||
|
||||
/* Copy with the default pdata (not a ptr reference!) */
|
||||
|
@ -424,34 +432,29 @@ static int xilinxfb_of_probe(struct platform_device *op)
|
|||
}
|
||||
|
||||
/*
|
||||
* To check whether the core is connected directly to DCR or PLB
|
||||
* To check whether the core is connected directly to DCR or BUS
|
||||
* interface and initialize the tft_access accordingly.
|
||||
*/
|
||||
p = (u32 *)of_get_property(op->dev.of_node, "xlnx,dcr-splb-slave-if", NULL);
|
||||
tft_access = p ? *p : 0;
|
||||
of_property_read_u32(op->dev.of_node, "xlnx,dcr-splb-slave-if",
|
||||
&tft_access);
|
||||
|
||||
/*
|
||||
* Fill the resource structure if its direct PLB interface
|
||||
* Fill the resource structure if its direct BUS interface
|
||||
* otherwise fill the dcr_host structure.
|
||||
*/
|
||||
if (tft_access) {
|
||||
drvdata->flags |= PLB_ACCESS_FLAG;
|
||||
rc = of_address_to_resource(op->dev.of_node, 0, &res);
|
||||
if (rc) {
|
||||
dev_err(&op->dev, "invalid address\n");
|
||||
goto err;
|
||||
}
|
||||
drvdata->flags |= BUS_ACCESS_FLAG;
|
||||
}
|
||||
#ifdef CONFIG_PPC_DCR
|
||||
else {
|
||||
int start;
|
||||
res.start = 0;
|
||||
start = dcr_resource_start(op->dev.of_node, 0);
|
||||
drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0);
|
||||
drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len);
|
||||
if (!DCR_MAP_OK(drvdata->dcr_host)) {
|
||||
dev_err(&op->dev, "invalid DCR address\n");
|
||||
goto err;
|
||||
kfree(drvdata);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -478,11 +481,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
|
|||
pdata.rotate_screen = 1;
|
||||
|
||||
dev_set_drvdata(&op->dev, drvdata);
|
||||
return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata);
|
||||
|
||||
err:
|
||||
kfree(drvdata);
|
||||
return -ENODEV;
|
||||
return xilinxfb_assign(op, drvdata, &pdata);
|
||||
}
|
||||
|
||||
static int xilinxfb_of_remove(struct platform_device *op)
|
||||
|
|
|
@ -624,7 +624,7 @@ extern void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u3
|
|||
extern void fb_set_suspend(struct fb_info *info, int state);
|
||||
extern int fb_get_color_depth(struct fb_var_screeninfo *var,
|
||||
struct fb_fix_screeninfo *fix);
|
||||
extern int fb_get_options(char *name, char **option);
|
||||
extern int fb_get_options(const char *name, char **option);
|
||||
extern int fb_new_modelist(struct fb_info *info);
|
||||
|
||||
extern struct fb_info *registered_fb[FB_MAX];
|
||||
|
|
|
@ -10,10 +10,13 @@
|
|||
#define __LINUX_OF_DISPLAY_TIMING_H
|
||||
|
||||
struct device_node;
|
||||
struct display_timing;
|
||||
struct display_timings;
|
||||
|
||||
#define OF_USE_NATIVE_MODE -1
|
||||
|
||||
int of_get_display_timing(struct device_node *np, const char *name,
|
||||
struct display_timing *dt);
|
||||
struct display_timings *of_get_display_timings(struct device_node *np);
|
||||
int of_display_timings_exist(struct device_node *np);
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#ifndef __OMAP_PANEL_DATA_H
|
||||
#define __OMAP_PANEL_DATA_H
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/display_timing.h>
|
||||
|
||||
struct omap_dss_device;
|
||||
|
||||
/**
|
||||
|
@ -147,4 +150,210 @@ struct panel_tpo_td043_data {
|
|||
int nreset_gpio;
|
||||
};
|
||||
|
||||
/**
|
||||
* encoder_tfp410 platform data
|
||||
* @name: name for this display entity
|
||||
* @power_down_gpio: gpio number for PD pin (or -1 if not available)
|
||||
* @data_lines: number of DPI datalines
|
||||
*/
|
||||
struct encoder_tfp410_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
int power_down_gpio;
|
||||
int data_lines;
|
||||
};
|
||||
|
||||
/**
|
||||
* encoder_tpd12s015 platform data
|
||||
* @name: name for this display entity
|
||||
* @ct_cp_hpd_gpio: CT_CP_HPD gpio number
|
||||
* @ls_oe_gpio: LS_OE gpio number
|
||||
* @hpd_gpio: HPD gpio number
|
||||
*/
|
||||
struct encoder_tpd12s015_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int ct_cp_hpd_gpio;
|
||||
int ls_oe_gpio;
|
||||
int hpd_gpio;
|
||||
};
|
||||
|
||||
/**
|
||||
* connector_dvi platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @i2c_bus_num: i2c bus number to be used for reading EDID
|
||||
*/
|
||||
struct connector_dvi_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
int i2c_bus_num;
|
||||
};
|
||||
|
||||
/**
|
||||
* connector_hdmi platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
*/
|
||||
struct connector_hdmi_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
};
|
||||
|
||||
/**
|
||||
* connector_atv platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @connector_type: composite/svideo
|
||||
* @invert_polarity: invert signal polarity
|
||||
*/
|
||||
struct connector_atv_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
enum omap_dss_venc_type connector_type;
|
||||
bool invert_polarity;
|
||||
};
|
||||
|
||||
/**
|
||||
* panel_dpi platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @data_lines: number of DPI datalines
|
||||
* @display_timing: timings for this panel
|
||||
* @backlight_gpio: gpio to enable/disable the backlight (or -1)
|
||||
* @enable_gpio: gpio to enable/disable the panel (or -1)
|
||||
*/
|
||||
struct panel_dpi_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int data_lines;
|
||||
|
||||
const struct display_timing *display_timing;
|
||||
|
||||
int backlight_gpio;
|
||||
int enable_gpio;
|
||||
};
|
||||
|
||||
/**
|
||||
* panel_dsicm platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @reset_gpio: gpio to reset the panel (or -1)
|
||||
* @use_ext_te: use external TE GPIO
|
||||
* @ext_te_gpio: external TE GPIO
|
||||
* @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
|
||||
* @use_dsi_backlight: true if panel uses DSI command to control backlight
|
||||
* @pin_config: DSI pin configuration
|
||||
*/
|
||||
struct panel_dsicm_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int reset_gpio;
|
||||
|
||||
bool use_ext_te;
|
||||
int ext_te_gpio;
|
||||
|
||||
unsigned ulps_timeout;
|
||||
|
||||
bool use_dsi_backlight;
|
||||
|
||||
struct omap_dsi_pin_config pin_config;
|
||||
};
|
||||
|
||||
/**
|
||||
* panel_acx565akm platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @reset_gpio: gpio to reset the panel (or -1)
|
||||
* @datapairs: number of SDI datapairs
|
||||
*/
|
||||
struct panel_acx565akm_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int reset_gpio;
|
||||
|
||||
int datapairs;
|
||||
};
|
||||
|
||||
/**
|
||||
* panel_lb035q02 platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @data_lines: number of DPI datalines
|
||||
* @backlight_gpio: gpio to enable/disable the backlight (or -1)
|
||||
* @enable_gpio: gpio to enable/disable the panel (or -1)
|
||||
*/
|
||||
struct panel_lb035q02_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int data_lines;
|
||||
|
||||
int backlight_gpio;
|
||||
int enable_gpio;
|
||||
};
|
||||
|
||||
/**
|
||||
* panel_sharp_ls037v7dw01 platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @data_lines: number of DPI datalines
|
||||
* @resb_gpio: reset signal GPIO
|
||||
* @ini_gpio: power on control GPIO
|
||||
* @mo_gpio: selection for resolution(VGA/QVGA) GPIO
|
||||
* @lr_gpio: selection for horizontal scanning direction GPIO
|
||||
* @ud_gpio: selection for vertical scanning direction GPIO
|
||||
*/
|
||||
struct panel_sharp_ls037v7dw01_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int data_lines;
|
||||
|
||||
int resb_gpio;
|
||||
int ini_gpio;
|
||||
int mo_gpio;
|
||||
int lr_gpio;
|
||||
int ud_gpio;
|
||||
};
|
||||
|
||||
/**
|
||||
* panel-tpo-td043mtea1 platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @data_lines: number of DPI datalines
|
||||
* @nreset_gpio: reset signal
|
||||
*/
|
||||
struct panel_tpo_td043mtea1_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int data_lines;
|
||||
|
||||
int nreset_gpio;
|
||||
};
|
||||
|
||||
/**
|
||||
* panel-nec-nl8048hl11 platform data
|
||||
* @name: name for this display entity
|
||||
* @source: name of the display entity used as a video source
|
||||
* @data_lines: number of DPI datalines
|
||||
* @res_gpio: reset signal
|
||||
* @qvga_gpio: selection for resolution(QVGA/WVGA)
|
||||
*/
|
||||
struct panel_nec_nl8048hl11_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int data_lines;
|
||||
|
||||
int res_gpio;
|
||||
int qvga_gpio;
|
||||
};
|
||||
|
||||
#endif /* __OMAP_PANEL_DATA_H */
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <video/videomode.h>
|
||||
|
||||
#define DISPC_IRQ_FRAMEDONE (1 << 0)
|
||||
#define DISPC_IRQ_VSYNC (1 << 1)
|
||||
#define DISPC_IRQ_EVSYNC_EVEN (1 << 2)
|
||||
|
@ -68,6 +70,7 @@ enum omap_display_type {
|
|||
OMAP_DISPLAY_TYPE_DSI = 1 << 3,
|
||||
OMAP_DISPLAY_TYPE_VENC = 1 << 4,
|
||||
OMAP_DISPLAY_TYPE_HDMI = 1 << 5,
|
||||
OMAP_DISPLAY_TYPE_DVI = 1 << 6,
|
||||
};
|
||||
|
||||
enum omap_plane {
|
||||
|
@ -169,6 +172,11 @@ enum omap_dss_audio_state {
|
|||
OMAP_DSS_AUDIO_PLAYING,
|
||||
};
|
||||
|
||||
struct omap_dss_audio {
|
||||
struct snd_aes_iec958 *iec;
|
||||
struct snd_cea_861_aud_if *cea;
|
||||
};
|
||||
|
||||
enum omap_dss_rotation_type {
|
||||
OMAP_DSS_ROT_DMA = 1 << 0,
|
||||
OMAP_DSS_ROT_VRFB = 1 << 1,
|
||||
|
@ -365,6 +373,7 @@ struct omap_dss_board_info {
|
|||
int num_devices;
|
||||
struct omap_dss_device **devices;
|
||||
struct omap_dss_device *default_device;
|
||||
const char *default_display_name;
|
||||
int (*dsi_enable_pads)(int dsi_id, unsigned lane_mask);
|
||||
void (*dsi_disable_pads)(int dsi_id, unsigned lane_mask);
|
||||
int (*set_min_bus_tput)(struct device *dev, unsigned long r);
|
||||
|
@ -512,7 +521,7 @@ struct omap_overlay_manager {
|
|||
enum omap_dss_output_id supported_outputs;
|
||||
|
||||
/* dynamic fields */
|
||||
struct omap_dss_output *output;
|
||||
struct omap_dss_device *output;
|
||||
|
||||
/*
|
||||
* The following functions do not block:
|
||||
|
@ -526,7 +535,7 @@ struct omap_overlay_manager {
|
|||
*/
|
||||
|
||||
int (*set_output)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_output *output);
|
||||
struct omap_dss_device *output);
|
||||
int (*unset_output)(struct omap_overlay_manager *mgr);
|
||||
|
||||
int (*set_manager_info)(struct omap_overlay_manager *mgr,
|
||||
|
@ -569,33 +578,192 @@ struct omap_dss_writeback_info {
|
|||
u8 pre_mult_alpha;
|
||||
};
|
||||
|
||||
struct omap_dss_output {
|
||||
struct list_head list;
|
||||
struct omapdss_dpi_ops {
|
||||
int (*connect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
const char *name;
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev);
|
||||
|
||||
/* display type supported by the output */
|
||||
enum omap_display_type type;
|
||||
int (*check_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*set_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*get_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
|
||||
/* DISPC channel for this output */
|
||||
enum omap_channel dispc_channel;
|
||||
void (*set_data_lines)(struct omap_dss_device *dssdev, int data_lines);
|
||||
};
|
||||
|
||||
/* output instance */
|
||||
enum omap_dss_output_id id;
|
||||
struct omapdss_sdi_ops {
|
||||
int (*connect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
/* output's platform device pointer */
|
||||
struct platform_device *pdev;
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev);
|
||||
|
||||
/* dynamic fields */
|
||||
struct omap_overlay_manager *manager;
|
||||
int (*check_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*set_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*get_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
|
||||
struct omap_dss_device *device;
|
||||
void (*set_datapairs)(struct omap_dss_device *dssdev, int datapairs);
|
||||
};
|
||||
|
||||
struct omapdss_dvi_ops {
|
||||
int (*connect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*check_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*set_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*get_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
};
|
||||
|
||||
struct omapdss_atv_ops {
|
||||
int (*connect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*check_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*set_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*get_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
|
||||
void (*set_type)(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_venc_type type);
|
||||
void (*invert_vid_out_polarity)(struct omap_dss_device *dssdev,
|
||||
bool invert_polarity);
|
||||
|
||||
int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
|
||||
u32 (*get_wss)(struct omap_dss_device *dssdev);
|
||||
};
|
||||
|
||||
struct omapdss_hdmi_ops {
|
||||
int (*connect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*check_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*set_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*get_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
|
||||
int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
|
||||
bool (*detect)(struct omap_dss_device *dssdev);
|
||||
|
||||
/*
|
||||
* Note: These functions might sleep. Do not call while
|
||||
* holding a spinlock/readlock.
|
||||
*/
|
||||
int (*audio_enable)(struct omap_dss_device *dssdev);
|
||||
void (*audio_disable)(struct omap_dss_device *dssdev);
|
||||
bool (*audio_supported)(struct omap_dss_device *dssdev);
|
||||
int (*audio_config)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio);
|
||||
/* Note: These functions may not sleep */
|
||||
int (*audio_start)(struct omap_dss_device *dssdev);
|
||||
void (*audio_stop)(struct omap_dss_device *dssdev);
|
||||
};
|
||||
|
||||
struct omapdss_dsi_ops {
|
||||
int (*connect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes,
|
||||
bool enter_ulps);
|
||||
|
||||
/* bus configuration */
|
||||
int (*set_config)(struct omap_dss_device *dssdev,
|
||||
const struct omap_dss_dsi_config *cfg);
|
||||
int (*configure_pins)(struct omap_dss_device *dssdev,
|
||||
const struct omap_dsi_pin_config *pin_cfg);
|
||||
|
||||
void (*enable_hs)(struct omap_dss_device *dssdev, int channel,
|
||||
bool enable);
|
||||
int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
|
||||
|
||||
int (*update)(struct omap_dss_device *dssdev, int channel,
|
||||
void (*callback)(int, void *), void *data);
|
||||
|
||||
void (*bus_lock)(struct omap_dss_device *dssdev);
|
||||
void (*bus_unlock)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*enable_video_output)(struct omap_dss_device *dssdev, int channel);
|
||||
void (*disable_video_output)(struct omap_dss_device *dssdev,
|
||||
int channel);
|
||||
|
||||
int (*request_vc)(struct omap_dss_device *dssdev, int *channel);
|
||||
int (*set_vc_id)(struct omap_dss_device *dssdev, int channel,
|
||||
int vc_id);
|
||||
void (*release_vc)(struct omap_dss_device *dssdev, int channel);
|
||||
|
||||
/* data transfer */
|
||||
int (*dcs_write)(struct omap_dss_device *dssdev, int channel,
|
||||
u8 *data, int len);
|
||||
int (*dcs_write_nosync)(struct omap_dss_device *dssdev, int channel,
|
||||
u8 *data, int len);
|
||||
int (*dcs_read)(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
|
||||
u8 *data, int len);
|
||||
|
||||
int (*gen_write)(struct omap_dss_device *dssdev, int channel,
|
||||
u8 *data, int len);
|
||||
int (*gen_write_nosync)(struct omap_dss_device *dssdev, int channel,
|
||||
u8 *data, int len);
|
||||
int (*gen_read)(struct omap_dss_device *dssdev, int channel,
|
||||
u8 *reqdata, int reqlen,
|
||||
u8 *data, int len);
|
||||
|
||||
int (*bta_sync)(struct omap_dss_device *dssdev, int channel);
|
||||
|
||||
int (*set_max_rx_packet_size)(struct omap_dss_device *dssdev,
|
||||
int channel, u16 plen);
|
||||
};
|
||||
|
||||
struct omap_dss_device {
|
||||
struct device dev;
|
||||
/* old device, to be removed */
|
||||
struct device old_dev;
|
||||
|
||||
/* new device, pointer to panel device */
|
||||
struct device *dev;
|
||||
|
||||
struct module *owner;
|
||||
|
||||
struct list_head panel_list;
|
||||
|
||||
/* alias in the form of "display%d" */
|
||||
char alias[16];
|
||||
|
||||
enum omap_display_type type;
|
||||
enum omap_display_type output_type;
|
||||
|
||||
/* obsolete, to be removed */
|
||||
enum omap_channel channel;
|
||||
|
@ -616,9 +784,6 @@ struct omap_dss_device {
|
|||
|
||||
struct {
|
||||
int module;
|
||||
|
||||
bool ext_te;
|
||||
u8 ext_te_gpio;
|
||||
} dsi;
|
||||
|
||||
struct {
|
||||
|
@ -639,10 +804,6 @@ struct omap_dss_device {
|
|||
struct rfbi_timings rfbi_timings;
|
||||
} ctrl;
|
||||
|
||||
int reset_gpio;
|
||||
|
||||
int max_backlight_level;
|
||||
|
||||
const char *name;
|
||||
|
||||
/* used to match device to driver */
|
||||
|
@ -652,22 +813,40 @@ struct omap_dss_device {
|
|||
|
||||
struct omap_dss_driver *driver;
|
||||
|
||||
union {
|
||||
const struct omapdss_dpi_ops *dpi;
|
||||
const struct omapdss_sdi_ops *sdi;
|
||||
const struct omapdss_dvi_ops *dvi;
|
||||
const struct omapdss_hdmi_ops *hdmi;
|
||||
const struct omapdss_atv_ops *atv;
|
||||
const struct omapdss_dsi_ops *dsi;
|
||||
} ops;
|
||||
|
||||
/* helper variable for driver suspend/resume */
|
||||
bool activate_after_resume;
|
||||
|
||||
enum omap_display_caps caps;
|
||||
|
||||
struct omap_dss_output *output;
|
||||
struct omap_dss_device *output;
|
||||
|
||||
enum omap_dss_display_state state;
|
||||
|
||||
enum omap_dss_audio_state audio_state;
|
||||
|
||||
/* platform specific */
|
||||
int (*platform_enable)(struct omap_dss_device *dssdev);
|
||||
void (*platform_disable)(struct omap_dss_device *dssdev);
|
||||
int (*set_backlight)(struct omap_dss_device *dssdev, int level);
|
||||
int (*get_backlight)(struct omap_dss_device *dssdev);
|
||||
/* OMAP DSS output specific fields */
|
||||
|
||||
struct list_head list;
|
||||
|
||||
/* DISPC channel for this output */
|
||||
enum omap_channel dispc_channel;
|
||||
|
||||
/* output instance */
|
||||
enum omap_dss_output_id id;
|
||||
|
||||
/* dynamic fields */
|
||||
struct omap_overlay_manager *manager;
|
||||
|
||||
struct omap_dss_device *device;
|
||||
};
|
||||
|
||||
struct omap_dss_hdmi_data
|
||||
|
@ -677,17 +856,15 @@ struct omap_dss_hdmi_data
|
|||
int hpd_gpio;
|
||||
};
|
||||
|
||||
struct omap_dss_audio {
|
||||
struct snd_aes_iec958 *iec;
|
||||
struct snd_cea_861_aud_if *cea;
|
||||
};
|
||||
|
||||
struct omap_dss_driver {
|
||||
struct device_driver driver;
|
||||
|
||||
int (*probe)(struct omap_dss_device *);
|
||||
void (*remove)(struct omap_dss_device *);
|
||||
|
||||
int (*connect)(struct omap_dss_device *dssdev);
|
||||
void (*disconnect)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*enable)(struct omap_dss_device *display);
|
||||
void (*disable)(struct omap_dss_device *display);
|
||||
int (*run_test)(struct omap_dss_device *display, int test);
|
||||
|
@ -753,7 +930,10 @@ bool omapdss_is_initialized(void);
|
|||
int omap_dss_register_driver(struct omap_dss_driver *);
|
||||
void omap_dss_unregister_driver(struct omap_dss_driver *);
|
||||
|
||||
void omap_dss_get_device(struct omap_dss_device *dssdev);
|
||||
int omapdss_register_display(struct omap_dss_device *dssdev);
|
||||
void omapdss_unregister_display(struct omap_dss_device *dssdev);
|
||||
|
||||
struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev);
|
||||
void omap_dss_put_device(struct omap_dss_device *dssdev);
|
||||
#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
|
||||
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from);
|
||||
|
@ -761,8 +941,10 @@ struct omap_dss_device *omap_dss_find_device(void *data,
|
|||
int (*match)(struct omap_dss_device *dssdev, void *data));
|
||||
const char *omapdss_get_default_display_name(void);
|
||||
|
||||
int omap_dss_start_device(struct omap_dss_device *dssdev);
|
||||
void omap_dss_stop_device(struct omap_dss_device *dssdev);
|
||||
void videomode_to_omap_video_timings(const struct videomode *vm,
|
||||
struct omap_video_timings *ovt);
|
||||
void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
|
||||
struct videomode *vm);
|
||||
|
||||
int dss_feat_get_num_mgrs(void);
|
||||
int dss_feat_get_num_ovls(void);
|
||||
|
@ -778,10 +960,17 @@ struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
|
|||
int omap_dss_get_num_overlays(void);
|
||||
struct omap_overlay *omap_dss_get_overlay(int num);
|
||||
|
||||
struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id);
|
||||
int omapdss_output_set_device(struct omap_dss_output *out,
|
||||
int omapdss_register_output(struct omap_dss_device *output);
|
||||
void omapdss_unregister_output(struct omap_dss_device *output);
|
||||
struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id);
|
||||
struct omap_dss_device *omap_dss_find_output(const char *name);
|
||||
struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node);
|
||||
int omapdss_output_set_device(struct omap_dss_device *out,
|
||||
struct omap_dss_device *dssdev);
|
||||
int omapdss_output_unset_device(struct omap_dss_output *out);
|
||||
int omapdss_output_unset_device(struct omap_dss_device *out);
|
||||
|
||||
struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev);
|
||||
struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev);
|
||||
|
||||
void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
|
||||
u16 *xres, u16 *yres);
|
||||
|
@ -832,7 +1021,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
|
|||
bool mem_to_mem);
|
||||
|
||||
#define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
|
||||
#define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
|
||||
#define to_dss_device(x) container_of((x), struct omap_dss_device, old_dev)
|
||||
|
||||
void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
|
||||
bool enable);
|
||||
|
@ -883,6 +1072,11 @@ int omapdss_compat_init(void);
|
|||
void omapdss_compat_uninit(void);
|
||||
|
||||
struct dss_mgr_ops {
|
||||
int (*connect)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
void (*start_update)(struct omap_overlay_manager *mgr);
|
||||
int (*enable)(struct omap_overlay_manager *mgr);
|
||||
void (*disable)(struct omap_overlay_manager *mgr);
|
||||
|
@ -899,6 +1093,10 @@ struct dss_mgr_ops {
|
|||
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops);
|
||||
void dss_uninstall_mgr_ops(void);
|
||||
|
||||
int dss_mgr_connect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings);
|
||||
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
|
||||
|
@ -910,4 +1108,15 @@ int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
|
|||
void (*handler)(void *), void *data);
|
||||
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
|
||||
static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dssdev->output;
|
||||
}
|
||||
|
||||
static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче