Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
f133a9d7
Commit
f133a9d7
authored
Oct 28, 2009
by
Tomi Valkeinen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
OMAP: DSS2: Taal DSI command mode panel driver
Signed-off-by:
Tomi Valkeinen
<
tomi.valkeinen@nokia.com
>
parent
3b8f29b4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1011 additions
and
0 deletions
+1011
-0
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/Kconfig
+6
-0
drivers/video/omap2/displays/Makefile
drivers/video/omap2/displays/Makefile
+2
-0
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/displays/panel-taal.c
+1003
-0
No files found.
drivers/video/omap2/displays/Kconfig
View file @
f133a9d7
...
...
@@ -13,4 +13,10 @@ config PANEL_SHARP_LS037V7DW01
help
LCD Panel used in TI's SDP3430 and EVM boards
config PANEL_TAAL
tristate "Taal DSI Panel"
depends on OMAP2_DSS_DSI
help
Taal DSI command mode panel from TPO.
endmenu
drivers/video/omap2/displays/Makefile
View file @
f133a9d7
obj-$(CONFIG_PANEL_GENERIC)
+=
panel-generic.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01)
+=
panel-sharp-ls037v7dw01.o
obj-$(CONFIG_PANEL_TAAL)
+=
panel-taal.o
drivers/video/omap2/displays/panel-taal.c
0 → 100644
View file @
f133a9d7
/*
* Taal DSI command mode panel
*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@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/>.
*/
/*#define DEBUG*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <plat/display.h>
/* DSI Virtual channel. Hardcoded for now. */
#define TCH 0
#define DCS_READ_NUM_ERRORS 0x05
#define DCS_READ_POWER_MODE 0x0a
#define DCS_READ_MADCTL 0x0b
#define DCS_READ_PIXEL_FORMAT 0x0c
#define DCS_RDDSDR 0x0f
#define DCS_SLEEP_IN 0x10
#define DCS_SLEEP_OUT 0x11
#define DCS_DISPLAY_OFF 0x28
#define DCS_DISPLAY_ON 0x29
#define DCS_COLUMN_ADDR 0x2a
#define DCS_PAGE_ADDR 0x2b
#define DCS_MEMORY_WRITE 0x2c
#define DCS_TEAR_OFF 0x34
#define DCS_TEAR_ON 0x35
#define DCS_MEM_ACC_CTRL 0x36
#define DCS_PIXEL_FORMAT 0x3a
#define DCS_BRIGHTNESS 0x51
#define DCS_CTRL_DISPLAY 0x53
#define DCS_WRITE_CABC 0x55
#define DCS_READ_CABC 0x56
#define DCS_GET_ID1 0xda
#define DCS_GET_ID2 0xdb
#define DCS_GET_ID3 0xdc
/* #define TAAL_USE_ESD_CHECK */
#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
struct
taal_data
{
struct
backlight_device
*
bldev
;
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
omap_dss_device
*
dssdev
;
bool
enabled
;
u8
rotate
;
bool
mirror
;
bool
te_enabled
;
bool
use_ext_te
;
struct
completion
te_completion
;
bool
use_dsi_bl
;
bool
cabc_broken
;
unsigned
cabc_mode
;
bool
intro_printed
;
struct
workqueue_struct
*
esd_wq
;
struct
delayed_work
esd_work
;
};
static
void
taal_esd_work
(
struct
work_struct
*
work
);
static
void
hw_guard_start
(
struct
taal_data
*
td
,
int
guard_msec
)
{
td
->
hw_guard_wait
=
msecs_to_jiffies
(
guard_msec
);
td
->
hw_guard_end
=
jiffies
+
td
->
hw_guard_wait
;
}
static
void
hw_guard_wait
(
struct
taal_data
*
td
)
{
unsigned
long
wait
=
td
->
hw_guard_end
-
jiffies
;
if
((
long
)
wait
>
0
&&
wait
<=
td
->
hw_guard_wait
)
{
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
wait
);
}
}
static
int
taal_dcs_read_1
(
u8
dcs_cmd
,
u8
*
data
)
{
int
r
;
u8
buf
[
1
];
r
=
dsi_vc_dcs_read
(
TCH
,
dcs_cmd
,
buf
,
1
);
if
(
r
<
0
)
return
r
;
*
data
=
buf
[
0
];
return
0
;
}
static
int
taal_dcs_write_0
(
u8
dcs_cmd
)
{
return
dsi_vc_dcs_write
(
TCH
,
&
dcs_cmd
,
1
);
}
static
int
taal_dcs_write_1
(
u8
dcs_cmd
,
u8
param
)
{
u8
buf
[
2
];
buf
[
0
]
=
dcs_cmd
;
buf
[
1
]
=
param
;
return
dsi_vc_dcs_write
(
TCH
,
buf
,
2
);
}
static
int
taal_sleep_in
(
struct
taal_data
*
td
)
{
u8
cmd
;
int
r
;
hw_guard_wait
(
td
);
cmd
=
DCS_SLEEP_IN
;
r
=
dsi_vc_dcs_write_nosync
(
TCH
,
&
cmd
,
1
);
if
(
r
)
return
r
;
hw_guard_start
(
td
,
120
);
msleep
(
5
);
return
0
;
}
static
int
taal_sleep_out
(
struct
taal_data
*
td
)
{
int
r
;
hw_guard_wait
(
td
);
r
=
taal_dcs_write_0
(
DCS_SLEEP_OUT
);
if
(
r
)
return
r
;
hw_guard_start
(
td
,
120
);
msleep
(
5
);
return
0
;
}
static
int
taal_get_id
(
u8
*
id1
,
u8
*
id2
,
u8
*
id3
)
{
int
r
;
r
=
taal_dcs_read_1
(
DCS_GET_ID1
,
id1
);
if
(
r
)
return
r
;
r
=
taal_dcs_read_1
(
DCS_GET_ID2
,
id2
);
if
(
r
)
return
r
;
r
=
taal_dcs_read_1
(
DCS_GET_ID3
,
id3
);
if
(
r
)
return
r
;
return
0
;
}
static
int
taal_set_addr_mode
(
u8
rotate
,
bool
mirror
)
{
int
r
;
u8
mode
;
int
b5
,
b6
,
b7
;
r
=
taal_dcs_read_1
(
DCS_READ_MADCTL
,
&
mode
);
if
(
r
)
return
r
;
switch
(
rotate
)
{
default:
case
0
:
b7
=
0
;
b6
=
0
;
b5
=
0
;
break
;
case
1
:
b7
=
0
;
b6
=
1
;
b5
=
1
;
break
;
case
2
:
b7
=
1
;
b6
=
1
;
b5
=
0
;
break
;
case
3
:
b7
=
1
;
b6
=
0
;
b5
=
1
;
break
;
}
if
(
mirror
)
b6
=
!
b6
;
mode
&=
~
((
1
<<
7
)
|
(
1
<<
6
)
|
(
1
<<
5
));
mode
|=
(
b7
<<
7
)
|
(
b6
<<
6
)
|
(
b5
<<
5
);
return
taal_dcs_write_1
(
DCS_MEM_ACC_CTRL
,
mode
);
}
static
int
taal_set_update_window
(
u16
x
,
u16
y
,
u16
w
,
u16
h
)
{
int
r
;
u16
x1
=
x
;
u16
x2
=
x
+
w
-
1
;
u16
y1
=
y
;
u16
y2
=
y
+
h
-
1
;
u8
buf
[
5
];
buf
[
0
]
=
DCS_COLUMN_ADDR
;
buf
[
1
]
=
(
x1
>>
8
)
&
0xff
;
buf
[
2
]
=
(
x1
>>
0
)
&
0xff
;
buf
[
3
]
=
(
x2
>>
8
)
&
0xff
;
buf
[
4
]
=
(
x2
>>
0
)
&
0xff
;
r
=
dsi_vc_dcs_write_nosync
(
TCH
,
buf
,
sizeof
(
buf
));
if
(
r
)
return
r
;
buf
[
0
]
=
DCS_PAGE_ADDR
;
buf
[
1
]
=
(
y1
>>
8
)
&
0xff
;
buf
[
2
]
=
(
y1
>>
0
)
&
0xff
;
buf
[
3
]
=
(
y2
>>
8
)
&
0xff
;
buf
[
4
]
=
(
y2
>>
0
)
&
0xff
;
r
=
dsi_vc_dcs_write_nosync
(
TCH
,
buf
,
sizeof
(
buf
));
if
(
r
)
return
r
;
dsi_vc_send_bta_sync
(
TCH
);
return
r
;
}
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
);
int
r
;
int
level
;
if
(
dev
->
props
.
fb_blank
==
FB_BLANK_UNBLANK
&&
dev
->
props
.
power
==
FB_BLANK_UNBLANK
)
level
=
dev
->
props
.
brightness
;
else
level
=
0
;
dev_dbg
(
&
dssdev
->
dev
,
"update brightness to %d
\n
"
,
level
);
if
(
td
->
use_dsi_bl
)
{
if
(
td
->
enabled
)
{
dsi_bus_lock
();
r
=
taal_dcs_write_1
(
DCS_BRIGHTNESS
,
level
);
dsi_bus_unlock
();
if
(
r
)
return
r
;
}
}
else
{
if
(
!
dssdev
->
set_backlight
)
return
-
EINVAL
;
r
=
dssdev
->
set_backlight
(
dssdev
,
level
);
if
(
r
)
return
r
;
}
return
0
;
}
static
int
taal_bl_get_intensity
(
struct
backlight_device
*
dev
)
{
if
(
dev
->
props
.
fb_blank
==
FB_BLANK_UNBLANK
&&
dev
->
props
.
power
==
FB_BLANK_UNBLANK
)
return
dev
->
props
.
brightness
;
return
0
;
}
static
struct
backlight_ops
taal_bl_ops
=
{
.
get_brightness
=
taal_bl_get_intensity
,
.
update_status
=
taal_bl_update_status
,
};
static
void
taal_get_timings
(
struct
omap_dss_device
*
dssdev
,
struct
omap_video_timings
*
timings
)
{
*
timings
=
dssdev
->
panel
.
timings
;
}
static
void
taal_get_resolution
(
struct
omap_dss_device
*
dssdev
,
u16
*
xres
,
u16
*
yres
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
if
(
td
->
rotate
==
0
||
td
->
rotate
==
2
)
{
*
xres
=
dssdev
->
panel
.
timings
.
x_res
;
*
yres
=
dssdev
->
panel
.
timings
.
y_res
;
}
else
{
*
yres
=
dssdev
->
panel
.
timings
.
x_res
;
*
xres
=
dssdev
->
panel
.
timings
.
y_res
;
}
}
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
);
complete_all
(
&
td
->
te_completion
);
return
IRQ_HANDLED
;
}
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
);
u8
errors
;
int
r
;
if
(
td
->
enabled
)
{
dsi_bus_lock
();
r
=
taal_dcs_read_1
(
DCS_READ_NUM_ERRORS
,
&
errors
);
dsi_bus_unlock
();
}
else
{
r
=
-
ENODEV
;
}
if
(
r
)
return
r
;
return
snprintf
(
buf
,
PAGE_SIZE
,
"%d
\n
"
,
errors
);
}
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
);
u8
id1
,
id2
,
id3
;
int
r
;
if
(
td
->
enabled
)
{
dsi_bus_lock
();
r
=
taal_get_id
(
&
id1
,
&
id2
,
&
id3
);
dsi_bus_unlock
();
}
else
{
r
=
-
ENODEV
;
}
if
(
r
)
return
r
;
return
snprintf
(
buf
,
PAGE_SIZE
,
"%02x.%02x.%02x
\n
"
,
id1
,
id2
,
id3
);
}
static
const
char
*
cabc_modes
[]
=
{
"off"
,
/* used also always 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
omap_dss_device
*
dssdev
=
to_dss_device
(
dev
);
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
const
char
*
mode_str
;
int
mode
;
int
len
;
mode
=
td
->
cabc_mode
;
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
omap_dss_device
*
dssdev
=
to_dss_device
(
dev
);
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cabc_modes
);
i
++
)
{
if
(
sysfs_streq
(
cabc_modes
[
i
],
buf
))
break
;
}
if
(
i
==
ARRAY_SIZE
(
cabc_modes
))
return
-
EINVAL
;
if
(
td
->
enabled
)
{
dsi_bus_lock
();
if
(
!
td
->
cabc_broken
)
taal_dcs_write_1
(
DCS_WRITE_CABC
,
i
);
dsi_bus_unlock
();
}
td
->
cabc_mode
=
i
;
return
count
;
}
static
ssize_t
show_cabc_available_modes
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
int
len
;
int
i
;
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
(
num_dsi_errors
,
S_IRUGO
,
taal_num_errors_show
,
NULL
);
static
DEVICE_ATTR
(
hw_revision
,
S_IRUGO
,
taal_hw_revision_show
,
NULL
);
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
*
taal_attrs
[]
=
{
&
dev_attr_num_dsi_errors
.
attr
,
&
dev_attr_hw_revision
.
attr
,
&
dev_attr_cabc_mode
.
attr
,
&
dev_attr_cabc_available_modes
.
attr
,
NULL
,
};
static
struct
attribute_group
taal_attr_group
=
{
.
attrs
=
taal_attrs
,
};
static
int
taal_probe
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
;
struct
backlight_device
*
bldev
;
int
r
;
const
struct
omap_video_timings
taal_panel_timings
=
{
.
x_res
=
864
,
.
y_res
=
480
,
};
dev_dbg
(
&
dssdev
->
dev
,
"probe
\n
"
);
dssdev
->
panel
.
config
=
OMAP_DSS_LCD_TFT
;
dssdev
->
panel
.
timings
=
taal_panel_timings
;
dssdev
->
ctrl
.
pixel_size
=
24
;
td
=
kzalloc
(
sizeof
(
*
td
),
GFP_KERNEL
);
if
(
!
td
)
{
r
=
-
ENOMEM
;
goto
err0
;
}
td
->
dssdev
=
dssdev
;
td
->
esd_wq
=
create_singlethread_workqueue
(
"taal_esd"
);
if
(
td
->
esd_wq
==
NULL
)
{
dev_err
(
&
dssdev
->
dev
,
"can't create ESD workqueue
\n
"
);
r
=
-
ENOMEM
;
goto
err2
;
}
INIT_DELAYED_WORK_DEFERRABLE
(
&
td
->
esd_work
,
taal_esd_work
);
dev_set_drvdata
(
&
dssdev
->
dev
,
td
);
dssdev
->
get_timings
=
taal_get_timings
;
dssdev
->
get_resolution
=
taal_get_resolution
;
/* if no platform set_backlight() defined, presume DSI backlight
* control */
if
(
!
dssdev
->
set_backlight
)
td
->
use_dsi_bl
=
true
;
bldev
=
backlight_device_register
(
"taal"
,
&
dssdev
->
dev
,
dssdev
,
&
taal_bl_ops
);
if
(
IS_ERR
(
bldev
))
{
r
=
PTR_ERR
(
bldev
);
goto
err1
;
}
td
->
bldev
=
bldev
;
bldev
->
props
.
fb_blank
=
FB_BLANK_UNBLANK
;
bldev
->
props
.
power
=
FB_BLANK_UNBLANK
;
if
(
td
->
use_dsi_bl
)
{
bldev
->
props
.
max_brightness
=
255
;
bldev
->
props
.
brightness
=
255
;
}
else
{
bldev
->
props
.
max_brightness
=
127
;
bldev
->
props
.
brightness
=
127
;
}
taal_bl_update_status
(
bldev
);
if
(
dssdev
->
phy
.
dsi
.
ext_te
)
{
int
gpio
=
dssdev
->
phy
.
dsi
.
ext_te_gpio
;
r
=
gpio_request
(
gpio
,
"taal irq"
);
if
(
r
)
{
dev_err
(
&
dssdev
->
dev
,
"GPIO request failed
\n
"
);
goto
err3
;
}
gpio_direction_input
(
gpio
);
r
=
request_irq
(
gpio_to_irq
(
gpio
),
taal_te_isr
,
IRQF_DISABLED
|
IRQF_TRIGGER_RISING
,
"taal vsync"
,
dssdev
);
if
(
r
)
{
dev_err
(
&
dssdev
->
dev
,
"IRQ request failed
\n
"
);
gpio_free
(
gpio
);
goto
err3
;
}
init_completion
(
&
td
->
te_completion
);
td
->
use_ext_te
=
true
;
}
r
=
sysfs_create_group
(
&
dssdev
->
dev
.
kobj
,
&
taal_attr_group
);
if
(
r
)
{
dev_err
(
&
dssdev
->
dev
,
"failed to create sysfs files
\n
"
);
goto
err4
;
}
return
0
;
err4:
if
(
td
->
use_ext_te
)
{
int
gpio
=
dssdev
->
phy
.
dsi
.
ext_te_gpio
;
free_irq
(
gpio_to_irq
(
gpio
),
dssdev
);
gpio_free
(
gpio
);
}
err3:
backlight_device_unregister
(
bldev
);
err2:
cancel_delayed_work_sync
(
&
td
->
esd_work
);
destroy_workqueue
(
td
->
esd_wq
);
err1:
kfree
(
td
);
err0:
return
r
;
}
static
void
taal_remove
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
struct
backlight_device
*
bldev
;
dev_dbg
(
&
dssdev
->
dev
,
"remove
\n
"
);
sysfs_remove_group
(
&
dssdev
->
dev
.
kobj
,
&
taal_attr_group
);
if
(
td
->
use_ext_te
)
{
int
gpio
=
dssdev
->
phy
.
dsi
.
ext_te_gpio
;
free_irq
(
gpio_to_irq
(
gpio
),
dssdev
);
gpio_free
(
gpio
);
}
bldev
=
td
->
bldev
;
bldev
->
props
.
power
=
FB_BLANK_POWERDOWN
;
taal_bl_update_status
(
bldev
);
backlight_device_unregister
(
bldev
);
cancel_delayed_work_sync
(
&
td
->
esd_work
);
destroy_workqueue
(
td
->
esd_wq
);
kfree
(
td
);
}
static
int
taal_enable
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
u8
id1
,
id2
,
id3
;
int
r
;
dev_dbg
(
&
dssdev
->
dev
,
"enable
\n
"
);
if
(
dssdev
->
platform_enable
)
{
r
=
dssdev
->
platform_enable
(
dssdev
);
if
(
r
)
return
r
;
}
/* it seems we have to wait a bit until taal is ready */
msleep
(
5
);
r
=
taal_sleep_out
(
td
);
if
(
r
)
goto
err
;
r
=
taal_get_id
(
&
id1
,
&
id2
,
&
id3
);
if
(
r
)
goto
err
;
/* on early revisions CABC is broken */
if
(
id2
==
0x00
||
id2
==
0xff
||
id2
==
0x81
)
td
->
cabc_broken
=
true
;
taal_dcs_write_1
(
DCS_BRIGHTNESS
,
0xff
);
taal_dcs_write_1
(
DCS_CTRL_DISPLAY
,
(
1
<<
2
)
|
(
1
<<
5
));
/* BL | BCTRL */
taal_dcs_write_1
(
DCS_PIXEL_FORMAT
,
0x7
);
/* 24bit/pixel */
taal_set_addr_mode
(
td
->
rotate
,
td
->
mirror
);
if
(
!
td
->
cabc_broken
)
taal_dcs_write_1
(
DCS_WRITE_CABC
,
td
->
cabc_mode
);
taal_dcs_write_0
(
DCS_DISPLAY_ON
);
#ifdef TAAL_USE_ESD_CHECK
queue_delayed_work
(
td
->
esd_wq
,
&
td
->
esd_work
,
TAAL_ESD_CHECK_PERIOD
);
#endif
td
->
enabled
=
1
;
if
(
!
td
->
intro_printed
)
{
dev_info
(
&
dssdev
->
dev
,
"revision %02x.%02x.%02x
\n
"
,
id1
,
id2
,
id3
);
if
(
td
->
cabc_broken
)
dev_info
(
&
dssdev
->
dev
,
"old Taal version, CABC disabled
\n
"
);
td
->
intro_printed
=
true
;
}
return
0
;
err:
if
(
dssdev
->
platform_disable
)
dssdev
->
platform_disable
(
dssdev
);
return
r
;
}
static
void
taal_disable
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
dev_dbg
(
&
dssdev
->
dev
,
"disable
\n
"
);
cancel_delayed_work
(
&
td
->
esd_work
);
taal_dcs_write_0
(
DCS_DISPLAY_OFF
);
taal_sleep_in
(
td
);
/* wait a bit so that the message goes through */
msleep
(
10
);
if
(
dssdev
->
platform_disable
)
dssdev
->
platform_disable
(
dssdev
);
td
->
enabled
=
0
;
}
static
int
taal_suspend
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
struct
backlight_device
*
bldev
=
td
->
bldev
;
bldev
->
props
.
power
=
FB_BLANK_POWERDOWN
;
taal_bl_update_status
(
bldev
);
return
0
;
}
static
int
taal_resume
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
struct
backlight_device
*
bldev
=
td
->
bldev
;
bldev
->
props
.
power
=
FB_BLANK_UNBLANK
;
taal_bl_update_status
(
bldev
);
return
0
;
}
static
void
taal_setup_update
(
struct
omap_dss_device
*
dssdev
,
u16
x
,
u16
y
,
u16
w
,
u16
h
)
{
taal_set_update_window
(
x
,
y
,
w
,
h
);
}
static
int
taal_enable_te
(
struct
omap_dss_device
*
dssdev
,
bool
enable
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
int
r
;
td
->
te_enabled
=
enable
;
if
(
enable
)
r
=
taal_dcs_write_1
(
DCS_TEAR_ON
,
0
);
else
r
=
taal_dcs_write_0
(
DCS_TEAR_OFF
);
return
r
;
}
static
int
taal_wait_te
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
long
wait
=
msecs_to_jiffies
(
500
);
if
(
!
td
->
use_ext_te
||
!
td
->
te_enabled
)
return
0
;
INIT_COMPLETION
(
td
->
te_completion
);
wait
=
wait_for_completion_timeout
(
&
td
->
te_completion
,
wait
);
if
(
wait
==
0
)
{
dev_err
(
&
dssdev
->
dev
,
"timeout waiting TE
\n
"
);
return
-
ETIME
;
}
return
0
;
}
static
int
taal_rotate
(
struct
omap_dss_device
*
dssdev
,
u8
rotate
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
int
r
;
dev_dbg
(
&
dssdev
->
dev
,
"rotate %d
\n
"
,
rotate
);
if
(
td
->
enabled
)
{
r
=
taal_set_addr_mode
(
rotate
,
td
->
mirror
);
if
(
r
)
return
r
;
}
td
->
rotate
=
rotate
;
return
0
;
}
static
u8
taal_get_rotate
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
return
td
->
rotate
;
}
static
int
taal_mirror
(
struct
omap_dss_device
*
dssdev
,
bool
enable
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
int
r
;
dev_dbg
(
&
dssdev
->
dev
,
"mirror %d
\n
"
,
enable
);
if
(
td
->
enabled
)
{
r
=
taal_set_addr_mode
(
td
->
rotate
,
enable
);
if
(
r
)
return
r
;
}
td
->
mirror
=
enable
;
return
0
;
}
static
bool
taal_get_mirror
(
struct
omap_dss_device
*
dssdev
)
{
struct
taal_data
*
td
=
dev_get_drvdata
(
&
dssdev
->
dev
);
return
td
->
mirror
;
}
static
int
taal_run_test
(
struct
omap_dss_device
*
dssdev
,
int
test_num
)
{
u8
id1
,
id2
,
id3
;
int
r
;
r
=
taal_dcs_read_1
(
DCS_GET_ID1
,
&
id1
);
if
(
r
)
return
r
;
r
=
taal_dcs_read_1
(
DCS_GET_ID2
,
&
id2
);
if
(
r
)
return
r
;
r
=
taal_dcs_read_1
(
DCS_GET_ID3
,
&
id3
);
if
(
r
)
return
r
;
return
0
;
}
static
int
taal_memory_read
(
struct
omap_dss_device
*
dssdev
,
void
*
buf
,
size_t
size
,
u16
x
,
u16
y
,
u16
w
,
u16
h
)
{
int
r
;
int
first
=
1
;
int
plen
;
unsigned
buf_used
=
0
;
if
(
size
<
w
*
h
*
3
)
return
-
ENOMEM
;
size
=
min
(
w
*
h
*
3
,
dssdev
->
panel
.
timings
.
x_res
*
dssdev
->
panel
.
timings
.
y_res
*
3
);
/* plen 1 or 2 goes into short packet. until checksum error is fixed,
* use short packets. plen 32 works, but bigger packets seem to cause
* an error. */
if
(
size
%
2
)
plen
=
1
;
else
plen
=
2
;
taal_setup_update
(
dssdev
,
x
,
y
,
w
,
h
);
r
=
dsi_vc_set_max_rx_packet_size
(
TCH
,
plen
);
if
(
r
)
return
r
;
while
(
buf_used
<
size
)
{
u8
dcs_cmd
=
first
?
0x2e
:
0x3e
;
first
=
0
;
r
=
dsi_vc_dcs_read
(
TCH
,
dcs_cmd
,
buf
+
buf_used
,
size
-
buf_used
);
if
(
r
<
0
)
{
dev_err
(
&
dssdev
->
dev
,
"read error
\n
"
);
goto
err
;
}
buf_used
+=
r
;
if
(
r
<
plen
)
{
dev_err
(
&
dssdev
->
dev
,
"short read
\n
"
);
break
;
}
if
(
signal_pending
(
current
))
{
dev_err
(
&
dssdev
->
dev
,
"signal pending, "
"aborting memory read
\n
"
);
r
=
-
ERESTARTSYS
;
goto
err
;
}
}
r
=
buf_used
;
err:
dsi_vc_set_max_rx_packet_size
(
TCH
,
1
);
return
r
;
}
static
void
taal_esd_work
(
struct
work_struct
*
work
)
{
struct
taal_data
*
td
=
container_of
(
work
,
struct
taal_data
,
esd_work
.
work
);
struct
omap_dss_device
*
dssdev
=
td
->
dssdev
;
u8
state1
,
state2
;
int
r
;
if
(
!
td
->
enabled
)
return
;
dsi_bus_lock
();
r
=
taal_dcs_read_1
(
DCS_RDDSDR
,
&
state1
);
if
(
r
)
{
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
"
);
goto
err
;
}
r
=
taal_dcs_read_1
(
DCS_RDDSDR
,
&
state2
);
if
(
r
)
{
dev_err
(
&
dssdev
->
dev
,
"failed to read Taal status
\n
"
);
goto
err
;
}
/* Each sleep out command will trigger a self diagnostic and flip
* Bit6 if the test passes.
*/
if
(
!
((
state1
^
state2
)
&
(
1
<<
6
)))
{
dev_err
(
&
dssdev
->
dev
,
"LCD self diagnostics failed
\n
"
);
goto
err
;
}
/* Self-diagnostics result is also shown on TE GPIO line. We need
* to re-enable TE after self diagnostics */
if
(
td
->
use_ext_te
&&
td
->
te_enabled
)
taal_enable_te
(
dssdev
,
true
);
dsi_bus_unlock
();
queue_delayed_work
(
td
->
esd_wq
,
&
td
->
esd_work
,
TAAL_ESD_CHECK_PERIOD
);
return
;
err:
dev_err
(
&
dssdev
->
dev
,
"performing LCD reset
\n
"
);
taal_disable
(
dssdev
);
taal_enable
(
dssdev
);
dsi_bus_unlock
();
queue_delayed_work
(
td
->
esd_wq
,
&
td
->
esd_work
,
TAAL_ESD_CHECK_PERIOD
);
}
static
struct
omap_dss_driver
taal_driver
=
{
.
probe
=
taal_probe
,
.
remove
=
taal_remove
,
.
enable
=
taal_enable
,
.
disable
=
taal_disable
,
.
suspend
=
taal_suspend
,
.
resume
=
taal_resume
,
.
setup_update
=
taal_setup_update
,
.
enable_te
=
taal_enable_te
,
.
wait_for_te
=
taal_wait_te
,
.
set_rotate
=
taal_rotate
,
.
get_rotate
=
taal_get_rotate
,
.
set_mirror
=
taal_mirror
,
.
get_mirror
=
taal_get_mirror
,
.
run_test
=
taal_run_test
,
.
memory_read
=
taal_memory_read
,
.
driver
=
{
.
name
=
"taal"
,
.
owner
=
THIS_MODULE
,
},
};
static
int
__init
taal_init
(
void
)
{
omap_dss_register_driver
(
&
taal_driver
);
return
0
;
}
static
void
__exit
taal_exit
(
void
)
{
omap_dss_unregister_driver
(
&
taal_driver
);
}
module_init
(
taal_init
);
module_exit
(
taal_exit
);
MODULE_AUTHOR
(
"Tomi Valkeinen <tomi.valkeinen@nokia.com>"
);
MODULE_DESCRIPTION
(
"Taal Driver"
);
MODULE_LICENSE
(
"GPL"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment