Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
dce7886e
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
dce7886e
编写于
2月 14, 2013
作者:
S
Samuel Ortiz
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-mfd' of
git://git.linaro.org/people/ljones/linux-3.0-ux500
into for-next
Signed-off-by:
N
Samuel Ortiz
<
sameo@linux.intel.com
>
上级
ba3980df
8908c049
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
1394 addition
and
74 deletion
+1394
-74
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-core.c
+2
-0
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-debugfs.c
+1194
-55
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-gpadc.c
+71
-19
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/ab8500-sysctrl.c
+92
-0
drivers/mfd/abx500-core.c
drivers/mfd/abx500-core.c
+16
-0
include/linux/mfd/abx500.h
include/linux/mfd/abx500.h
+2
-0
include/linux/mfd/abx500/ab8500-sysctrl.h
include/linux/mfd/abx500/ab8500-sysctrl.h
+5
-0
include/linux/mfd/abx500/ab8500.h
include/linux/mfd/abx500/ab8500.h
+12
-0
未找到文件。
drivers/mfd/ab8500-core.c
浏览文件 @
dce7886e
...
@@ -320,6 +320,7 @@ static struct abx500_ops ab8500_ops = {
...
@@ -320,6 +320,7 @@ static struct abx500_ops ab8500_ops = {
.
mask_and_set_register
=
ab8500_mask_and_set_register
,
.
mask_and_set_register
=
ab8500_mask_and_set_register
,
.
event_registers_startup_state_get
=
NULL
,
.
event_registers_startup_state_get
=
NULL
,
.
startup_irq_enabled
=
NULL
,
.
startup_irq_enabled
=
NULL
,
.
dump_all_banks
=
ab8500_dump_all_banks
,
};
};
static
void
ab8500_irq_lock
(
struct
irq_data
*
data
)
static
void
ab8500_irq_lock
(
struct
irq_data
*
data
)
...
@@ -521,6 +522,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
...
@@ -521,6 +522,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int
virq
=
ab8500_irq_get_virq
(
ab8500
,
line
);
int
virq
=
ab8500_irq_get_virq
(
ab8500
,
line
);
handle_nested_irq
(
virq
);
handle_nested_irq
(
virq
);
ab8500_debug_register_interrupt
(
line
);
value
&=
~
(
1
<<
bit
);
value
&=
~
(
1
<<
bit
);
}
while
(
value
);
}
while
(
value
);
...
...
drivers/mfd/ab8500-debugfs.c
浏览文件 @
dce7886e
...
@@ -4,6 +4,72 @@
...
@@ -4,6 +4,72 @@
* Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
* Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
* License Terms: GNU General Public License v2
* License Terms: GNU General Public License v2
*/
*/
/*
* AB8500 register access
* ======================
*
* read:
* # echo BANK > <debugfs>/ab8500/register-bank
* # echo ADDR > <debugfs>/ab8500/register-address
* # cat <debugfs>/ab8500/register-value
*
* write:
* # echo BANK > <debugfs>/ab8500/register-bank
* # echo ADDR > <debugfs>/ab8500/register-address
* # echo VALUE > <debugfs>/ab8500/register-value
*
* read all registers from a bank:
* # echo BANK > <debugfs>/ab8500/register-bank
* # cat <debugfs>/ab8500/all-bank-register
*
* BANK target AB8500 register bank
* ADDR target AB8500 register address
* VALUE decimal or 0x-prefixed hexadecimal
*
*
* User Space notification on AB8500 IRQ
* =====================================
*
* Allows user space entity to be notified when target AB8500 IRQ occurs.
* When subscribed, a sysfs entry is created in ab8500.i2c platform device.
* One can pool this file to get target IRQ occurence information.
*
* subscribe to an AB8500 IRQ:
* # echo IRQ > <debugfs>/ab8500/irq-subscribe
*
* unsubscribe from an AB8500 IRQ:
* # echo IRQ > <debugfs>/ab8500/irq-unsubscribe
*
*
* AB8500 register formated read/write access
* ==========================================
*
* Read: read data, data>>SHIFT, data&=MASK, output data
* [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE
* Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data
* [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98]
*
* Usage:
* # echo "CMD [OPTIONS] BANK ADRESS [VALUE]" > $debugfs/ab8500/hwreg
*
* CMD read read access
* write write access
*
* BANK target reg bank
* ADDRESS target reg address
* VALUE (write) value to be updated
*
* OPTIONS
* -d|-dec (read) output in decimal
* -h|-hexa (read) output in 0x-hexa (default)
* -l|-w|-b 32bit (default), 16bit or 8bit reg access
* -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF)
* -s|-shift SHIFT bit shift value (read:left, write:right)
* -o|-offset OFFSET address offset to add to ADDRESS value
*
* Warning: bit shift operation is applied to bit-mask.
* Warning: bit shift direction depends on read or right command.
*/
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/uaccess.h>
...
@@ -11,13 +77,29 @@
...
@@ -11,13 +77,29 @@
#include <linux/module.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/kobject.h>
#include <linux/slab.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-gpadc.h>
#ifdef CONFIG_DEBUG_FS
#include <linux/string.h>
#include <linux/ctype.h>
#endif
static
u32
debug_bank
;
static
u32
debug_bank
;
static
u32
debug_address
;
static
u32
debug_address
;
static
int
irq_first
;
static
int
irq_last
;
static
u32
*
irq_count
;
static
int
num_irqs
;
static
struct
device_attribute
**
dev_attr
;
static
char
**
event_name
;
/**
/**
* struct ab8500_reg_range
* struct ab8500_reg_range
* @first: the first address of the range
* @first: the first address of the range
...
@@ -42,15 +124,35 @@ struct ab8500_prcmu_ranges {
...
@@ -42,15 +124,35 @@ struct ab8500_prcmu_ranges {
const
struct
ab8500_reg_range
*
range
;
const
struct
ab8500_reg_range
*
range
;
};
};
/* hwreg- "mask" and "shift" entries ressources */
struct
hwreg_cfg
{
u32
bank
;
/* target bank */
u32
addr
;
/* target address */
uint
fmt
;
/* format */
uint
mask
;
/* read/write mask, applied before any bit shift */
int
shift
;
/* bit shift (read:right shift, write:left shift */
};
/* fmt bit #0: 0=hexa, 1=dec */
#define REG_FMT_DEC(c) ((c)->fmt & 0x1)
#define REG_FMT_HEX(c) (!REG_FMT_DEC(c))
static
struct
hwreg_cfg
hwreg_cfg
=
{
.
addr
=
0
,
/* default: invalid phys addr */
.
fmt
=
0
,
/* default: 32bit access, hex output */
.
mask
=
0xFFFFFFFF
,
/* default: no mask */
.
shift
=
0
,
/* default: no bit shift */
};
#define AB8500_NAME_STRING "ab8500"
#define AB8500_NAME_STRING "ab8500"
#define AB8500_NUM_BANKS 22
#define AB8500_ADC_NAME_STRING "gpadc"
#define AB8500_NUM_BANKS 24
#define AB8500_REV_REG 0x80
#define AB8500_REV_REG 0x80
static
struct
ab8500_prcmu_ranges
debug_ranges
[
AB8500_NUM_BANKS
]
=
{
static
struct
ab8500_prcmu_ranges
debug_ranges
[
AB8500_NUM_BANKS
]
=
{
[
0x0
]
=
{
[
0x0
]
=
{
.
num_ranges
=
0
,
.
num_ranges
=
0
,
.
range
=
0
,
.
range
=
NULL
,
},
},
[
AB8500_SYS_CTRL1_BLOCK
]
=
{
[
AB8500_SYS_CTRL1_BLOCK
]
=
{
.
num_ranges
=
3
,
.
num_ranges
=
3
,
...
@@ -215,7 +317,7 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
...
@@ -215,7 +317,7 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
},
},
},
[
AB8500_CHARGER
]
=
{
[
AB8500_CHARGER
]
=
{
.
num_ranges
=
8
,
.
num_ranges
=
9
,
.
range
=
(
struct
ab8500_reg_range
[])
{
.
range
=
(
struct
ab8500_reg_range
[])
{
{
{
.
first
=
0x00
,
.
first
=
0x00
,
...
@@ -249,6 +351,10 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
...
@@ -249,6 +351,10 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
.
first
=
0xC0
,
.
first
=
0xC0
,
.
last
=
0xC2
,
.
last
=
0xC2
,
},
},
{
.
first
=
0xf5
,
.
last
=
0xf6
,
},
},
},
},
},
[
AB8500_GAS_GAUGE
]
=
{
[
AB8500_GAS_GAUGE
]
=
{
...
@@ -268,6 +374,24 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
...
@@ -268,6 +374,24 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
},
},
},
},
},
[
AB8500_DEVELOPMENT
]
=
{
.
num_ranges
=
1
,
.
range
=
(
struct
ab8500_reg_range
[])
{
{
.
first
=
0x00
,
.
last
=
0x00
,
},
},
},
[
AB8500_DEBUG
]
=
{
.
num_ranges
=
1
,
.
range
=
(
struct
ab8500_reg_range
[])
{
{
.
first
=
0x05
,
.
last
=
0x07
,
},
},
},
[
AB8500_AUDIO
]
=
{
[
AB8500_AUDIO
]
=
{
.
num_ranges
=
1
,
.
num_ranges
=
1
,
.
range
=
(
struct
ab8500_reg_range
[])
{
.
range
=
(
struct
ab8500_reg_range
[])
{
...
@@ -354,15 +478,30 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
...
@@ -354,15 +478,30 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
},
};
};
static
i
nt
ab8500_registers_print
(
struct
seq_file
*
s
,
void
*
p
)
static
i
rqreturn_t
ab8500_debug_handler
(
int
irq
,
void
*
data
)
{
{
struct
device
*
dev
=
s
->
private
;
char
buf
[
16
]
;
unsigned
int
i
;
struct
kobject
*
kobj
=
(
struct
kobject
*
)
data
;
u
32
bank
=
debug_bank
;
u
nsigned
int
irq_abb
=
irq
-
irq_first
;
seq_printf
(
s
,
AB8500_NAME_STRING
" register values:
\n
"
);
if
(
irq_abb
<
num_irqs
)
irq_count
[
irq_abb
]
++
;
/*
* This makes it possible to use poll for events (POLLPRI | POLLERR)
* from userspace on sysfs file named <irq-nr>
*/
sprintf
(
buf
,
"%d"
,
irq
);
sysfs_notify
(
kobj
,
NULL
,
buf
);
return
IRQ_HANDLED
;
}
/* Prints to seq_file or log_buf */
static
int
ab8500_registers_print
(
struct
device
*
dev
,
u32
bank
,
struct
seq_file
*
s
)
{
unsigned
int
i
;
seq_printf
(
s
,
" bank %u:
\n
"
,
bank
);
for
(
i
=
0
;
i
<
debug_ranges
[
bank
].
num_ranges
;
i
++
)
{
for
(
i
=
0
;
i
<
debug_ranges
[
bank
].
num_ranges
;
i
++
)
{
u32
reg
;
u32
reg
;
...
@@ -379,22 +518,42 @@ static int ab8500_registers_print(struct seq_file *s, void *p)
...
@@ -379,22 +518,42 @@ static int ab8500_registers_print(struct seq_file *s, void *p)
return
err
;
return
err
;
}
}
err
=
seq_printf
(
s
,
" [%u/0x%02X]: 0x%02X
\n
"
,
bank
,
if
(
s
)
{
reg
,
value
);
err
=
seq_printf
(
s
,
" [%u/0x%02X]: 0x%02X
\n
"
,
if
(
err
<
0
)
{
bank
,
reg
,
value
);
dev_err
(
dev
,
"seq_printf overflow
\n
"
);
if
(
err
<
0
)
{
/* Error is not returned here since
dev_err
(
dev
,
* the output is wanted in any case */
"seq_printf overflow bank=%d reg=%d
\n
"
,
return
0
;
bank
,
reg
);
/* Error is not returned here since
* the output is wanted in any case */
return
0
;
}
}
else
{
printk
(
KERN_INFO
" [%u/0x%02X]: 0x%02X
\n
"
,
bank
,
reg
,
value
);
}
}
}
}
}
}
return
0
;
return
0
;
}
}
static
int
ab8500_print_bank_registers
(
struct
seq_file
*
s
,
void
*
p
)
{
struct
device
*
dev
=
s
->
private
;
u32
bank
=
debug_bank
;
seq_printf
(
s
,
AB8500_NAME_STRING
" register values:
\n
"
);
seq_printf
(
s
,
" bank %u:
\n
"
,
bank
);
ab8500_registers_print
(
dev
,
bank
,
s
);
return
0
;
}
static
int
ab8500_registers_open
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
ab8500_registers_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
return
single_open
(
file
,
ab8500_
registers_print
,
inode
->
i_private
);
return
single_open
(
file
,
ab8500_
print_bank_registers
,
inode
->
i_private
);
}
}
static
const
struct
file_operations
ab8500_registers_fops
=
{
static
const
struct
file_operations
ab8500_registers_fops
=
{
...
@@ -405,6 +564,64 @@ static const struct file_operations ab8500_registers_fops = {
...
@@ -405,6 +564,64 @@ static const struct file_operations ab8500_registers_fops = {
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
};
};
static
int
ab8500_print_all_banks
(
struct
seq_file
*
s
,
void
*
p
)
{
struct
device
*
dev
=
s
->
private
;
unsigned
int
i
;
int
err
;
seq_printf
(
s
,
AB8500_NAME_STRING
" register values:
\n
"
);
for
(
i
=
1
;
i
<
AB8500_NUM_BANKS
;
i
++
)
{
err
=
seq_printf
(
s
,
" bank %u:
\n
"
,
i
);
if
(
err
<
0
)
dev_err
(
dev
,
"seq_printf overflow, bank=%d
\n
"
,
i
);
ab8500_registers_print
(
dev
,
i
,
s
);
}
return
0
;
}
/* Dump registers to kernel log */
void
ab8500_dump_all_banks
(
struct
device
*
dev
)
{
unsigned
int
i
;
printk
(
KERN_INFO
"ab8500 register values:
\n
"
);
for
(
i
=
1
;
i
<
AB8500_NUM_BANKS
;
i
++
)
{
printk
(
KERN_INFO
" bank %u:
\n
"
,
i
);
ab8500_registers_print
(
dev
,
i
,
NULL
);
}
}
static
int
ab8500_all_banks_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
seq_file
*
s
;
int
err
;
err
=
single_open
(
file
,
ab8500_print_all_banks
,
inode
->
i_private
);
if
(
!
err
)
{
/* Default buf size in seq_read is not enough */
s
=
(
struct
seq_file
*
)
file
->
private_data
;
s
->
size
=
(
PAGE_SIZE
*
2
);
s
->
buf
=
kmalloc
(
s
->
size
,
GFP_KERNEL
);
if
(
!
s
->
buf
)
{
single_release
(
inode
,
file
);
err
=
-
ENOMEM
;
}
}
return
err
;
}
static
const
struct
file_operations
ab8500_all_banks_fops
=
{
.
open
=
ab8500_all_banks_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_bank_print
(
struct
seq_file
*
s
,
void
*
p
)
static
int
ab8500_bank_print
(
struct
seq_file
*
s
,
void
*
p
)
{
{
return
seq_printf
(
s
,
"%d
\n
"
,
debug_bank
);
return
seq_printf
(
s
,
"%d
\n
"
,
debug_bank
);
...
@@ -519,6 +736,761 @@ static ssize_t ab8500_val_write(struct file *file,
...
@@ -519,6 +736,761 @@ static ssize_t ab8500_val_write(struct file *file,
return
count
;
return
count
;
}
}
/*
* Interrupt status
*/
static
u32
num_interrupts
[
AB8500_MAX_NR_IRQS
];
static
int
num_interrupt_lines
;
void
ab8500_debug_register_interrupt
(
int
line
)
{
if
(
line
<
num_interrupt_lines
)
num_interrupts
[
line
]
++
;
}
static
int
ab8500_interrupts_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
line
;
seq_printf
(
s
,
"irq: number of
\n
"
);
for
(
line
=
0
;
line
<
num_interrupt_lines
;
line
++
)
seq_printf
(
s
,
"%3i: %6i
\n
"
,
line
,
num_interrupts
[
line
]);
return
0
;
}
static
int
ab8500_interrupts_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_interrupts_print
,
inode
->
i_private
);
}
/*
* - HWREG DB8500 formated routines
*/
static
int
ab8500_hwreg_print
(
struct
seq_file
*
s
,
void
*
d
)
{
struct
device
*
dev
=
s
->
private
;
int
ret
;
u8
regvalue
;
ret
=
abx500_get_register_interruptible
(
dev
,
(
u8
)
hwreg_cfg
.
bank
,
(
u8
)
hwreg_cfg
.
addr
,
&
regvalue
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"abx500_get_reg fail %d, %d
\n
"
,
ret
,
__LINE__
);
return
-
EINVAL
;
}
if
(
hwreg_cfg
.
shift
>=
0
)
regvalue
>>=
hwreg_cfg
.
shift
;
else
regvalue
<<=
-
hwreg_cfg
.
shift
;
regvalue
&=
hwreg_cfg
.
mask
;
if
(
REG_FMT_DEC
(
&
hwreg_cfg
))
seq_printf
(
s
,
"%d
\n
"
,
regvalue
);
else
seq_printf
(
s
,
"0x%02X
\n
"
,
regvalue
);
return
0
;
}
static
int
ab8500_hwreg_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_hwreg_print
,
inode
->
i_private
);
}
static
int
ab8500_gpadc_bat_ctrl_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
bat_ctrl_raw
;
int
bat_ctrl_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
bat_ctrl_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
BAT_CTRL
);
bat_ctrl_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
BAT_CTRL
,
bat_ctrl_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
bat_ctrl_convert
,
bat_ctrl_raw
);
}
static
int
ab8500_gpadc_bat_ctrl_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_bat_ctrl_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_bat_ctrl_fops
=
{
.
open
=
ab8500_gpadc_bat_ctrl_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_btemp_ball_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
btemp_ball_raw
;
int
btemp_ball_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
btemp_ball_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
BTEMP_BALL
);
btemp_ball_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
BTEMP_BALL
,
btemp_ball_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
btemp_ball_convert
,
btemp_ball_raw
);
}
static
int
ab8500_gpadc_btemp_ball_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_btemp_ball_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_btemp_ball_fops
=
{
.
open
=
ab8500_gpadc_btemp_ball_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_main_charger_v_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
main_charger_v_raw
;
int
main_charger_v_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
main_charger_v_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
MAIN_CHARGER_V
);
main_charger_v_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
MAIN_CHARGER_V
,
main_charger_v_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
main_charger_v_convert
,
main_charger_v_raw
);
}
static
int
ab8500_gpadc_main_charger_v_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_main_charger_v_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_main_charger_v_fops
=
{
.
open
=
ab8500_gpadc_main_charger_v_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_acc_detect1_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
acc_detect1_raw
;
int
acc_detect1_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
acc_detect1_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
ACC_DETECT1
);
acc_detect1_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
ACC_DETECT1
,
acc_detect1_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
acc_detect1_convert
,
acc_detect1_raw
);
}
static
int
ab8500_gpadc_acc_detect1_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_acc_detect1_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_acc_detect1_fops
=
{
.
open
=
ab8500_gpadc_acc_detect1_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_acc_detect2_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
acc_detect2_raw
;
int
acc_detect2_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
acc_detect2_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
ACC_DETECT2
);
acc_detect2_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
ACC_DETECT2
,
acc_detect2_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
acc_detect2_convert
,
acc_detect2_raw
);
}
static
int
ab8500_gpadc_acc_detect2_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_acc_detect2_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_acc_detect2_fops
=
{
.
open
=
ab8500_gpadc_acc_detect2_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_aux1_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
aux1_raw
;
int
aux1_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
aux1_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
ADC_AUX1
);
aux1_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
ADC_AUX1
,
aux1_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
aux1_convert
,
aux1_raw
);
}
static
int
ab8500_gpadc_aux1_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_aux1_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_aux1_fops
=
{
.
open
=
ab8500_gpadc_aux1_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_aux2_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
aux2_raw
;
int
aux2_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
aux2_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
ADC_AUX2
);
aux2_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
ADC_AUX2
,
aux2_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
aux2_convert
,
aux2_raw
);
}
static
int
ab8500_gpadc_aux2_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_aux2_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_aux2_fops
=
{
.
open
=
ab8500_gpadc_aux2_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_main_bat_v_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
main_bat_v_raw
;
int
main_bat_v_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
main_bat_v_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
MAIN_BAT_V
);
main_bat_v_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
MAIN_BAT_V
,
main_bat_v_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
main_bat_v_convert
,
main_bat_v_raw
);
}
static
int
ab8500_gpadc_main_bat_v_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_main_bat_v_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_main_bat_v_fops
=
{
.
open
=
ab8500_gpadc_main_bat_v_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_vbus_v_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
vbus_v_raw
;
int
vbus_v_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
vbus_v_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
VBUS_V
);
vbus_v_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
VBUS_V
,
vbus_v_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
vbus_v_convert
,
vbus_v_raw
);
}
static
int
ab8500_gpadc_vbus_v_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_vbus_v_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_vbus_v_fops
=
{
.
open
=
ab8500_gpadc_vbus_v_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_main_charger_c_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
main_charger_c_raw
;
int
main_charger_c_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
main_charger_c_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
MAIN_CHARGER_C
);
main_charger_c_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
MAIN_CHARGER_C
,
main_charger_c_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
main_charger_c_convert
,
main_charger_c_raw
);
}
static
int
ab8500_gpadc_main_charger_c_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_main_charger_c_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_main_charger_c_fops
=
{
.
open
=
ab8500_gpadc_main_charger_c_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_usb_charger_c_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
usb_charger_c_raw
;
int
usb_charger_c_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
usb_charger_c_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
USB_CHARGER_C
);
usb_charger_c_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
USB_CHARGER_C
,
usb_charger_c_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
usb_charger_c_convert
,
usb_charger_c_raw
);
}
static
int
ab8500_gpadc_usb_charger_c_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_usb_charger_c_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_usb_charger_c_fops
=
{
.
open
=
ab8500_gpadc_usb_charger_c_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_bk_bat_v_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
bk_bat_v_raw
;
int
bk_bat_v_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
bk_bat_v_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
BK_BAT_V
);
bk_bat_v_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
BK_BAT_V
,
bk_bat_v_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
bk_bat_v_convert
,
bk_bat_v_raw
);
}
static
int
ab8500_gpadc_bk_bat_v_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_bk_bat_v_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_bk_bat_v_fops
=
{
.
open
=
ab8500_gpadc_bk_bat_v_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
int
ab8500_gpadc_die_temp_print
(
struct
seq_file
*
s
,
void
*
p
)
{
int
die_temp_raw
;
int
die_temp_convert
;
struct
ab8500_gpadc
*
gpadc
;
gpadc
=
ab8500_gpadc_get
(
"ab8500-gpadc.0"
);
die_temp_raw
=
ab8500_gpadc_read_raw
(
gpadc
,
DIE_TEMP
);
die_temp_convert
=
ab8500_gpadc_ad_to_voltage
(
gpadc
,
DIE_TEMP
,
die_temp_raw
);
return
seq_printf
(
s
,
"%d,0x%X
\n
"
,
die_temp_convert
,
die_temp_raw
);
}
static
int
ab8500_gpadc_die_temp_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_gpadc_die_temp_print
,
inode
->
i_private
);
}
static
const
struct
file_operations
ab8500_gpadc_die_temp_fops
=
{
.
open
=
ab8500_gpadc_die_temp_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
/*
* return length of an ASCII numerical value, 0 is string is not a
* numerical value.
* string shall start at value 1st char.
* string can be tailed with \0 or space or newline chars only.
* value can be decimal or hexadecimal (prefixed 0x or 0X).
*/
static
int
strval_len
(
char
*
b
)
{
char
*
s
=
b
;
if
((
*
s
==
'0'
)
&&
((
*
(
s
+
1
)
==
'x'
)
||
(
*
(
s
+
1
)
==
'X'
)))
{
s
+=
2
;
for
(;
*
s
&&
(
*
s
!=
' '
)
&&
(
*
s
!=
'\n'
);
s
++
)
{
if
(
!
isxdigit
(
*
s
))
return
0
;
}
}
else
{
if
(
*
s
==
'-'
)
s
++
;
for
(;
*
s
&&
(
*
s
!=
' '
)
&&
(
*
s
!=
'\n'
);
s
++
)
{
if
(
!
isdigit
(
*
s
))
return
0
;
}
}
return
(
int
)
(
s
-
b
);
}
/*
* parse hwreg input data.
* update global hwreg_cfg only if input data syntax is ok.
*/
static
ssize_t
hwreg_common_write
(
char
*
b
,
struct
hwreg_cfg
*
cfg
,
struct
device
*
dev
)
{
uint
write
,
val
=
0
;
u8
regvalue
;
int
ret
;
struct
hwreg_cfg
loc
=
{
.
bank
=
0
,
/* default: invalid phys addr */
.
addr
=
0
,
/* default: invalid phys addr */
.
fmt
=
0
,
/* default: 32bit access, hex output */
.
mask
=
0xFFFFFFFF
,
/* default: no mask */
.
shift
=
0
,
/* default: no bit shift */
};
/* read or write ? */
if
(
!
strncmp
(
b
,
"read "
,
5
))
{
write
=
0
;
b
+=
5
;
}
else
if
(
!
strncmp
(
b
,
"write "
,
6
))
{
write
=
1
;
b
+=
6
;
}
else
return
-
EINVAL
;
/* OPTIONS -l|-w|-b -s -m -o */
while
((
*
b
==
' '
)
||
(
*
b
==
'-'
))
{
if
(
*
(
b
-
1
)
!=
' '
)
{
b
++
;
continue
;
}
if
((
!
strncmp
(
b
,
"-d "
,
3
))
||
(
!
strncmp
(
b
,
"-dec "
,
5
)))
{
b
+=
(
*
(
b
+
2
)
==
' '
)
?
3
:
5
;
loc
.
fmt
|=
(
1
<<
0
);
}
else
if
((
!
strncmp
(
b
,
"-h "
,
3
))
||
(
!
strncmp
(
b
,
"-hex "
,
5
)))
{
b
+=
(
*
(
b
+
2
)
==
' '
)
?
3
:
5
;
loc
.
fmt
&=
~
(
1
<<
0
);
}
else
if
((
!
strncmp
(
b
,
"-m "
,
3
))
||
(
!
strncmp
(
b
,
"-mask "
,
6
)))
{
b
+=
(
*
(
b
+
2
)
==
' '
)
?
3
:
6
;
if
(
strval_len
(
b
)
==
0
)
return
-
EINVAL
;
loc
.
mask
=
simple_strtoul
(
b
,
&
b
,
0
);
}
else
if
((
!
strncmp
(
b
,
"-s "
,
3
))
||
(
!
strncmp
(
b
,
"-shift "
,
7
)))
{
b
+=
(
*
(
b
+
2
)
==
' '
)
?
3
:
7
;
if
(
strval_len
(
b
)
==
0
)
return
-
EINVAL
;
loc
.
shift
=
simple_strtol
(
b
,
&
b
,
0
);
}
else
{
return
-
EINVAL
;
}
}
/* get arg BANK and ADDRESS */
if
(
strval_len
(
b
)
==
0
)
return
-
EINVAL
;
loc
.
bank
=
simple_strtoul
(
b
,
&
b
,
0
);
while
(
*
b
==
' '
)
b
++
;
if
(
strval_len
(
b
)
==
0
)
return
-
EINVAL
;
loc
.
addr
=
simple_strtoul
(
b
,
&
b
,
0
);
if
(
write
)
{
while
(
*
b
==
' '
)
b
++
;
if
(
strval_len
(
b
)
==
0
)
return
-
EINVAL
;
val
=
simple_strtoul
(
b
,
&
b
,
0
);
}
/* args are ok, update target cfg (mainly for read) */
*
cfg
=
loc
;
#ifdef ABB_HWREG_DEBUG
pr_warn
(
"HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d"
"value=0x%X
\n
"
,
(
write
)
?
"write"
:
"read"
,
REG_FMT_DEC
(
cfg
)
?
"decimal"
:
"hexa"
,
cfg
->
addr
,
cfg
->
mask
,
cfg
->
shift
,
val
);
#endif
if
(
!
write
)
return
0
;
ret
=
abx500_get_register_interruptible
(
dev
,
(
u8
)
cfg
->
bank
,
(
u8
)
cfg
->
addr
,
&
regvalue
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"abx500_get_reg fail %d, %d
\n
"
,
ret
,
__LINE__
);
return
-
EINVAL
;
}
if
(
cfg
->
shift
>=
0
)
{
regvalue
&=
~
(
cfg
->
mask
<<
(
cfg
->
shift
));
val
=
(
val
&
cfg
->
mask
)
<<
(
cfg
->
shift
);
}
else
{
regvalue
&=
~
(
cfg
->
mask
>>
(
-
cfg
->
shift
));
val
=
(
val
&
cfg
->
mask
)
>>
(
-
cfg
->
shift
);
}
val
=
val
|
regvalue
;
ret
=
abx500_set_register_interruptible
(
dev
,
(
u8
)
cfg
->
bank
,
(
u8
)
cfg
->
addr
,
(
u8
)
val
);
if
(
ret
<
0
)
{
pr_err
(
"abx500_set_reg failed %d, %d"
,
ret
,
__LINE__
);
return
-
EINVAL
;
}
return
0
;
}
static
ssize_t
ab8500_hwreg_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
device
*
dev
=
((
struct
seq_file
*
)(
file
->
private_data
))
->
private
;
char
buf
[
128
];
int
buf_size
,
ret
;
/* Get userspace string and assure termination */
buf_size
=
min
(
count
,
(
sizeof
(
buf
)
-
1
));
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
buf
[
buf_size
]
=
0
;
/* get args and process */
ret
=
hwreg_common_write
(
buf
,
&
hwreg_cfg
,
dev
);
return
(
ret
)
?
ret
:
buf_size
;
}
/*
* - irq subscribe/unsubscribe stuff
*/
static
int
ab8500_subscribe_unsubscribe_print
(
struct
seq_file
*
s
,
void
*
p
)
{
seq_printf
(
s
,
"%d
\n
"
,
irq_first
);
return
0
;
}
static
int
ab8500_subscribe_unsubscribe_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
ab8500_subscribe_unsubscribe_print
,
inode
->
i_private
);
}
/*
* Userspace should use poll() on this file. When an event occur
* the blocking poll will be released.
*/
static
ssize_t
show_irq
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
unsigned
long
name
;
unsigned
int
irq_index
;
int
err
;
err
=
strict_strtoul
(
attr
->
attr
.
name
,
0
,
&
name
);
if
(
err
)
return
err
;
irq_index
=
name
-
irq_first
;
if
(
irq_index
>=
num_irqs
)
return
-
EINVAL
;
else
return
sprintf
(
buf
,
"%u
\n
"
,
irq_count
[
irq_index
]);
}
static
ssize_t
ab8500_subscribe_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
device
*
dev
=
((
struct
seq_file
*
)(
file
->
private_data
))
->
private
;
char
buf
[
32
];
int
buf_size
;
unsigned
long
user_val
;
int
err
;
unsigned
int
irq_index
;
/* Get userspace string and assure termination */
buf_size
=
min
(
count
,
(
sizeof
(
buf
)
-
1
));
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
buf
[
buf_size
]
=
0
;
err
=
strict_strtoul
(
buf
,
0
,
&
user_val
);
if
(
err
)
return
-
EINVAL
;
if
(
user_val
<
irq_first
)
{
dev_err
(
dev
,
"debugfs error input < %d
\n
"
,
irq_first
);
return
-
EINVAL
;
}
if
(
user_val
>
irq_last
)
{
dev_err
(
dev
,
"debugfs error input > %d
\n
"
,
irq_last
);
return
-
EINVAL
;
}
irq_index
=
user_val
-
irq_first
;
if
(
irq_index
>=
num_irqs
)
return
-
EINVAL
;
/*
* This will create a sysfs file named <irq-nr> which userspace can
* use to select or poll and get the AB8500 events
*/
dev_attr
[
irq_index
]
=
kmalloc
(
sizeof
(
struct
device_attribute
),
GFP_KERNEL
);
event_name
[
irq_index
]
=
kmalloc
(
buf_size
,
GFP_KERNEL
);
sprintf
(
event_name
[
irq_index
],
"%lu"
,
user_val
);
dev_attr
[
irq_index
]
->
show
=
show_irq
;
dev_attr
[
irq_index
]
->
store
=
NULL
;
dev_attr
[
irq_index
]
->
attr
.
name
=
event_name
[
irq_index
];
dev_attr
[
irq_index
]
->
attr
.
mode
=
S_IRUGO
;
err
=
sysfs_create_file
(
&
dev
->
kobj
,
&
dev_attr
[
irq_index
]
->
attr
);
if
(
err
<
0
)
{
printk
(
KERN_ERR
"sysfs_create_file failed %d
\n
"
,
err
);
return
err
;
}
err
=
request_threaded_irq
(
user_val
,
NULL
,
ab8500_debug_handler
,
IRQF_SHARED
|
IRQF_NO_SUSPEND
,
"ab8500-debug"
,
&
dev
->
kobj
);
if
(
err
<
0
)
{
printk
(
KERN_ERR
"request_threaded_irq failed %d, %lu
\n
"
,
err
,
user_val
);
sysfs_remove_file
(
&
dev
->
kobj
,
&
dev_attr
[
irq_index
]
->
attr
);
return
err
;
}
return
buf_size
;
}
static
ssize_t
ab8500_unsubscribe_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
device
*
dev
=
((
struct
seq_file
*
)(
file
->
private_data
))
->
private
;
char
buf
[
32
];
int
buf_size
;
unsigned
long
user_val
;
int
err
;
unsigned
int
irq_index
;
/* Get userspace string and assure termination */
buf_size
=
min
(
count
,
(
sizeof
(
buf
)
-
1
));
if
(
copy_from_user
(
buf
,
user_buf
,
buf_size
))
return
-
EFAULT
;
buf
[
buf_size
]
=
0
;
err
=
strict_strtoul
(
buf
,
0
,
&
user_val
);
if
(
err
)
return
-
EINVAL
;
if
(
user_val
<
irq_first
)
{
dev_err
(
dev
,
"debugfs error input < %d
\n
"
,
irq_first
);
return
-
EINVAL
;
}
if
(
user_val
>
irq_last
)
{
dev_err
(
dev
,
"debugfs error input > %d
\n
"
,
irq_last
);
return
-
EINVAL
;
}
irq_index
=
user_val
-
irq_first
;
if
(
irq_index
>=
num_irqs
)
return
-
EINVAL
;
/* Set irq count to 0 when unsubscribe */
irq_count
[
irq_index
]
=
0
;
if
(
dev_attr
[
irq_index
])
sysfs_remove_file
(
&
dev
->
kobj
,
&
dev_attr
[
irq_index
]
->
attr
);
free_irq
(
user_val
,
&
dev
->
kobj
);
kfree
(
event_name
[
irq_index
]);
kfree
(
dev_attr
[
irq_index
]);
return
buf_size
;
}
/*
* - several deubgfs nodes fops
*/
static
const
struct
file_operations
ab8500_bank_fops
=
{
static
const
struct
file_operations
ab8500_bank_fops
=
{
.
open
=
ab8500_bank_open
,
.
open
=
ab8500_bank_open
,
.
write
=
ab8500_bank_write
,
.
write
=
ab8500_bank_write
,
...
@@ -546,64 +1518,231 @@ static const struct file_operations ab8500_val_fops = {
...
@@ -546,64 +1518,231 @@ static const struct file_operations ab8500_val_fops = {
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
};
};
static
const
struct
file_operations
ab8500_interrupts_fops
=
{
.
open
=
ab8500_interrupts_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
const
struct
file_operations
ab8500_subscribe_fops
=
{
.
open
=
ab8500_subscribe_unsubscribe_open
,
.
write
=
ab8500_subscribe_write
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
const
struct
file_operations
ab8500_unsubscribe_fops
=
{
.
open
=
ab8500_subscribe_unsubscribe_open
,
.
write
=
ab8500_unsubscribe_write
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
const
struct
file_operations
ab8500_hwreg_fops
=
{
.
open
=
ab8500_hwreg_open
,
.
write
=
ab8500_hwreg_write
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
};
static
struct
dentry
*
ab8500_dir
;
static
struct
dentry
*
ab8500_dir
;
static
struct
dentry
*
ab8500_reg_file
;
static
struct
dentry
*
ab8500_gpadc_dir
;
static
struct
dentry
*
ab8500_bank_file
;
static
struct
dentry
*
ab8500_address_file
;
static
struct
dentry
*
ab8500_val_file
;
static
int
ab8500_debug_probe
(
struct
platform_device
*
plf
)
static
int
ab8500_debug_probe
(
struct
platform_device
*
plf
)
{
{
struct
dentry
*
file
;
int
ret
=
-
ENOMEM
;
struct
ab8500
*
ab8500
;
debug_bank
=
AB8500_MISC
;
debug_bank
=
AB8500_MISC
;
debug_address
=
AB8500_REV_REG
&
0x00FF
;
debug_address
=
AB8500_REV_REG
&
0x00FF
;
ab8500
=
dev_get_drvdata
(
plf
->
dev
.
parent
);
num_irqs
=
ab8500
->
mask_size
;
irq_count
=
kzalloc
(
sizeof
(
*
irq_count
)
*
num_irqs
,
GFP_KERNEL
);
if
(
!
irq_count
)
return
-
ENOMEM
;
dev_attr
=
kzalloc
(
sizeof
(
*
dev_attr
)
*
num_irqs
,
GFP_KERNEL
);
if
(
!
dev_attr
)
goto
out_freeirq_count
;
event_name
=
kzalloc
(
sizeof
(
*
event_name
)
*
num_irqs
,
GFP_KERNEL
);
if
(
!
event_name
)
goto
out_freedev_attr
;
irq_first
=
platform_get_irq_byname
(
plf
,
"IRQ_FIRST"
);
if
(
irq_first
<
0
)
{
dev_err
(
&
plf
->
dev
,
"First irq not found, err %d
\n
"
,
irq_first
);
ret
=
irq_first
;
goto
out_freeevent_name
;
}
irq_last
=
platform_get_irq_byname
(
plf
,
"IRQ_LAST"
);
if
(
irq_last
<
0
)
{
dev_err
(
&
plf
->
dev
,
"Last irq not found, err %d
\n
"
,
irq_last
);
ret
=
irq_last
;
goto
out_freeevent_name
;
}
ab8500_dir
=
debugfs_create_dir
(
AB8500_NAME_STRING
,
NULL
);
ab8500_dir
=
debugfs_create_dir
(
AB8500_NAME_STRING
,
NULL
);
if
(
!
ab8500_dir
)
if
(
!
ab8500_dir
)
goto
exit_no_debugfs
;
goto
err
;
ab8500_gpadc_dir
=
debugfs_create_dir
(
AB8500_ADC_NAME_STRING
,
ab8500_dir
);
if
(
!
ab8500_gpadc_dir
)
goto
err
;
file
=
debugfs_create_file
(
"all-bank-registers"
,
S_IRUGO
,
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_registers_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"all-banks"
,
S_IRUGO
,
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_all_banks_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"register-bank"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_bank_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"register-address"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_address_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"register-value"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_val_fops
);
if
(
!
file
)
goto
err
;
ab8500_reg_file
=
debugfs_create_file
(
"all-bank-registers"
,
file
=
debugfs_create_file
(
"irq-subscribe"
,
(
S_IRUGO
|
S_IWUSR
)
,
S_IRUGO
,
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_registers
_fops
);
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_subscribe
_fops
);
if
(
!
ab8500_reg_
file
)
if
(
!
file
)
goto
e
xit_destroy_di
r
;
goto
e
r
r
;
ab8500_bank_file
=
debugfs_create_file
(
"register-bank"
,
if
(
is_ab8500
(
ab8500
))
(
S_IRUGO
|
S_IWUSR
),
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_bank_fops
);
num_interrupt_lines
=
AB8500_NR_IRQS
;
if
(
!
ab8500_bank_file
)
else
if
(
is_ab8505
(
ab8500
))
goto
exit_destroy_reg
;
num_interrupt_lines
=
AB8505_NR_IRQS
;
else
if
(
is_ab9540
(
ab8500
))
num_interrupt_lines
=
AB9540_NR_IRQS
;
ab8500_address_file
=
debugfs_create_file
(
"register-address"
,
file
=
debugfs_create_file
(
"interrupts"
,
(
S_IRUGO
),
(
S_IRUGO
|
S_IWUSR
),
ab8500_dir
,
&
plf
->
dev
,
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_interrupts_fops
);
&
ab8500_address_fops
);
if
(
!
file
)
if
(
!
ab8500_address_file
)
goto
err
;
goto
exit_destroy_bank
;
ab8500_val_file
=
debugfs_create_file
(
"register-value"
,
file
=
debugfs_create_file
(
"irq-unsubscribe"
,
(
S_IRUGO
|
S_IWUSR
),
(
S_IRUGO
|
S_IWUSR
),
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_val_fops
);
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_unsubscribe_fops
);
if
(
!
ab8500_val_file
)
if
(
!
file
)
goto
exit_destroy_address
;
goto
err
;
file
=
debugfs_create_file
(
"hwreg"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_dir
,
&
plf
->
dev
,
&
ab8500_hwreg_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"bat_ctrl"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_bat_ctrl_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"btemp_ball"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_btemp_ball_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"main_charger_v"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_main_charger_v_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"acc_detect1"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_acc_detect1_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"acc_detect2"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_acc_detect2_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"adc_aux1"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_aux1_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"adc_aux2"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_aux2_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"main_bat_v"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_main_bat_v_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"vbus_v"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_vbus_v_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"main_charger_c"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_main_charger_c_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"usb_charger_c"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_usb_charger_c_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"bk_bat_v"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_bk_bat_v_fops
);
if
(
!
file
)
goto
err
;
file
=
debugfs_create_file
(
"die_temp"
,
(
S_IRUGO
|
S_IWUSR
),
ab8500_gpadc_dir
,
&
plf
->
dev
,
&
ab8500_gpadc_die_temp_fops
);
if
(
!
file
)
goto
err
;
return
0
;
return
0
;
exit_destroy_address:
err:
debugfs_remove
(
ab8500_address_file
);
if
(
ab8500_dir
)
exit_destroy_bank:
debugfs_remove_recursive
(
ab8500_dir
);
debugfs_remove
(
ab8500_bank_file
);
exit_destroy_reg:
debugfs_remove
(
ab8500_reg_file
);
exit_destroy_dir:
debugfs_remove
(
ab8500_dir
);
exit_no_debugfs:
dev_err
(
&
plf
->
dev
,
"failed to create debugfs entries.
\n
"
);
dev_err
(
&
plf
->
dev
,
"failed to create debugfs entries.
\n
"
);
return
-
ENOMEM
;
out_freeevent_name:
kfree
(
event_name
);
out_freedev_attr:
kfree
(
dev_attr
);
out_freeirq_count:
kfree
(
irq_count
);
return
ret
;
}
}
static
int
ab8500_debug_remove
(
struct
platform_device
*
plf
)
static
int
ab8500_debug_remove
(
struct
platform_device
*
plf
)
{
{
debugfs_remove
(
ab8500_val_file
);
debugfs_remove_recursive
(
ab8500_dir
);
debugfs_remove
(
ab8500_address_file
);
kfree
(
event_name
);
debugfs_remove
(
ab8500_bank_file
);
kfree
(
dev_attr
);
debugfs_remove
(
ab8500_reg_file
);
kfree
(
irq_count
);
debugfs_remove
(
ab8500_dir
);
return
0
;
return
0
;
}
}
...
...
drivers/mfd/ab8500-gpadc.c
浏览文件 @
dce7886e
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/consumer.h>
...
@@ -82,6 +83,11 @@
...
@@ -82,6 +83,11 @@
/* This is used to not lose precision when dividing to get gain and offset */
/* This is used to not lose precision when dividing to get gain and offset */
#define CALIB_SCALE 1000
#define CALIB_SCALE 1000
/* Time in ms before disabling regulator */
#define GPADC_AUDOSUSPEND_DELAY 1
#define CONVERSION_TIME 500
/* ms */
enum
cal_channels
{
enum
cal_channels
{
ADC_INPUT_VMAIN
=
0
,
ADC_INPUT_VMAIN
=
0
,
ADC_INPUT_BTEMP
,
ADC_INPUT_BTEMP
,
...
@@ -102,10 +108,10 @@ struct adc_cal_data {
...
@@ -102,10 +108,10 @@ struct adc_cal_data {
/**
/**
* struct ab8500_gpadc - AB8500 GPADC device information
* struct ab8500_gpadc - AB8500 GPADC device information
* @chip_id ABB chip id
* @dev: pointer to the struct device
* @dev: pointer to the struct device
* @node: a list of AB8500 GPADCs, hence prepared for
* @node: a list of AB8500 GPADCs, hence prepared for
reentrance
reentrance
* @parent: pointer to the struct ab8500
* @ab8500_gpadc_complete: pointer to the struct completion, to indicate
* @ab8500_gpadc_complete: pointer to the struct completion, to indicate
* the completion of gpadc conversion
* the completion of gpadc conversion
* @ab8500_gpadc_lock: structure of type mutex
* @ab8500_gpadc_lock: structure of type mutex
...
@@ -114,9 +120,9 @@ struct adc_cal_data {
...
@@ -114,9 +120,9 @@ struct adc_cal_data {
* @cal_data array of ADC calibration data structs
* @cal_data array of ADC calibration data structs
*/
*/
struct
ab8500_gpadc
{
struct
ab8500_gpadc
{
u8
chip_id
;
struct
device
*
dev
;
struct
device
*
dev
;
struct
list_head
node
;
struct
list_head
node
;
struct
ab8500
*
parent
;
struct
completion
ab8500_gpadc_complete
;
struct
completion
ab8500_gpadc_complete
;
struct
mutex
ab8500_gpadc_lock
;
struct
mutex
ab8500_gpadc_lock
;
struct
regulator
*
regu
;
struct
regulator
*
regu
;
...
@@ -282,8 +288,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
...
@@ -282,8 +288,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
return
-
ENODEV
;
return
-
ENODEV
;
mutex_lock
(
&
gpadc
->
ab8500_gpadc_lock
);
mutex_lock
(
&
gpadc
->
ab8500_gpadc_lock
);
/* Enable VTVout LDO this is required for GPADC */
/* Enable VTVout LDO this is required for GPADC */
regulator_enable
(
gpadc
->
regu
);
pm_runtime_get_sync
(
gpadc
->
dev
);
/* Check if ADC is not busy, lock and proceed */
/* Check if ADC is not busy, lock and proceed */
do
{
do
{
...
@@ -332,7 +339,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
...
@@ -332,7 +339,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
EN_BUF
|
EN_ICHAR
);
EN_BUF
|
EN_ICHAR
);
break
;
break
;
case
BTEMP_BALL
:
case
BTEMP_BALL
:
if
(
gpadc
->
chip_id
>=
AB8500_CUT3P0
)
{
if
(
!
is_ab8500_2p0_or_earlier
(
gpadc
->
parent
)
)
{
/* Turn on btemp pull-up on ABB 3.0 */
/* Turn on btemp pull-up on ABB 3.0 */
ret
=
abx500_mask_and_set_register_interruptible
(
ret
=
abx500_mask_and_set_register_interruptible
(
gpadc
->
dev
,
gpadc
->
dev
,
...
@@ -344,7 +351,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
...
@@ -344,7 +351,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
* Delay might be needed for ABB8500 cut 3.0, if not, remove
* Delay might be needed for ABB8500 cut 3.0, if not, remove
* when hardware will be available
* when hardware will be available
*/
*/
msleep
(
1
);
usleep_range
(
1000
,
1000
);
break
;
break
;
}
}
/* Intentional fallthrough */
/* Intentional fallthrough */
...
@@ -367,7 +374,8 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
...
@@ -367,7 +374,8 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
goto
out
;
goto
out
;
}
}
/* wait for completion of conversion */
/* wait for completion of conversion */
if
(
!
wait_for_completion_timeout
(
&
gpadc
->
ab8500_gpadc_complete
,
2
*
HZ
))
{
if
(
!
wait_for_completion_timeout
(
&
gpadc
->
ab8500_gpadc_complete
,
msecs_to_jiffies
(
CONVERSION_TIME
)))
{
dev_err
(
gpadc
->
dev
,
dev_err
(
gpadc
->
dev
,
"timeout: didn't receive GPADC conversion interrupt
\n
"
);
"timeout: didn't receive GPADC conversion interrupt
\n
"
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
...
@@ -397,8 +405,10 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
...
@@ -397,8 +405,10 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
dev_err
(
gpadc
->
dev
,
"gpadc_conversion: disable gpadc failed
\n
"
);
dev_err
(
gpadc
->
dev
,
"gpadc_conversion: disable gpadc failed
\n
"
);
goto
out
;
goto
out
;
}
}
/* Disable VTVout LDO this is required for GPADC */
regulator_disable
(
gpadc
->
regu
);
pm_runtime_mark_last_busy
(
gpadc
->
dev
);
pm_runtime_put_autosuspend
(
gpadc
->
dev
);
mutex_unlock
(
&
gpadc
->
ab8500_gpadc_lock
);
mutex_unlock
(
&
gpadc
->
ab8500_gpadc_lock
);
return
(
high_data
<<
8
)
|
low_data
;
return
(
high_data
<<
8
)
|
low_data
;
...
@@ -412,7 +422,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
...
@@ -412,7 +422,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
*/
*/
(
void
)
abx500_set_register_interruptible
(
gpadc
->
dev
,
AB8500_GPADC
,
(
void
)
abx500_set_register_interruptible
(
gpadc
->
dev
,
AB8500_GPADC
,
AB8500_GPADC_CTRL1_REG
,
DIS_GPADC
);
AB8500_GPADC_CTRL1_REG
,
DIS_GPADC
);
regulator_disable
(
gpadc
->
regu
);
pm_runtime_put
(
gpadc
->
dev
);
mutex_unlock
(
&
gpadc
->
ab8500_gpadc_lock
);
mutex_unlock
(
&
gpadc
->
ab8500_gpadc_lock
);
dev_err
(
gpadc
->
dev
,
dev_err
(
gpadc
->
dev
,
"gpadc_conversion: Failed to AD convert channel %d
\n
"
,
channel
);
"gpadc_conversion: Failed to AD convert channel %d
\n
"
,
channel
);
...
@@ -571,6 +583,28 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
...
@@ -571,6 +583,28 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
gpadc
->
cal_data
[
ADC_INPUT_VBAT
].
offset
);
gpadc
->
cal_data
[
ADC_INPUT_VBAT
].
offset
);
}
}
static
int
ab8500_gpadc_runtime_suspend
(
struct
device
*
dev
)
{
struct
ab8500_gpadc
*
gpadc
=
dev_get_drvdata
(
dev
);
regulator_disable
(
gpadc
->
regu
);
return
0
;
}
static
int
ab8500_gpadc_runtime_resume
(
struct
device
*
dev
)
{
struct
ab8500_gpadc
*
gpadc
=
dev_get_drvdata
(
dev
);
regulator_enable
(
gpadc
->
regu
);
return
0
;
}
static
int
ab8500_gpadc_runtime_idle
(
struct
device
*
dev
)
{
pm_runtime_suspend
(
dev
);
return
0
;
}
static
int
ab8500_gpadc_probe
(
struct
platform_device
*
pdev
)
static
int
ab8500_gpadc_probe
(
struct
platform_device
*
pdev
)
{
{
int
ret
=
0
;
int
ret
=
0
;
...
@@ -591,6 +625,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
...
@@ -591,6 +625,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
}
}
gpadc
->
dev
=
&
pdev
->
dev
;
gpadc
->
dev
=
&
pdev
->
dev
;
gpadc
->
parent
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
mutex_init
(
&
gpadc
->
ab8500_gpadc_lock
);
mutex_init
(
&
gpadc
->
ab8500_gpadc_lock
);
/* Initialize completion used to notify completion of conversion */
/* Initialize completion used to notify completion of conversion */
...
@@ -607,14 +642,6 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
...
@@ -607,14 +642,6 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
goto
fail
;
goto
fail
;
}
}
/* Get Chip ID of the ABB ASIC */
ret
=
abx500_get_chip_id
(
gpadc
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
gpadc
->
dev
,
"failed to get chip ID
\n
"
);
goto
fail_irq
;
}
gpadc
->
chip_id
=
(
u8
)
ret
;
/* VTVout LDO used to power up ab8500-GPADC */
/* VTVout LDO used to power up ab8500-GPADC */
gpadc
->
regu
=
regulator_get
(
&
pdev
->
dev
,
"vddadc"
);
gpadc
->
regu
=
regulator_get
(
&
pdev
->
dev
,
"vddadc"
);
if
(
IS_ERR
(
gpadc
->
regu
))
{
if
(
IS_ERR
(
gpadc
->
regu
))
{
...
@@ -622,6 +649,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
...
@@ -622,6 +649,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
dev_err
(
gpadc
->
dev
,
"failed to get vtvout LDO
\n
"
);
dev_err
(
gpadc
->
dev
,
"failed to get vtvout LDO
\n
"
);
goto
fail_irq
;
goto
fail_irq
;
}
}
platform_set_drvdata
(
pdev
,
gpadc
);
regulator_enable
(
gpadc
->
regu
);
pm_runtime_set_autosuspend_delay
(
gpadc
->
dev
,
GPADC_AUDOSUSPEND_DELAY
);
pm_runtime_use_autosuspend
(
gpadc
->
dev
);
pm_runtime_set_active
(
gpadc
->
dev
);
pm_runtime_enable
(
gpadc
->
dev
);
ab8500_gpadc_read_calibration_data
(
gpadc
);
ab8500_gpadc_read_calibration_data
(
gpadc
);
list_add_tail
(
&
gpadc
->
node
,
&
ab8500_gpadc_list
);
list_add_tail
(
&
gpadc
->
node
,
&
ab8500_gpadc_list
);
dev_dbg
(
gpadc
->
dev
,
"probe success
\n
"
);
dev_dbg
(
gpadc
->
dev
,
"probe success
\n
"
);
...
@@ -642,19 +679,34 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
...
@@ -642,19 +679,34 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
list_del
(
&
gpadc
->
node
);
list_del
(
&
gpadc
->
node
);
/* remove interrupt - completion of Sw ADC conversion */
/* remove interrupt - completion of Sw ADC conversion */
free_irq
(
gpadc
->
irq
,
gpadc
);
free_irq
(
gpadc
->
irq
,
gpadc
);
/* disable VTVout LDO that is being used by GPADC */
regulator_put
(
gpadc
->
regu
);
pm_runtime_get_sync
(
gpadc
->
dev
);
pm_runtime_disable
(
gpadc
->
dev
);
regulator_disable
(
gpadc
->
regu
);
pm_runtime_set_suspended
(
gpadc
->
dev
);
pm_runtime_put_noidle
(
gpadc
->
dev
);
kfree
(
gpadc
);
kfree
(
gpadc
);
gpadc
=
NULL
;
gpadc
=
NULL
;
return
0
;
return
0
;
}
}
static
const
struct
dev_pm_ops
ab8500_gpadc_pm_ops
=
{
SET_RUNTIME_PM_OPS
(
ab8500_gpadc_runtime_suspend
,
ab8500_gpadc_runtime_resume
,
ab8500_gpadc_runtime_idle
)
};
static
struct
platform_driver
ab8500_gpadc_driver
=
{
static
struct
platform_driver
ab8500_gpadc_driver
=
{
.
probe
=
ab8500_gpadc_probe
,
.
probe
=
ab8500_gpadc_probe
,
.
remove
=
ab8500_gpadc_remove
,
.
remove
=
ab8500_gpadc_remove
,
.
driver
=
{
.
driver
=
{
.
name
=
"ab8500-gpadc"
,
.
name
=
"ab8500-gpadc"
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
.
pm
=
&
ab8500_gpadc_pm_ops
,
},
},
};
};
...
...
drivers/mfd/ab8500-sysctrl.c
浏览文件 @
dce7886e
...
@@ -7,12 +7,73 @@
...
@@ -7,12 +7,73 @@
#include <linux/err.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/reboot.h>
#include <linux/signal.h>
#include <linux/power_supply.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
static
struct
device
*
sysctrl_dev
;
static
struct
device
*
sysctrl_dev
;
void
ab8500_power_off
(
void
)
{
sigset_t
old
;
sigset_t
all
;
static
char
*
pss
[]
=
{
"ab8500_ac"
,
"ab8500_usb"
};
int
i
;
bool
charger_present
=
false
;
union
power_supply_propval
val
;
struct
power_supply
*
psy
;
int
ret
;
/*
* If we have a charger connected and we're powering off,
* reboot into charge-only mode.
*/
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pss
);
i
++
)
{
psy
=
power_supply_get_by_name
(
pss
[
i
]);
if
(
!
psy
)
continue
;
ret
=
psy
->
get_property
(
psy
,
POWER_SUPPLY_PROP_ONLINE
,
&
val
);
if
(
!
ret
&&
val
.
intval
)
{
charger_present
=
true
;
break
;
}
}
if
(
!
charger_present
)
goto
shutdown
;
/* Check if battery is known */
psy
=
power_supply_get_by_name
(
"ab8500_btemp"
);
if
(
psy
)
{
ret
=
psy
->
get_property
(
psy
,
POWER_SUPPLY_PROP_TECHNOLOGY
,
&
val
);
if
(
!
ret
&&
val
.
intval
!=
POWER_SUPPLY_TECHNOLOGY_UNKNOWN
)
{
printk
(
KERN_INFO
"Charger
\"
%s
\"
is connected with known battery."
" Rebooting.
\n
"
,
pss
[
i
]);
machine_restart
(
"charging"
);
}
}
shutdown:
sigfillset
(
&
all
);
if
(
!
sigprocmask
(
SIG_BLOCK
,
&
all
,
&
old
))
{
(
void
)
ab8500_sysctrl_set
(
AB8500_STW4500CTRL1
,
AB8500_STW4500CTRL1_SWOFF
|
AB8500_STW4500CTRL1_SWRESET4500N
);
(
void
)
sigprocmask
(
SIG_SETMASK
,
&
old
,
NULL
);
}
}
static
inline
bool
valid_bank
(
u8
bank
)
static
inline
bool
valid_bank
(
u8
bank
)
{
{
return
((
bank
==
AB8500_SYS_CTRL1_BLOCK
)
||
return
((
bank
==
AB8500_SYS_CTRL1_BLOCK
)
||
...
@@ -33,6 +94,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
...
@@ -33,6 +94,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
return
abx500_get_register_interruptible
(
sysctrl_dev
,
bank
,
return
abx500_get_register_interruptible
(
sysctrl_dev
,
bank
,
(
u8
)(
reg
&
0xFF
),
value
);
(
u8
)(
reg
&
0xFF
),
value
);
}
}
EXPORT_SYMBOL
(
ab8500_sysctrl_read
);
int
ab8500_sysctrl_write
(
u16
reg
,
u8
mask
,
u8
value
)
int
ab8500_sysctrl_write
(
u16
reg
,
u8
mask
,
u8
value
)
{
{
...
@@ -48,10 +110,40 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
...
@@ -48,10 +110,40 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
return
abx500_mask_and_set_register_interruptible
(
sysctrl_dev
,
bank
,
return
abx500_mask_and_set_register_interruptible
(
sysctrl_dev
,
bank
,
(
u8
)(
reg
&
0xFF
),
mask
,
value
);
(
u8
)(
reg
&
0xFF
),
mask
,
value
);
}
}
EXPORT_SYMBOL
(
ab8500_sysctrl_write
);
static
int
ab8500_sysctrl_probe
(
struct
platform_device
*
pdev
)
static
int
ab8500_sysctrl_probe
(
struct
platform_device
*
pdev
)
{
{
struct
ab8500_platform_data
*
plat
;
struct
ab8500_sysctrl_platform_data
*
pdata
;
sysctrl_dev
=
&
pdev
->
dev
;
sysctrl_dev
=
&
pdev
->
dev
;
plat
=
dev_get_platdata
(
pdev
->
dev
.
parent
);
if
(
plat
->
pm_power_off
)
pm_power_off
=
ab8500_power_off
;
pdata
=
plat
->
sysctrl
;
if
(
pdata
)
{
int
ret
,
i
,
j
;
for
(
i
=
AB8500_SYSCLKREQ1RFCLKBUF
;
i
<=
AB8500_SYSCLKREQ8RFCLKBUF
;
i
++
)
{
j
=
i
-
AB8500_SYSCLKREQ1RFCLKBUF
;
ret
=
ab8500_sysctrl_write
(
i
,
0xff
,
pdata
->
initial_req_buf_config
[
j
]);
dev_dbg
(
&
pdev
->
dev
,
"Setting SysClkReq%dRfClkBuf 0x%X
\n
"
,
j
+
1
,
pdata
->
initial_req_buf_config
[
j
]);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"unable to set sysClkReq%dRfClkBuf: "
"%d
\n
"
,
j
+
1
,
ret
);
}
}
}
return
0
;
return
0
;
}
}
...
...
drivers/mfd/abx500-core.c
浏览文件 @
dce7886e
...
@@ -153,6 +153,22 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
...
@@ -153,6 +153,22 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
}
}
EXPORT_SYMBOL
(
abx500_startup_irq_enabled
);
EXPORT_SYMBOL
(
abx500_startup_irq_enabled
);
void
abx500_dump_all_banks
(
void
)
{
struct
abx500_ops
*
ops
;
struct
device
dummy_child
=
{
0
};
struct
abx500_device_entry
*
dev_entry
;
list_for_each_entry
(
dev_entry
,
&
abx500_list
,
list
)
{
dummy_child
.
parent
=
dev_entry
->
dev
;
ops
=
&
dev_entry
->
ops
;
if
((
ops
!=
NULL
)
&&
(
ops
->
dump_all_banks
!=
NULL
))
ops
->
dump_all_banks
(
&
dummy_child
);
}
}
EXPORT_SYMBOL
(
abx500_dump_all_banks
);
MODULE_AUTHOR
(
"Mattias Wallin <mattias.wallin@stericsson.com>"
);
MODULE_AUTHOR
(
"Mattias Wallin <mattias.wallin@stericsson.com>"
);
MODULE_DESCRIPTION
(
"ABX500 core driver"
);
MODULE_DESCRIPTION
(
"ABX500 core driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
include/linux/mfd/abx500.h
浏览文件 @
dce7886e
...
@@ -306,6 +306,7 @@ int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
...
@@ -306,6 +306,7 @@ int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
int
abx500_get_chip_id
(
struct
device
*
dev
);
int
abx500_get_chip_id
(
struct
device
*
dev
);
int
abx500_event_registers_startup_state_get
(
struct
device
*
dev
,
u8
*
event
);
int
abx500_event_registers_startup_state_get
(
struct
device
*
dev
,
u8
*
event
);
int
abx500_startup_irq_enabled
(
struct
device
*
dev
,
unsigned
int
irq
);
int
abx500_startup_irq_enabled
(
struct
device
*
dev
,
unsigned
int
irq
);
void
abx500_dump_all_banks
(
void
);
struct
abx500_ops
{
struct
abx500_ops
{
int
(
*
get_chip_id
)
(
struct
device
*
);
int
(
*
get_chip_id
)
(
struct
device
*
);
...
@@ -316,6 +317,7 @@ struct abx500_ops {
...
@@ -316,6 +317,7 @@ struct abx500_ops {
int
(
*
mask_and_set_register
)
(
struct
device
*
,
u8
,
u8
,
u8
,
u8
);
int
(
*
mask_and_set_register
)
(
struct
device
*
,
u8
,
u8
,
u8
,
u8
);
int
(
*
event_registers_startup_state_get
)
(
struct
device
*
,
u8
*
);
int
(
*
event_registers_startup_state_get
)
(
struct
device
*
,
u8
*
);
int
(
*
startup_irq_enabled
)
(
struct
device
*
,
unsigned
int
);
int
(
*
startup_irq_enabled
)
(
struct
device
*
,
unsigned
int
);
void
(
*
dump_all_banks
)
(
struct
device
*
);
};
};
int
abx500_register_ops
(
struct
device
*
core_dev
,
struct
abx500_ops
*
ops
);
int
abx500_register_ops
(
struct
device
*
core_dev
,
struct
abx500_ops
*
ops
);
...
...
include/linux/mfd/abx500/ab8500-sysctrl.h
浏览文件 @
dce7886e
...
@@ -37,6 +37,11 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
...
@@ -37,6 +37,11 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
return
ab8500_sysctrl_write
(
reg
,
bits
,
0
);
return
ab8500_sysctrl_write
(
reg
,
bits
,
0
);
}
}
/* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
struct
ab8500_sysctrl_platform_data
{
u8
initial_req_buf_config
[
8
];
};
/* Registers */
/* Registers */
#define AB8500_TURNONSTATUS 0x100
#define AB8500_TURNONSTATUS 0x100
#define AB8500_RESETSTATUS 0x101
#define AB8500_RESETSTATUS 0x101
...
...
include/linux/mfd/abx500/ab8500.h
浏览文件 @
dce7886e
...
@@ -270,10 +270,12 @@ struct regulator_reg_init;
...
@@ -270,10 +270,12 @@ struct regulator_reg_init;
struct
regulator_init_data
;
struct
regulator_init_data
;
struct
ab8500_gpio_platform_data
;
struct
ab8500_gpio_platform_data
;
struct
ab8500_codec_platform_data
;
struct
ab8500_codec_platform_data
;
struct
ab8500_sysctrl_platform_data
;
/**
/**
* struct ab8500_platform_data - AB8500 platform data
* struct ab8500_platform_data - AB8500 platform data
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @pm_power_off: Should machine pm power off hook be registered or not
* @init: board-specific initialization after detection of ab8500
* @init: board-specific initialization after detection of ab8500
* @num_regulator_reg_init: number of regulator init registers
* @num_regulator_reg_init: number of regulator init registers
* @regulator_reg_init: regulator init registers
* @regulator_reg_init: regulator init registers
...
@@ -282,6 +284,7 @@ struct ab8500_codec_platform_data;
...
@@ -282,6 +284,7 @@ struct ab8500_codec_platform_data;
*/
*/
struct
ab8500_platform_data
{
struct
ab8500_platform_data
{
int
irq_base
;
int
irq_base
;
bool
pm_power_off
;
void
(
*
init
)
(
struct
ab8500
*
);
void
(
*
init
)
(
struct
ab8500
*
);
int
num_regulator_reg_init
;
int
num_regulator_reg_init
;
struct
ab8500_regulator_reg_init
*
regulator_reg_init
;
struct
ab8500_regulator_reg_init
*
regulator_reg_init
;
...
@@ -289,6 +292,7 @@ struct ab8500_platform_data {
...
@@ -289,6 +292,7 @@ struct ab8500_platform_data {
struct
regulator_init_data
*
regulator
;
struct
regulator_init_data
*
regulator
;
struct
ab8500_gpio_platform_data
*
gpio
;
struct
ab8500_gpio_platform_data
*
gpio
;
struct
ab8500_codec_platform_data
*
codec
;
struct
ab8500_codec_platform_data
*
codec
;
struct
ab8500_sysctrl_platform_data
*
sysctrl
;
};
};
extern
int
ab8500_init
(
struct
ab8500
*
ab8500
,
extern
int
ab8500_init
(
struct
ab8500
*
ab8500
,
...
@@ -341,4 +345,12 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
...
@@ -341,4 +345,12 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
return
(
is_ab8500
(
ab
)
&&
(
ab
->
chip_id
==
AB8500_CUT2P0
));
return
(
is_ab8500
(
ab
)
&&
(
ab
->
chip_id
==
AB8500_CUT2P0
));
}
}
#ifdef CONFIG_AB8500_DEBUG
void
ab8500_dump_all_banks
(
struct
device
*
dev
);
void
ab8500_debug_register_interrupt
(
int
line
);
#else
static
inline
void
ab8500_dump_all_banks
(
struct
device
*
dev
)
{}
static
inline
void
ab8500_debug_register_interrupt
(
int
line
)
{}
#endif
#endif
/* MFD_AB8500_H */
#endif
/* MFD_AB8500_H */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录