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
395e9801
Commit
395e9801
authored
Dec 08, 2009
by
Kevin Hilman
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'davinci-upstream-accepted' into davinci-reset
parents
ca3e7676
9e56b56d
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1273 additions
and
27 deletions
+1273
-27
arch/arm/mach-davinci/include/mach/keyscan.h
arch/arm/mach-davinci/include/mach/keyscan.h
+41
-0
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Kconfig
+10
-0
drivers/input/keyboard/Makefile
drivers/input/keyboard/Makefile
+1
-0
drivers/input/keyboard/davinci_keyscan.c
drivers/input/keyboard/davinci_keyscan.c
+337
-0
drivers/mtd/mtdpart.c
drivers/mtd/mtdpart.c
+40
-0
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/davinci_nand.c
+1
-1
drivers/rtc/Kconfig
drivers/rtc/Kconfig
+10
-0
drivers/rtc/Makefile
drivers/rtc/Makefile
+1
-0
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-davinci.c
+673
-0
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-omap.c
+0
-5
drivers/video/da8xx-fb.c
drivers/video/da8xx-fb.c
+155
-21
include/linux/mtd/partitions.h
include/linux/mtd/partitions.h
+3
-0
include/video/da8xx-fb.h
include/video/da8xx-fb.h
+1
-0
No files found.
arch/arm/mach-davinci/include/mach/keyscan.h
0 → 100644
View file @
395e9801
/*
* Copyright (C) 2009 Texas Instruments, Inc
*
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.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.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DAVINCI_KEYSCAN_H
#define DAVINCI_KEYSCAN_H
#include <linux/io.h>
enum
davinci_matrix_types
{
DAVINCI_KEYSCAN_MATRIX_4X4
,
DAVINCI_KEYSCAN_MATRIX_5X3
,
};
struct
davinci_ks_platform_data
{
unsigned
short
*
keymap
;
u32
keymapsize
;
u8
rep
:
1
;
u8
strobe
;
u8
interval
;
u8
matrix_type
;
};
#endif
drivers/input/keyboard/Kconfig
View file @
395e9801
...
...
@@ -423,4 +423,14 @@ config KEYBOARD_W90P910
To compile this driver as a module, choose M here: the
module will be called w90p910_keypad.
config KEYBOARD_DAVINCI
tristate "TI DaVinci Key Scan"
depends on ARCH_DAVINCI_DM365
help
Say Y to enable keypad module support for the TI DaVinci
platforms (DM365).
To compile this driver as a module, choose M here: the
module will be called davinci_keyscan.
endif
drivers/input/keyboard/Makefile
View file @
395e9801
...
...
@@ -37,3 +37,4 @@ obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
obj-$(CONFIG_KEYBOARD_TWL4030)
+=
twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD)
+=
xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910)
+=
w90p910_keypad.o
obj-$(CONFIG_KEYBOARD_DAVINCI)
+=
davinci_keyscan.o
drivers/input/keyboard/davinci_keyscan.c
0 → 100644
View file @
395e9801
/*
* DaVinci Key Scan Driver for TI platforms
*
* Copyright (C) 2009 Texas Instruments, Inc
*
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
*
* Intial Code: Sandeep Paulraj <s-paulraj@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.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/keyscan.h>
/* Key scan registers */
#define DAVINCI_KEYSCAN_KEYCTRL 0x0000
#define DAVINCI_KEYSCAN_INTENA 0x0004
#define DAVINCI_KEYSCAN_INTFLAG 0x0008
#define DAVINCI_KEYSCAN_INTCLR 0x000c
#define DAVINCI_KEYSCAN_STRBWIDTH 0x0010
#define DAVINCI_KEYSCAN_INTERVAL 0x0014
#define DAVINCI_KEYSCAN_CONTTIME 0x0018
#define DAVINCI_KEYSCAN_CURRENTST 0x001c
#define DAVINCI_KEYSCAN_PREVSTATE 0x0020
#define DAVINCI_KEYSCAN_EMUCTRL 0x0024
#define DAVINCI_KEYSCAN_IODFTCTRL 0x002c
/* Key Control Register (KEYCTRL) */
#define DAVINCI_KEYSCAN_KEYEN 0x00000001
#define DAVINCI_KEYSCAN_PREVMODE 0x00000002
#define DAVINCI_KEYSCAN_CHATOFF 0x00000004
#define DAVINCI_KEYSCAN_AUTODET 0x00000008
#define DAVINCI_KEYSCAN_SCANMODE 0x00000010
#define DAVINCI_KEYSCAN_OUTTYPE 0x00000020
/* Masks for the interrupts */
#define DAVINCI_KEYSCAN_INT_CONT 0x00000008
#define DAVINCI_KEYSCAN_INT_OFF 0x00000004
#define DAVINCI_KEYSCAN_INT_ON 0x00000002
#define DAVINCI_KEYSCAN_INT_CHANGE 0x00000001
#define DAVINCI_KEYSCAN_INT_ALL 0x0000000f
struct
davinci_ks
{
struct
input_dev
*
input
;
struct
davinci_ks_platform_data
*
pdata
;
int
irq
;
void
__iomem
*
base
;
resource_size_t
pbase
;
size_t
base_size
;
unsigned
short
keymap
[];
};
/* Initializing the kp Module */
static
int
__init
davinci_ks_initialize
(
struct
davinci_ks
*
davinci_ks
)
{
struct
device
*
dev
=
&
davinci_ks
->
input
->
dev
;
struct
davinci_ks_platform_data
*
pdata
=
davinci_ks
->
pdata
;
u32
matrix_ctrl
;
/* Enable all interrupts */
__raw_writel
(
DAVINCI_KEYSCAN_INT_ALL
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_INTENA
);
/* Clear interrupts if any */
__raw_writel
(
DAVINCI_KEYSCAN_INT_ALL
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_INTCLR
);
/* Setup the scan period = strobe + interval */
__raw_writel
(
pdata
->
strobe
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_STRBWIDTH
);
__raw_writel
(
pdata
->
interval
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_INTERVAL
);
__raw_writel
(
0x01
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_CONTTIME
);
/* Define matrix type */
switch
(
pdata
->
matrix_type
)
{
case
DAVINCI_KEYSCAN_MATRIX_4X4
:
matrix_ctrl
=
0
;
break
;
case
DAVINCI_KEYSCAN_MATRIX_5X3
:
matrix_ctrl
=
(
1
<<
6
);
break
;
default:
dev_err
(
dev
->
parent
,
"wrong matrix type
\n
"
);
return
-
EINVAL
;
}
/* Enable key scan module and set matrix type */
__raw_writel
(
DAVINCI_KEYSCAN_AUTODET
|
DAVINCI_KEYSCAN_KEYEN
|
matrix_ctrl
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_KEYCTRL
);
return
0
;
}
static
irqreturn_t
davinci_ks_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
davinci_ks
*
davinci_ks
=
dev_id
;
struct
device
*
dev
=
&
davinci_ks
->
input
->
dev
;
unsigned
short
*
keymap
=
davinci_ks
->
keymap
;
int
keymapsize
=
davinci_ks
->
pdata
->
keymapsize
;
u32
prev_status
,
new_status
,
changed
;
bool
release
;
int
keycode
=
KEY_UNKNOWN
;
int
i
;
/* Disable interrupt */
__raw_writel
(
0x0
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_INTENA
);
/* Reading previous and new status of the key scan */
prev_status
=
__raw_readl
(
davinci_ks
->
base
+
DAVINCI_KEYSCAN_PREVSTATE
);
new_status
=
__raw_readl
(
davinci_ks
->
base
+
DAVINCI_KEYSCAN_CURRENTST
);
changed
=
prev_status
^
new_status
;
if
(
changed
)
{
/*
* It goes through all bits in 'changed' to ensure
* that no key changes are being missed
*/
for
(
i
=
0
;
i
<
keymapsize
;
i
++
)
{
if
((
changed
>>
i
)
&
0x1
)
{
keycode
=
keymap
[
i
];
release
=
(
new_status
>>
i
)
&
0x1
;
dev_dbg
(
dev
->
parent
,
"key %d %s
\n
"
,
keycode
,
release
?
"released"
:
"pressed"
);
input_report_key
(
davinci_ks
->
input
,
keycode
,
!
release
);
input_sync
(
davinci_ks
->
input
);
}
}
/* Clearing interrupt */
__raw_writel
(
DAVINCI_KEYSCAN_INT_ALL
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_INTCLR
);
}
/* Enable interrupts */
__raw_writel
(
0x1
,
davinci_ks
->
base
+
DAVINCI_KEYSCAN_INTENA
);
return
IRQ_HANDLED
;
}
static
int
__init
davinci_ks_probe
(
struct
platform_device
*
pdev
)
{
struct
davinci_ks
*
davinci_ks
;
struct
input_dev
*
key_dev
;
struct
resource
*
res
,
*
mem
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
davinci_ks_platform_data
*
pdata
=
pdev
->
dev
.
platform_data
;
int
error
,
i
;
if
(
!
pdata
->
keymap
)
{
dev_dbg
(
dev
,
"no keymap from pdata
\n
"
);
return
-
EINVAL
;
}
davinci_ks
=
kzalloc
(
sizeof
(
struct
davinci_ks
)
+
sizeof
(
unsigned
short
)
*
pdata
->
keymapsize
,
GFP_KERNEL
);
if
(
!
davinci_ks
)
{
dev_dbg
(
dev
,
"could not allocate memory for private data
\n
"
);
return
-
ENOMEM
;
}
memcpy
(
davinci_ks
->
keymap
,
pdata
->
keymap
,
sizeof
(
unsigned
short
)
*
pdata
->
keymapsize
);
key_dev
=
input_allocate_device
();
if
(
!
key_dev
)
{
dev_dbg
(
dev
,
"could not allocate input device
\n
"
);
error
=
-
ENOMEM
;
goto
fail1
;
}
davinci_ks
->
input
=
key_dev
;
davinci_ks
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
davinci_ks
->
irq
<
0
)
{
dev_err
(
dev
,
"no key scan irq
\n
"
);
error
=
davinci_ks
->
irq
;
goto
fail2
;
}
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
dev_err
(
dev
,
"no mem resource
\n
"
);
error
=
-
EINVAL
;
goto
fail2
;
}
davinci_ks
->
pbase
=
res
->
start
;
davinci_ks
->
base_size
=
resource_size
(
res
);
mem
=
request_mem_region
(
davinci_ks
->
pbase
,
davinci_ks
->
base_size
,
pdev
->
name
);
if
(
!
mem
)
{
dev_err
(
dev
,
"key scan registers at %08x are not free
\n
"
,
davinci_ks
->
pbase
);
error
=
-
EBUSY
;
goto
fail2
;
}
davinci_ks
->
base
=
ioremap
(
davinci_ks
->
pbase
,
davinci_ks
->
base_size
);
if
(
!
davinci_ks
->
base
)
{
dev_err
(
dev
,
"can't ioremap MEM resource.
\n
"
);
error
=
-
ENOMEM
;
goto
fail3
;
}
/* Enable auto repeat feature of Linux input subsystem */
if
(
pdata
->
rep
)
__set_bit
(
EV_REP
,
key_dev
->
evbit
);
/* Setup input device */
__set_bit
(
EV_KEY
,
key_dev
->
evbit
);
/* Setup the platform data */
davinci_ks
->
pdata
=
pdata
;
for
(
i
=
0
;
i
<
davinci_ks
->
pdata
->
keymapsize
;
i
++
)
__set_bit
(
davinci_ks
->
pdata
->
keymap
[
i
],
key_dev
->
keybit
);
key_dev
->
name
=
"davinci_keyscan"
;
key_dev
->
phys
=
"davinci_keyscan/input0"
;
key_dev
->
dev
.
parent
=
&
pdev
->
dev
;
key_dev
->
id
.
bustype
=
BUS_HOST
;
key_dev
->
id
.
vendor
=
0x0001
;
key_dev
->
id
.
product
=
0x0001
;
key_dev
->
id
.
version
=
0x0001
;
key_dev
->
keycode
=
davinci_ks
->
keymap
;
key_dev
->
keycodesize
=
sizeof
(
davinci_ks
->
keymap
[
0
]);
key_dev
->
keycodemax
=
davinci_ks
->
pdata
->
keymapsize
;
error
=
input_register_device
(
davinci_ks
->
input
);
if
(
error
<
0
)
{
dev_err
(
dev
,
"unable to register davinci key scan device
\n
"
);
goto
fail4
;
}
error
=
request_irq
(
davinci_ks
->
irq
,
davinci_ks_interrupt
,
IRQF_DISABLED
,
pdev
->
name
,
davinci_ks
);
if
(
error
<
0
)
{
dev_err
(
dev
,
"unable to register davinci key scan interrupt
\n
"
);
goto
fail5
;
}
error
=
davinci_ks_initialize
(
davinci_ks
);
if
(
error
<
0
)
{
dev_err
(
dev
,
"unable to initialize davinci key scan device
\n
"
);
goto
fail6
;
}
platform_set_drvdata
(
pdev
,
davinci_ks
);
return
0
;
fail6:
free_irq
(
davinci_ks
->
irq
,
davinci_ks
);
fail5:
input_unregister_device
(
davinci_ks
->
input
);
key_dev
=
NULL
;
fail4:
iounmap
(
davinci_ks
->
base
);
fail3:
release_mem_region
(
davinci_ks
->
pbase
,
davinci_ks
->
base_size
);
fail2:
input_free_device
(
key_dev
);
fail1:
kfree
(
davinci_ks
);
return
error
;
}
static
int
__devexit
davinci_ks_remove
(
struct
platform_device
*
pdev
)
{
struct
davinci_ks
*
davinci_ks
=
platform_get_drvdata
(
pdev
);
free_irq
(
davinci_ks
->
irq
,
davinci_ks
);
input_unregister_device
(
davinci_ks
->
input
);
iounmap
(
davinci_ks
->
base
);
release_mem_region
(
davinci_ks
->
pbase
,
davinci_ks
->
base_size
);
platform_set_drvdata
(
pdev
,
NULL
);
kfree
(
davinci_ks
);
return
0
;
}
static
struct
platform_driver
davinci_ks_driver
=
{
.
driver
=
{
.
name
=
"davinci_keyscan"
,
.
owner
=
THIS_MODULE
,
},
.
remove
=
__devexit_p
(
davinci_ks_remove
),
};
static
int
__init
davinci_ks_init
(
void
)
{
return
platform_driver_probe
(
&
davinci_ks_driver
,
davinci_ks_probe
);
}
module_init
(
davinci_ks_init
);
static
void
__exit
davinci_ks_exit
(
void
)
{
platform_driver_unregister
(
&
davinci_ks_driver
);
}
module_exit
(
davinci_ks_exit
);
MODULE_AUTHOR
(
"Miguel Aguilar"
);
MODULE_DESCRIPTION
(
"Texas Instruments DaVinci Key Scan Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/mtd/mtdpart.c
View file @
395e9801
...
...
@@ -26,6 +26,7 @@ static LIST_HEAD(mtd_partitions);
struct
mtd_part
{
struct
mtd_info
mtd
;
struct
mtd_info
*
master
;
struct
memory_accessor
macc
;
uint64_t
offset
;
struct
list_head
list
;
};
...
...
@@ -327,6 +328,39 @@ int del_mtd_partitions(struct mtd_info *master)
}
EXPORT_SYMBOL
(
del_mtd_partitions
);
/*
* This lets other kernel code access the flash data. For example, it
* might hold a board's Ethernet address, or board-specific calibration
* data generated on the manufacturing floor.
*/
static
ssize_t
mtd_macc_read
(
struct
memory_accessor
*
macc
,
char
*
buf
,
off_t
offset
,
size_t
count
)
{
struct
mtd_part
*
part
=
container_of
(
macc
,
struct
mtd_part
,
macc
);
ssize_t
ret
=
-
EIO
;
size_t
retlen
;
if
(
part_read
((
struct
mtd_info
*
)
part
,
offset
,
count
,
&
retlen
,
buf
)
==
0
)
ret
=
retlen
;
return
ret
;
}
static
ssize_t
mtd_macc_write
(
struct
memory_accessor
*
macc
,
const
char
*
buf
,
off_t
offset
,
size_t
count
)
{
struct
mtd_part
*
part
=
container_of
(
macc
,
struct
mtd_part
,
macc
);
ssize_t
ret
=
-
EIO
;
size_t
retlen
;
if
(
part_write
((
struct
mtd_info
*
)
part
,
offset
,
count
,
&
retlen
,
buf
)
==
0
)
ret
=
retlen
;
return
ret
;
}
static
struct
mtd_part
*
add_one_partition
(
struct
mtd_info
*
master
,
const
struct
mtd_partition
*
part
,
int
partno
,
uint64_t
cur_offset
)
...
...
@@ -364,6 +398,9 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
slave
->
mtd
.
read
=
part_read
;
slave
->
mtd
.
write
=
part_write
;
slave
->
macc
.
read
=
mtd_macc_read
;
slave
->
macc
.
write
=
mtd_macc_write
;
if
(
master
->
panic_write
)
slave
->
mtd
.
panic_write
=
part_panic_write
;
...
...
@@ -428,6 +465,9 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
printk
(
KERN_NOTICE
"0x%012llx-0x%012llx :
\"
%s
\"\n
"
,
(
unsigned
long
long
)
slave
->
offset
,
(
unsigned
long
long
)(
slave
->
offset
+
slave
->
mtd
.
size
),
slave
->
mtd
.
name
);
if
(
part
->
setup
)
part
->
setup
(
&
slave
->
macc
,
(
void
*
)
part
->
context
);
/* let's do some sanity checks */
if
(
slave
->
offset
>=
master
->
size
)
{
/* let's register it anyway to preserve ordering */
...
...
drivers/mtd/nand/davinci_nand.c
View file @
395e9801
...
...
@@ -599,7 +599,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info
->
mask_chipsel
=
pdata
->
mask_chipsel
;
/* use nandboot-capable ALE/CLE masks by default */
info
->
mask_ale
=
pdata
->
mask_
c
le
?
:
MASK_ALE
;
info
->
mask_ale
=
pdata
->
mask_
a
le
?
:
MASK_ALE
;
info
->
mask_cle
=
pdata
->
mask_cle
?
:
MASK_CLE
;
/* Set address of hardware control function */
...
...
drivers/rtc/Kconfig
View file @
395e9801
...
...
@@ -576,6 +576,16 @@ config RTC_DRV_AB3100
comment "on-CPU RTC drivers"
config RTC_DRV_DAVINCI
tristate "TI DaVinci RTC"
depends on ARCH_DAVINCI_DM365
help
If you say yes here you get support for the RTC on the
DaVinci platforms (DM365).
This driver can also be built as a module. If so, the module
will be called rtc-davinci.
config RTC_DRV_OMAP
tristate "TI OMAP1"
depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730
...
...
drivers/rtc/Makefile
View file @
395e9801
...
...
@@ -26,6 +26,7 @@ obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_BQ4802)
+=
rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_CMOS)
+=
rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331)
+=
rtc-coh901331.o
obj-$(CONFIG_RTC_DRV_DAVINCI)
+=
rtc-davinci.o
obj-$(CONFIG_RTC_DRV_DM355EVM)
+=
rtc-dm355evm.o
obj-$(CONFIG_RTC_DRV_DS1216)
+=
rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1286)
+=
rtc-ds1286.o
...
...
drivers/rtc/rtc-davinci.c
0 → 100644
View file @
395e9801
/*
* DaVinci Power Management and Real Time Clock Driver for TI platforms
*
* Copyright (C) 2009 Texas Instruments, Inc
*
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.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.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/platform_device.h>
#include <linux/io.h>
/*
* The DaVinci RTC is a simple RTC with the following
* Sec: 0 - 59 : BCD count
* Min: 0 - 59 : BCD count
* Hour: 0 - 23 : BCD count
* Day: 0 - 0x7FFF(32767) : Binary count ( Over 89 years )
*/
/* PRTC interface registers */
#define DAVINCI_PRTCIF_PID 0x00
#define PRTCIF_CTLR 0x04
#define PRTCIF_LDATA 0x08
#define PRTCIF_UDATA 0x0C
#define PRTCIF_INTEN 0x10
#define PRTCIF_INTFLG 0x14
/* PRTCIF_CTLR bit fields */
#define PRTCIF_CTLR_BUSY BIT(31)
#define PRTCIF_CTLR_SIZE BIT(25)
#define PRTCIF_CTLR_DIR BIT(24)
#define PRTCIF_CTLR_BENU_MSB BIT(23)
#define PRTCIF_CTLR_BENU_3RD_BYTE BIT(22)
#define PRTCIF_CTLR_BENU_2ND_BYTE BIT(21)
#define PRTCIF_CTLR_BENU_LSB BIT(20)
#define PRTCIF_CTLR_BENU_MASK (0x00F00000)
#define PRTCIF_CTLR_BENL_MSB BIT(19)
#define PRTCIF_CTLR_BENL_3RD_BYTE BIT(18)
#define PRTCIF_CTLR_BENL_2ND_BYTE BIT(17)
#define PRTCIF_CTLR_BENL_LSB BIT(16)
#define PRTCIF_CTLR_BENL_MASK (0x000F0000)
/* PRTCIF_INTEN bit fields */
#define PRTCIF_INTEN_RTCSS BIT(1)
#define PRTCIF_INTEN_RTCIF BIT(0)
#define PRTCIF_INTEN_MASK (PRTCIF_INTEN_RTCSS \
| PRTCIF_INTEN_RTCIF)
/* PRTCIF_INTFLG bit fields */
#define PRTCIF_INTFLG_RTCSS BIT(1)
#define PRTCIF_INTFLG_RTCIF BIT(0)
#define PRTCIF_INTFLG_MASK (PRTCIF_INTFLG_RTCSS \
| PRTCIF_INTFLG_RTCIF)
/* PRTC subsystem registers */
#define PRTCSS_RTC_INTC_EXTENA1 (0x0C)
#define PRTCSS_RTC_CTRL (0x10)
#define PRTCSS_RTC_WDT (0x11)
#define PRTCSS_RTC_TMR0 (0x12)
#define PRTCSS_RTC_TMR1 (0x13)
#define PRTCSS_RTC_CCTRL (0x14)
#define PRTCSS_RTC_SEC (0x15)
#define PRTCSS_RTC_MIN (0x16)
#define PRTCSS_RTC_HOUR (0x17)
#define PRTCSS_RTC_DAY0 (0x18)
#define PRTCSS_RTC_DAY1 (0x19)
#define PRTCSS_RTC_AMIN (0x1A)
#define PRTCSS_RTC_AHOUR (0x1B)
#define PRTCSS_RTC_ADAY0 (0x1C)
#define PRTCSS_RTC_ADAY1 (0x1D)
#define PRTCSS_RTC_CLKC_CNT (0x20)
/* PRTCSS_RTC_INTC_EXTENA1 */
#define PRTCSS_RTC_INTC_EXTENA1_MASK (0x07)
/* PRTCSS_RTC_CTRL bit fields */
#define PRTCSS_RTC_CTRL_WDTBUS BIT(7)
#define PRTCSS_RTC_CTRL_WEN BIT(6)
#define PRTCSS_RTC_CTRL_WDRT BIT(5)
#define PRTCSS_RTC_CTRL_WDTFLG BIT(4)
#define PRTCSS_RTC_CTRL_TE BIT(3)
#define PRTCSS_RTC_CTRL_TIEN BIT(2)
#define PRTCSS_RTC_CTRL_TMRFLG BIT(1)
#define PRTCSS_RTC_CTRL_TMMD BIT(0)
/* PRTCSS_RTC_CCTRL bit fields */
#define PRTCSS_RTC_CCTRL_CALBUSY BIT(7)
#define PRTCSS_RTC_CCTRL_DAEN BIT(5)
#define PRTCSS_RTC_CCTRL_HAEN BIT(4)
#define PRTCSS_RTC_CCTRL_MAEN BIT(3)
#define PRTCSS_RTC_CCTRL_ALMFLG BIT(2)
#define PRTCSS_RTC_CCTRL_AIEN BIT(1)
#define PRTCSS_RTC_CCTRL_CAEN BIT(0)
static
DEFINE_SPINLOCK
(
davinci_rtc_lock
);
struct
davinci_rtc
{
struct
rtc_device
*
rtc
;
void
__iomem
*
base
;
resource_size_t
pbase
;
size_t
base_size
;
int
irq
;
};
static
inline
void
rtcif_write
(
struct
davinci_rtc
*
davinci_rtc
,
u32
val
,
u32
addr
)
{
writel
(
val
,
davinci_rtc
->
base
+
addr
);
}
static
inline
u32
rtcif_read
(
struct
davinci_rtc
*
davinci_rtc
,
u32
addr
)
{
return
readl
(
davinci_rtc
->
base
+
addr
);
}
static
inline
void
rtcif_wait
(
struct
davinci_rtc
*
davinci_rtc
)
{
while
(
rtcif_read
(
davinci_rtc
,
PRTCIF_CTLR
)
&
PRTCIF_CTLR_BUSY
)
cpu_relax
();
}
static
inline
void
rtcss_write
(
struct
davinci_rtc
*
davinci_rtc
,
unsigned
long
val
,
u8
addr
)
{
rtcif_wait
(
davinci_rtc
);
rtcif_write
(
davinci_rtc
,
PRTCIF_CTLR_BENL_LSB
|
addr
,
PRTCIF_CTLR
);
rtcif_write
(
davinci_rtc
,
val
,
PRTCIF_LDATA
);
rtcif_wait
(
davinci_rtc
);
}
static
inline
u8
rtcss_read
(
struct
davinci_rtc
*
davinci_rtc
,
u8
addr
)
{
rtcif_wait
(
davinci_rtc
);
rtcif_write
(
davinci_rtc
,
PRTCIF_CTLR_DIR
|
PRTCIF_CTLR_BENL_LSB
|
addr
,
PRTCIF_CTLR
);
rtcif_wait
(
davinci_rtc
);
return
rtcif_read
(
davinci_rtc
,
PRTCIF_LDATA
);
}
static
inline
void
davinci_rtcss_calendar_wait
(
struct
davinci_rtc
*
davinci_rtc
)
{
while
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CCTRL
)
&
PRTCSS_RTC_CCTRL_CALBUSY
)
cpu_relax
();
}
static
irqreturn_t
davinci_rtc_interrupt
(
int
irq
,
void
*
class_dev
)
{
struct
davinci_rtc
*
davinci_rtc
=
class_dev
;
unsigned
long
events
=
0
;
u32
irq_flg
;
u8
alm_irq
,
tmr_irq
;
u8
rtc_ctrl
,
rtc_cctrl
;
int
ret
=
IRQ_NONE
;
irq_flg
=
rtcif_read
(
davinci_rtc
,
PRTCIF_INTFLG
)
&
PRTCIF_INTFLG_RTCSS
;
alm_irq
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CCTRL
)
&
PRTCSS_RTC_CCTRL_ALMFLG
;
tmr_irq
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CTRL
)
&
PRTCSS_RTC_CTRL_TMRFLG
;
if
(
irq_flg
)
{
if
(
alm_irq
)
{
events
|=
RTC_IRQF
|
RTC_AF
;
rtc_cctrl
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CCTRL
);
rtc_cctrl
|=
PRTCSS_RTC_CCTRL_ALMFLG
;
rtcss_write
(
davinci_rtc
,
rtc_cctrl
,
PRTCSS_RTC_CCTRL
);
}
else
if
(
tmr_irq
)
{
events
|=
RTC_IRQF
|
RTC_PF
;
rtc_ctrl
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CTRL
);
rtc_ctrl
|=
PRTCSS_RTC_CTRL_TMRFLG
;
rtcss_write
(
davinci_rtc
,
rtc_ctrl
,
PRTCSS_RTC_CTRL
);
}
rtcif_write
(
davinci_rtc
,
PRTCIF_INTFLG_RTCSS
,
PRTCIF_INTFLG
);
rtc_update_irq
(
davinci_rtc
->
rtc
,
1
,
events
);
ret
=
IRQ_HANDLED
;
}
return
ret
;
}
static
int
davinci_rtc_ioctl
(
struct
device
*
dev
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
u8
rtc_ctrl
;
unsigned
long
flags
;
int
ret
=
0
;
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
rtc_ctrl
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CTRL
);
switch
(
cmd
)
{
case
RTC_WIE_ON
:
rtc_ctrl
|=
PRTCSS_RTC_CTRL_WEN
|
PRTCSS_RTC_CTRL_WDTFLG
;
break
;
case
RTC_WIE_OFF
:
rtc_ctrl
&=
~
PRTCSS_RTC_CTRL_WEN
;
break
;
case
RTC_UIE_OFF
:
case
RTC_UIE_ON
:
ret
=
-
ENOTTY
;
break
;
default:
ret
=
-
ENOIOCTLCMD
;
}
rtcss_write
(
davinci_rtc
,
rtc_ctrl
,
PRTCSS_RTC_CTRL
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
return
ret
;
}
static
int
convertfromdays
(
u16
days
,
struct
rtc_time
*
tm
)
{
int
tmp_days
,
year
,
mon
;
for
(
year
=
2000
;;
year
++
)
{
tmp_days
=
rtc_year_days
(
1
,
12
,
year
);
if
(
days
>=
tmp_days
)
days
-=
tmp_days
;
else
{
for
(
mon
=
0
;;
mon
++
)
{
tmp_days
=
rtc_month_days
(
mon
,
year
);
if
(
days
>=
tmp_days
)
{
days
-=
tmp_days
;
}
else
{
tm
->
tm_year
=
year
-
1900
;
tm
->
tm_mon
=
mon
;
tm
->
tm_mday
=
days
+
1
;
break
;
}
}
break
;
}
}
return
0
;
}
static
int
convert2days
(
u16
*
days
,
struct
rtc_time
*
tm
)
{
int
i
;
*
days
=
0
;
/* epoch == 1900 */
if
(
tm
->
tm_year
<
100
||
tm
->
tm_year
>
199
)
return
-
EINVAL
;
for
(
i
=
2000
;
i
<
1900
+
tm
->
tm_year
;
i
++
)
*
days
+=
rtc_year_days
(
1
,
12
,
i
);
*
days
+=
rtc_year_days
(
tm
->
tm_mday
,
tm
->
tm_mon
,
1900
+
tm
->
tm_year
);
return
0
;
}
static
int
davinci_rtc_read_time
(
struct
device
*
dev
,
struct
rtc_time
*
tm
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
u16
days
=
0
;
u8
day0
,
day1
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
tm
->
tm_sec
=
bcd2bin
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_SEC
));
davinci_rtcss_calendar_wait
(
davinci_rtc
);
tm
->
tm_min
=
bcd2bin
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_MIN
));
davinci_rtcss_calendar_wait
(
davinci_rtc
);
tm
->
tm_hour
=
bcd2bin
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_HOUR
));
davinci_rtcss_calendar_wait
(
davinci_rtc
);
day0
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_DAY0
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
day1
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_DAY1
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
days
|=
day1
;
days
<<=
8
;
days
|=
day0
;
if
(
convertfromdays
(
days
,
tm
)
<
0
)
return
-
EINVAL
;
return
0
;
}
static
int
davinci_rtc_set_time
(
struct
device
*
dev
,
struct
rtc_time
*
tm
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
u16
days
;
u8
rtc_cctrl
;
unsigned
long
flags
;
if
(
convert2days
(
&
days
,
tm
)
<
0
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
bin2bcd
(
tm
->
tm_sec
),
PRTCSS_RTC_SEC
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
bin2bcd
(
tm
->
tm_min
),
PRTCSS_RTC_MIN
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
bin2bcd
(
tm
->
tm_hour
),
PRTCSS_RTC_HOUR
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
days
&
0xFF
,
PRTCSS_RTC_DAY0
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
(
days
&
0xFF00
)
>>
8
,
PRTCSS_RTC_DAY1
);
rtc_cctrl
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CCTRL
);
rtc_cctrl
|=
PRTCSS_RTC_CCTRL_CAEN
;
rtcss_write
(
davinci_rtc
,
rtc_cctrl
,
PRTCSS_RTC_CCTRL
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
return
0
;
}
static
int
davinci_rtc_alarm_irq_enable
(
struct
device
*
dev
,
unsigned
int
enabled
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
unsigned
long
flags
;
u8
rtc_cctrl
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CCTRL
);
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
if
(
enabled
)
rtc_cctrl
|=
PRTCSS_RTC_CCTRL_DAEN
|
PRTCSS_RTC_CCTRL_HAEN
|
PRTCSS_RTC_CCTRL_MAEN
|
PRTCSS_RTC_CCTRL_ALMFLG
|
PRTCSS_RTC_CCTRL_AIEN
;
else
rtc_cctrl
&=
~
PRTCSS_RTC_CCTRL_AIEN
;
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
rtc_cctrl
,
PRTCSS_RTC_CCTRL
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
return
0
;
}
static
int
davinci_rtc_read_alarm
(
struct
device
*
dev
,
struct
rtc_wkalrm
*
alm
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
u16
days
=
0
;
u8
day0
,
day1
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
alm
->
time
.
tm_min
=
bcd2bin
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_AMIN
));
davinci_rtcss_calendar_wait
(
davinci_rtc
);
alm
->
time
.
tm_hour
=
bcd2bin
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_AHOUR
));
davinci_rtcss_calendar_wait
(
davinci_rtc
);
day0
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_ADAY0
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
day1
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_ADAY1
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
days
|=
day1
;
days
<<=
8
;
days
|=
day0
;
if
(
convertfromdays
(
days
,
&
alm
->
time
)
<
0
)
return
-
EINVAL
;
alm
->
pending
=
!!
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CCTRL
)
&
PRTCSS_RTC_CCTRL_AIEN
);
alm
->
enabled
=
alm
->
pending
&&
device_may_wakeup
(
dev
);
return
0
;
}
static
int
davinci_rtc_set_alarm
(
struct
device
*
dev
,
struct
rtc_wkalrm
*
alm
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
unsigned
long
flags
;
u16
days
;
if
(
alm
->
time
.
tm_mday
<=
0
&&
alm
->
time
.
tm_mon
<
0
&&
alm
->
time
.
tm_year
<
0
)
{
struct
rtc_time
tm
;
unsigned
long
now
,
then
;
davinci_rtc_read_time
(
dev
,
&
tm
);
rtc_tm_to_time
(
&
tm
,
&
now
);
alm
->
time
.
tm_mday
=
tm
.
tm_mday
;
alm
->
time
.
tm_mon
=
tm
.
tm_mon
;
alm
->
time
.
tm_year
=
tm
.
tm_year
;
rtc_tm_to_time
(
&
alm
->
time
,
&
then
);
if
(
then
<
now
)
{
rtc_time_to_tm
(
now
+
24
*
60
*
60
,
&
tm
);
alm
->
time
.
tm_mday
=
tm
.
tm_mday
;
alm
->
time
.
tm_mon
=
tm
.
tm_mon
;
alm
->
time
.
tm_year
=
tm
.
tm_year
;
}
}
if
(
convert2days
(
&
days
,
&
alm
->
time
)
<
0
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
bin2bcd
(
alm
->
time
.
tm_min
),
PRTCSS_RTC_AMIN
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
bin2bcd
(
alm
->
time
.
tm_hour
),
PRTCSS_RTC_AHOUR
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
days
&
0xFF
,
PRTCSS_RTC_ADAY0
);
davinci_rtcss_calendar_wait
(
davinci_rtc
);
rtcss_write
(
davinci_rtc
,
(
days
&
0xFF00
)
>>
8
,
PRTCSS_RTC_ADAY1
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
return
0
;
}
static
int
davinci_rtc_irq_set_state
(
struct
device
*
dev
,
int
enabled
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
unsigned
long
flags
;
u8
rtc_ctrl
;
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
rtc_ctrl
=
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CTRL
);
if
(
enabled
)
{
while
(
rtcss_read
(
davinci_rtc
,
PRTCSS_RTC_CTRL
)
&
PRTCSS_RTC_CTRL_WDTBUS
)
cpu_relax
();
rtc_ctrl
|=
PRTCSS_RTC_CTRL_TE
;
rtcss_write
(
davinci_rtc
,
rtc_ctrl
,
PRTCSS_RTC_CTRL
);
rtcss_write
(
davinci_rtc
,
0x0
,
PRTCSS_RTC_CLKC_CNT
);
rtc_ctrl
|=
PRTCSS_RTC_CTRL_TIEN
|
PRTCSS_RTC_CTRL_TMMD
|
PRTCSS_RTC_CTRL_TMRFLG
;
}
else
rtc_ctrl
&=
~
PRTCSS_RTC_CTRL_TIEN
;
rtcss_write
(
davinci_rtc
,
rtc_ctrl
,
PRTCSS_RTC_CTRL
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
return
0
;
}
static
int
davinci_rtc_irq_set_freq
(
struct
device
*
dev
,
int
freq
)
{
struct
davinci_rtc
*
davinci_rtc
=
dev_get_drvdata
(
dev
);
unsigned
long
flags
;
u16
tmr_counter
=
(
0x8000
>>
(
ffs
(
freq
)
-
1
));
spin_lock_irqsave
(
&
davinci_rtc_lock
,
flags
);
rtcss_write
(
davinci_rtc
,
tmr_counter
&
0xFF
,
PRTCSS_RTC_TMR0
);
rtcss_write
(
davinci_rtc
,
(
tmr_counter
&
0xFF00
)
>>
8
,
PRTCSS_RTC_TMR1
);
spin_unlock_irqrestore
(
&
davinci_rtc_lock
,
flags
);
return
0
;
}
static
struct
rtc_class_ops
davinci_rtc_ops
=
{
.
ioctl
=
davinci_rtc_ioctl
,
.
read_time
=
davinci_rtc_read_time
,
.
set_time
=
davinci_rtc_set_time
,
.
alarm_irq_enable
=
davinci_rtc_alarm_irq_enable
,
.
read_alarm
=
davinci_rtc_read_alarm
,
.
set_alarm
=
davinci_rtc_set_alarm
,
.
irq_set_state
=
davinci_rtc_irq_set_state
,
.
irq_set_freq
=
davinci_rtc_irq_set_freq
,
};
static
int
__init
davinci_rtc_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
davinci_rtc
*
davinci_rtc
;
struct
resource
*
res
,
*
mem
;
int
ret
=
0
;
davinci_rtc
=
kzalloc
(
sizeof
(
struct
davinci_rtc
),
GFP_KERNEL
);
if
(
!
davinci_rtc
)
{
dev_dbg
(
dev
,
"could not allocate memory for private data
\n
"
);
return
-
ENOMEM
;
}
davinci_rtc
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
davinci_rtc
->
irq
<
0
)
{
dev_err
(
dev
,
"no RTC irq
\n
"
);
ret
=
davinci_rtc
->
irq
;
goto
fail1
;
}
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
dev_err
(
dev
,
"no mem resource
\n
"
);
ret
=
-
EINVAL
;
goto
fail1
;
}
davinci_rtc
->
pbase
=
res
->
start
;
davinci_rtc
->
base_size
=
resource_size
(
res
);
mem
=
request_mem_region
(
davinci_rtc
->
pbase
,
davinci_rtc
->
base_size
,
pdev
->
name
);
if
(
!
mem
)
{
dev_err
(
dev
,
"RTC registers at %08x are not free
\n
"
,
davinci_rtc
->
pbase
);
ret
=
-
EBUSY
;
goto
fail1
;
}
davinci_rtc
->
base
=
ioremap
(
davinci_rtc
->
pbase
,
davinci_rtc
->
base_size
);
if
(
!
davinci_rtc
->
base
)
{
dev_err
(
dev
,
"unable to ioremap MEM resource
\n
"
);
ret
=
-
ENOMEM
;
goto
fail2
;
}
davinci_rtc
->
rtc
=
rtc_device_register
(
pdev
->
name
,
&
pdev
->
dev
,
&
davinci_rtc_ops
,
THIS_MODULE
);
if
(
IS_ERR
(
davinci_rtc
->
rtc
))
{
dev_err
(
dev
,
"unable to register RTC device, err %ld
\n
"
,
PTR_ERR
(
davinci_rtc
->
rtc
));
goto
fail3
;
}
rtcif_write
(
davinci_rtc
,
PRTCIF_INTFLG_RTCSS
,
PRTCIF_INTFLG
);
rtcif_write
(
davinci_rtc
,
0
,
PRTCIF_INTEN
);
rtcss_write
(
davinci_rtc
,
0
,
PRTCSS_RTC_INTC_EXTENA1
);
rtcss_write
(
davinci_rtc
,
0
,
PRTCSS_RTC_CTRL
);
rtcss_write
(
davinci_rtc
,
0
,
PRTCSS_RTC_CCTRL
);
ret
=
request_irq
(
davinci_rtc
->
irq
,
davinci_rtc_interrupt
,
IRQF_DISABLED
,
"davinci_rtc"
,
davinci_rtc
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"unable to register davinci RTC interrupt
\n
"
);
goto
fail4
;
}
/* Enable interrupts */
rtcif_write
(
davinci_rtc
,
PRTCIF_INTEN_RTCSS
,
PRTCIF_INTEN
);
rtcss_write
(
davinci_rtc
,
PRTCSS_RTC_INTC_EXTENA1_MASK
,
PRTCSS_RTC_INTC_EXTENA1
);
rtcss_write
(
davinci_rtc
,
PRTCSS_RTC_CCTRL_CAEN
,
PRTCSS_RTC_CCTRL
);
platform_set_drvdata
(
pdev
,
davinci_rtc
);
device_init_wakeup
(
&
pdev
->
dev
,
0
);
return
0
;
fail4:
rtc_device_unregister
(
davinci_rtc
->
rtc
);
fail3:
iounmap
(
davinci_rtc
->
base
);
fail2:
release_mem_region
(
davinci_rtc
->
pbase
,
davinci_rtc
->
base_size
);
fail1:
kfree
(
davinci_rtc
);
return
ret
;
}
static
int
__devexit
davinci_rtc_remove
(
struct
platform_device
*
pdev
)
{
struct
davinci_rtc
*
davinci_rtc
=
platform_get_drvdata
(
pdev
);
device_init_wakeup
(
&
pdev
->
dev
,
0
);
rtcif_write
(
davinci_rtc
,
0
,
PRTCIF_INTEN
);
free_irq
(
davinci_rtc
->
irq
,
davinci_rtc
);
rtc_device_unregister
(
davinci_rtc
->
rtc
);
iounmap
(
davinci_rtc
->
base
);
release_mem_region
(
davinci_rtc
->
pbase
,
davinci_rtc
->
base_size
);
platform_set_drvdata
(
pdev
,
NULL
);
kfree
(
davinci_rtc
);
return
0
;
}
static
struct
platform_driver
davinci_rtc_driver
=
{
.
probe
=
davinci_rtc_probe
,
.
remove
=
__devexit_p
(
davinci_rtc_remove
),
.
driver
=
{
.
name
=
"rtc_davinci"
,
.
owner
=
THIS_MODULE
,
},
};
static
int
__init
rtc_init
(
void
)
{
return
platform_driver_probe
(
&
davinci_rtc_driver
,
davinci_rtc_probe
);
}
module_init
(
rtc_init
);
static
void
__exit
rtc_exit
(
void
)
{
platform_driver_unregister
(
&
davinci_rtc_driver
);
}
module_exit
(
rtc_exit
);
MODULE_AUTHOR
(
"Miguel Aguilar"
);
MODULE_DESCRIPTION
(
"Texas Instruments DaVinci PRTC Driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/rtc/rtc-omap.c
View file @
395e9801
...
...
@@ -399,17 +399,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
new_ctrl
|=
OMAP_RTC_CTRL_STOP
;
/* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
*
* - Boards wired so that RTC_WAKE_INT does something, and muxed
* right (W13_1610_RTC_WAKE_INT is the default after chip reset),
* should initialize the device wakeup flag appropriately.
*
* - Boards wired so RTC_ON_nOFF is used as the reset signal,
* rather than nPWRON_RESET, should forcibly enable split
* power mode. (Some chip errata report that RTC_CTRL_SPLIT
* is write-only, and always reads as zero...)
*/
device_init_wakeup
(
&
pdev
->
dev
,
0
);
if
(
new_ctrl
&
(
u8
)
OMAP_RTC_CTRL_SPLIT
)
pr_info
(
"%s: split power mode
\n
"
,
pdev
->
name
);
...
...
drivers/video/da8xx-fb.c
View file @
395e9801
...
...
@@ -28,6 +28,8 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/console.h>
#include <video/da8xx-fb.h>
#define DRIVER_NAME "da8xx_lcdc"
...
...
@@ -113,6 +115,12 @@ struct da8xx_fb_par {
unsigned
short
pseudo_palette
[
16
];
unsigned
int
databuf_sz
;
unsigned
int
palette_sz
;
unsigned
int
pxl_clk
;
int
blank
;
#ifdef CONFIG_CPU_FREQ
struct
notifier_block
freq_transition
;
#endif
void
(
*
panel_power_ctrl
)(
int
);
};
/* Variable Screen Information */
...
...
@@ -155,7 +163,7 @@ struct da8xx_panel {
int
vfp
;
/* Vertical front porch */
int
vbp
;
/* Vertical back porch */
int
vsw
;
/* Vertical Sync Pulse Width */
int
pxl_clk
;
/* Pixel clock */
unsigned
int
pxl_clk
;
/* Pixel clock */
unsigned
char
invert_pxl_clk
;
/* Invert Pixel clock */
};
...
...
@@ -171,7 +179,7 @@ static struct da8xx_panel known_lcd_panels[] = {
.
vfp
=
2
,
.
vbp
=
2
,
.
vsw
=
0
,
.
pxl_clk
=
0x1
0
,
.
pxl_clk
=
460800
0
,
.
invert_pxl_clk
=
1
,
},
/* Sharp LK043T1DG01 */
...
...
@@ -185,13 +193,23 @@ static struct da8xx_panel known_lcd_panels[] = {
.
vfp
=
2
,
.
vbp
=
2
,
.
vsw
=
10
,
.
pxl_clk
=
0x12
,
.
pxl_clk
=
7833600
,
.
invert_pxl_clk
=
0
,
},
};
/* Enable the Raster Engine of the LCD Controller */
static
inline
void
lcd_enable_raster
(
void
)
{
u32
reg
;
reg
=
lcdc_read
(
LCD_RASTER_CTRL_REG
);
if
(
!
(
reg
&
LCD_RASTER_ENABLE
))
lcdc_write
(
reg
|
LCD_RASTER_ENABLE
,
LCD_RASTER_CTRL_REG
);
}
/* Disable the Raster Engine of the LCD Controller */
static
void
lcd_disable_raster
(
struct
da8xx_fb_par
*
par
)
static
inline
void
lcd_disable_raster
(
void
)
{
u32
reg
;
...
...
@@ -443,25 +461,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
static
void
lcd_reset
(
struct
da8xx_fb_par
*
par
)
{
/* Disable the Raster if previously Enabled */
if
(
lcdc_read
(
LCD_RASTER_CTRL_REG
)
&
LCD_RASTER_ENABLE
)
lcd_disable_raster
(
par
);
lcd_disable_raster
();
/* DMA has to be disabled */
lcdc_write
(
0
,
LCD_DMA_CTRL_REG
);
lcdc_write
(
0
,
LCD_RASTER_CTRL_REG
);
}
static
void
lcd_calc_clk_divider
(
struct
da8xx_fb_par
*
par
)
{
unsigned
int
lcd_clk
,
div
;
lcd_clk
=
clk_get_rate
(
par
->
lcdc_clk
);
div
=
lcd_clk
/
par
->
pxl_clk
;
/* Configure the LCD clock divisor. */
lcdc_write
(
LCD_CLK_DIVISOR
(
div
)
|
(
LCD_RASTER_MODE
&
0x1
),
LCD_CTRL_REG
);
}
static
int
lcd_init
(
struct
da8xx_fb_par
*
par
,
const
struct
lcd_ctrl_config
*
cfg
,
struct
da8xx_panel
*
panel
)
{
u32
bpp
;
int
ret
=
0
;
unsigned
int
lcd_clk
,
div
;
lcd_reset
(
par
);
/* Configure the LCD clock divisor. */
lcdc_write
(
LCD_CLK_DIVISOR
(
panel
->
pxl_clk
)
|
(
LCD_RASTER_MODE
&
0x1
),
LCD_CTRL_REG
);
/* Calculate the divider */
lcd_calc_clk_divider
(
par
);
if
(
panel
->
invert_pxl_clk
)
lcdc_write
((
lcdc_read
(
LCD_RASTER_TIMING_2_REG
)
|
...
...
@@ -513,13 +542,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
static
irqreturn_t
lcdc_irq_handler
(
int
irq
,
void
*
arg
)
{
u32
stat
=
lcdc_read
(
LCD_STAT_REG
);
u32
reg
;
if
((
stat
&
LCD_SYNC_LOST
)
&&
(
stat
&
LCD_FIFO_UNDERFLOW
))
{
reg
=
lcdc_read
(
LCD_RASTER_CTRL_REG
);
lcdc_write
(
reg
&
~
LCD_RASTER_ENABLE
,
LCD_RASTER_CTRL_REG
);
lcd_disable_raster
();
lcdc_write
(
stat
,
LCD_STAT_REG
);
lcd
c_write
(
reg
|
LCD_RASTER_ENABLE
,
LCD_RASTER_CTRL_REG
);
lcd
_enable_raster
(
);
}
else
lcdc_write
(
stat
,
LCD_STAT_REG
);
...
...
@@ -574,6 +601,38 @@ static int fb_check_var(struct fb_var_screeninfo *var,
return
err
;
}
#ifdef CONFIG_CPU_FREQ
static
int
lcd_da8xx_cpufreq_transition
(
struct
notifier_block
*
nb
,
unsigned
long
val
,
void
*
data
)
{
struct
da8xx_fb_par
*
par
;
par
=
container_of
(
nb
,
struct
da8xx_fb_par
,
freq_transition
);
if
(
val
==
CPUFREQ_PRECHANGE
)
{
lcd_disable_raster
();
}
else
if
(
val
==
CPUFREQ_POSTCHANGE
)
{
lcd_calc_clk_divider
(
par
);
lcd_enable_raster
();
}
return
0
;
}
static
inline
int
lcd_da8xx_cpufreq_register
(
struct
da8xx_fb_par
*
par
)
{
par
->
freq_transition
.
notifier_call
=
lcd_da8xx_cpufreq_transition
;
return
cpufreq_register_notifier
(
&
par
->
freq_transition
,
CPUFREQ_TRANSITION_NOTIFIER
);
}
static
inline
void
lcd_da8xx_cpufreq_deregister
(
struct
da8xx_fb_par
*
par
)
{
cpufreq_unregister_notifier
(
&
par
->
freq_transition
,
CPUFREQ_TRANSITION_NOTIFIER
);
}
#endif
static
int
__devexit
fb_remove
(
struct
platform_device
*
dev
)
{
struct
fb_info
*
info
=
dev_get_drvdata
(
&
dev
->
dev
);
...
...
@@ -581,8 +640,13 @@ static int __devexit fb_remove(struct platform_device *dev)
if
(
info
)
{
struct
da8xx_fb_par
*
par
=
info
->
par
;
if
(
lcdc_read
(
LCD_RASTER_CTRL_REG
)
&
LCD_RASTER_ENABLE
)
lcd_disable_raster
(
par
);
#ifdef CONFIG_CPU_FREQ
lcd_da8xx_cpufreq_deregister
(
par
);
#endif
if
(
par
->
panel_power_ctrl
)
par
->
panel_power_ctrl
(
0
);
lcd_disable_raster
();
lcdc_write
(
0
,
LCD_RASTER_CTRL_REG
);
/* disable DMA */
...
...
@@ -639,6 +703,35 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd,
return
0
;
}
static
int
cfb_blank
(
int
blank
,
struct
fb_info
*
info
)
{
struct
da8xx_fb_par
*
par
=
info
->
par
;
int
ret
=
0
;
if
(
par
->
blank
==
blank
)
return
0
;
par
->
blank
=
blank
;
switch
(
blank
)
{
case
FB_BLANK_UNBLANK
:
if
(
par
->
panel_power_ctrl
)
par
->
panel_power_ctrl
(
1
);
lcd_enable_raster
();
break
;
case
FB_BLANK_POWERDOWN
:
if
(
par
->
panel_power_ctrl
)
par
->
panel_power_ctrl
(
0
);
lcd_disable_raster
();
break
;
default:
ret
=
-
EINVAL
;
}
return
ret
;
}
static
struct
fb_ops
da8xx_fb_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_check_var
=
fb_check_var
,
...
...
@@ -647,6 +740,7 @@ static struct fb_ops da8xx_fb_ops = {
.
fb_fillrect
=
cfb_fillrect
,
.
fb_copyarea
=
cfb_copyarea
,
.
fb_imageblit
=
cfb_imageblit
,
.
fb_blank
=
cfb_blank
,
};
static
int
__init
fb_probe
(
struct
platform_device
*
device
)
...
...
@@ -721,6 +815,12 @@ static int __init fb_probe(struct platform_device *device)
}
par
=
da8xx_fb_info
->
par
;
par
->
lcdc_clk
=
fb_clk
;
par
->
pxl_clk
=
lcdc_info
->
pxl_clk
;
if
(
fb_pdata
->
panel_power_ctrl
)
{
par
->
panel_power_ctrl
=
fb_pdata
->
panel_power_ctrl
;
par
->
panel_power_ctrl
(
1
);
}
if
(
lcd_init
(
par
,
lcd_cfg
,
lcdc_info
)
<
0
)
{
dev_err
(
&
device
->
dev
,
"lcd_init failed
\n
"
);
...
...
@@ -754,8 +854,6 @@ static int __init fb_probe(struct platform_device *device)
da8xx_fb_fix
.
smem_len
=
par
->
databuf_sz
-
par
->
palette_sz
;
da8xx_fb_fix
.
line_length
=
(
lcdc_info
->
width
*
lcd_cfg
->
bpp
)
/
8
;
par
->
lcdc_clk
=
fb_clk
;
par
->
irq
=
platform_get_irq
(
device
,
0
);
if
(
par
->
irq
<
0
)
{
ret
=
-
ENOENT
;
...
...
@@ -814,12 +912,24 @@ static int __init fb_probe(struct platform_device *device)
goto
err_dealloc_cmap
;
}
#ifdef CONFIG_CPU_FREQ
ret
=
lcd_da8xx_cpufreq_register
(
par
);
if
(
ret
)
{
dev_err
(
&
device
->
dev
,
"failed to register cpufreq
\n
"
);
goto
err_cpu_freq
;
}
#endif
/* enable raster engine */
lcdc_write
(
lcdc_read
(
LCD_RASTER_CTRL_REG
)
|
LCD_RASTER_ENABLE
,
LCD_RASTER_CTRL_REG
);
lcd_enable_raster
();
return
0
;
#ifdef CONFIG_CPU_FREQ
err_cpu_freq:
unregister_framebuffer
(
da8xx_fb_info
);
#endif
err_dealloc_cmap:
fb_dealloc_cmap
(
&
da8xx_fb_info
->
cmap
);
...
...
@@ -852,11 +962,35 @@ err_request_mem:
#ifdef CONFIG_PM
static
int
fb_suspend
(
struct
platform_device
*
dev
,
pm_message_t
state
)
{
return
-
EBUSY
;
struct
fb_info
*
info
=
platform_get_drvdata
(
dev
);
struct
da8xx_fb_par
*
par
=
info
->
par
;
acquire_console_sem
();
if
(
par
->
panel_power_ctrl
)
par
->
panel_power_ctrl
(
0
);
fb_set_suspend
(
info
,
1
);
lcd_disable_raster
();
clk_disable
(
par
->
lcdc_clk
);
release_console_sem
();
return
0
;
}
static
int
fb_resume
(
struct
platform_device
*
dev
)
{
return
-
EBUSY
;
struct
fb_info
*
info
=
platform_get_drvdata
(
dev
);
struct
da8xx_fb_par
*
par
=
info
->
par
;
acquire_console_sem
();
if
(
par
->
panel_power_ctrl
)
par
->
panel_power_ctrl
(
1
);
clk_enable
(
par
->
lcdc_clk
);
lcd_enable_raster
();
fb_set_suspend
(
info
,
0
);
release_console_sem
();
return
0
;
}
#else
#define fb_suspend NULL
...
...
include/linux/mtd/partitions.h
View file @
395e9801
...
...
@@ -10,6 +10,7 @@
#define MTD_PARTITIONS_H
#include <linux/types.h>
#include <linux/memory.h>
/*
...
...
@@ -40,6 +41,8 @@ struct mtd_partition {
uint64_t
offset
;
/* offset within the master MTD space */
uint32_t
mask_flags
;
/* master MTD flags to mask out for this partition */
struct
nand_ecclayout
*
ecclayout
;
/* out of band layout for this partition (NAND only)*/
void
(
*
setup
)(
struct
memory_accessor
*
,
void
*
context
);
void
*
context
;
};
#define MTDPART_OFS_NXTBLK (-2)
...
...
include/video/da8xx-fb.h
View file @
395e9801
...
...
@@ -38,6 +38,7 @@ struct da8xx_lcdc_platform_data {
const
char
manu_name
[
10
];
void
*
controller_data
;
const
char
type
[
25
];
void
(
*
panel_power_ctrl
)(
int
);
};
struct
lcd_ctrl_config
{
...
...
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