Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
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
Show 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