Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
0caeaede
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看板
提交
0caeaede
编写于
3月 19, 2014
作者:
L
Lee Jones
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'ib-mfd-io-3.15' into HEAD
上级
1a55361e
b2931b98
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
247 addition
and
133 deletion
+247
-133
Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
+24
-0
drivers/iio/adc/Kconfig
drivers/iio/adc/Kconfig
+10
-0
drivers/iio/adc/Makefile
drivers/iio/adc/Makefile
+1
-0
drivers/iio/adc/twl4030-madc.c
drivers/iio/adc/twl4030-madc.c
+199
-121
drivers/mfd/Kconfig
drivers/mfd/Kconfig
+0
-10
drivers/mfd/Makefile
drivers/mfd/Makefile
+0
-1
include/linux/i2c/twl.h
include/linux/i2c/twl.h
+12
-0
include/linux/i2c/twl4030-madc.h
include/linux/i2c/twl4030-madc.h
+1
-1
未找到文件。
Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
0 → 100644
浏览文件 @
0caeaede
* TWL4030 Monitoring Analog to Digital Converter (MADC)
The MADC subsystem in the TWL4030 consists of a 10-bit ADC
combined with a 16-input analog multiplexer.
Required properties:
- compatible: Should contain "ti,twl4030-madc".
- interrupts: IRQ line for the MADC submodule.
- #io-channel-cells: Should be set to <1>.
Optional properties:
- ti,system-uses-second-madc-irq: boolean, set if the second madc irq register
should be used, which is intended to be used
by Co-Processors (e.g. a modem).
Example:
&twl {
madc {
compatible = "ti,twl4030-madc";
interrupts = <3>;
#io-channel-cells = <1>;
};
};
drivers/iio/adc/Kconfig
浏览文件 @
0caeaede
...
...
@@ -183,6 +183,16 @@ config TI_AM335X_ADC
Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client.
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
help
This driver provides support for Triton TWL4030-MADC. The
driver supports both RT and SW conversion methods.
This driver can also be built as a module. If so, the module will be
called twl4030-madc.
config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
depends on TWL4030_CORE
...
...
drivers/iio/adc/Makefile
浏览文件 @
0caeaede
...
...
@@ -20,5 +20,6 @@ obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_NAU7802)
+=
nau7802.o
obj-$(CONFIG_TI_ADC081C)
+=
ti-adc081c.o
obj-$(CONFIG_TI_AM335X_ADC)
+=
ti_am335x_adc.o
obj-$(CONFIG_TWL4030_MADC)
+=
twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC)
+=
twl6030-gpadc.o
obj-$(CONFIG_VIPERBOARD_ADC)
+=
viperboard_adc.o
drivers/
mfd
/twl4030-madc.c
→
drivers/
iio/adc
/twl4030-madc.c
浏览文件 @
0caeaede
...
...
@@ -47,20 +47,84 @@
#include <linux/gfp.h>
#include <linux/err.h>
/*
#include <linux/iio/iio.h>
/**
* struct twl4030_madc_data - a container for madc info
* @dev - pointer to device structure for madc
* @lock - mutex protecting this data structure
* @requests - Array of request struct corresponding to SW1, SW2 and RT
* @imr - Interrupt mask register of MADC
* @isr - Interrupt status register of MADC
* @dev: Pointer to device structure for madc
* @lock: Mutex protecting this data structure
* @requests: Array of request struct corresponding to SW1, SW2 and RT
* @use_second_irq: IRQ selection (main or co-processor)
* @imr: Interrupt mask register of MADC
* @isr: Interrupt status register of MADC
*/
struct
twl4030_madc_data
{
struct
device
*
dev
;
struct
mutex
lock
;
/* mutex protecting this data structure */
struct
twl4030_madc_request
requests
[
TWL4030_MADC_NUM_METHODS
];
int
imr
;
int
isr
;
bool
use_second_irq
;
u8
imr
;
u8
isr
;
};
static
int
twl4030_madc_read
(
struct
iio_dev
*
iio_dev
,
const
struct
iio_chan_spec
*
chan
,
int
*
val
,
int
*
val2
,
long
mask
)
{
struct
twl4030_madc_data
*
madc
=
iio_priv
(
iio_dev
);
struct
twl4030_madc_request
req
;
int
ret
;
req
.
method
=
madc
->
use_second_irq
?
TWL4030_MADC_SW2
:
TWL4030_MADC_SW1
;
req
.
channels
=
BIT
(
chan
->
channel
);
req
.
active
=
false
;
req
.
func_cb
=
NULL
;
req
.
type
=
TWL4030_MADC_WAIT
;
req
.
raw
=
!
(
mask
==
IIO_CHAN_INFO_PROCESSED
);
req
.
do_avg
=
(
mask
==
IIO_CHAN_INFO_AVERAGE_RAW
);
ret
=
twl4030_madc_conversion
(
&
req
);
if
(
ret
<
0
)
return
ret
;
*
val
=
req
.
rbuf
[
chan
->
channel
];
return
IIO_VAL_INT
;
}
static
const
struct
iio_info
twl4030_madc_iio_info
=
{
.
read_raw
=
&
twl4030_madc_read
,
.
driver_module
=
THIS_MODULE
,
};
#define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \
.type = _type, \
.channel = _channel, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
BIT(IIO_CHAN_INFO_PROCESSED), \
.datasheet_name = _name, \
.indexed = 1, \
}
static
const
struct
iio_chan_spec
twl4030_madc_iio_channels
[]
=
{
TWL4030_ADC_CHANNEL
(
0
,
IIO_VOLTAGE
,
"ADCIN0"
),
TWL4030_ADC_CHANNEL
(
1
,
IIO_TEMP
,
"ADCIN1"
),
TWL4030_ADC_CHANNEL
(
2
,
IIO_VOLTAGE
,
"ADCIN2"
),
TWL4030_ADC_CHANNEL
(
3
,
IIO_VOLTAGE
,
"ADCIN3"
),
TWL4030_ADC_CHANNEL
(
4
,
IIO_VOLTAGE
,
"ADCIN4"
),
TWL4030_ADC_CHANNEL
(
5
,
IIO_VOLTAGE
,
"ADCIN5"
),
TWL4030_ADC_CHANNEL
(
6
,
IIO_VOLTAGE
,
"ADCIN6"
),
TWL4030_ADC_CHANNEL
(
7
,
IIO_VOLTAGE
,
"ADCIN7"
),
TWL4030_ADC_CHANNEL
(
8
,
IIO_VOLTAGE
,
"ADCIN8"
),
TWL4030_ADC_CHANNEL
(
9
,
IIO_VOLTAGE
,
"ADCIN9"
),
TWL4030_ADC_CHANNEL
(
10
,
IIO_CURRENT
,
"ADCIN10"
),
TWL4030_ADC_CHANNEL
(
11
,
IIO_VOLTAGE
,
"ADCIN11"
),
TWL4030_ADC_CHANNEL
(
12
,
IIO_VOLTAGE
,
"ADCIN12"
),
TWL4030_ADC_CHANNEL
(
13
,
IIO_VOLTAGE
,
"ADCIN13"
),
TWL4030_ADC_CHANNEL
(
14
,
IIO_VOLTAGE
,
"ADCIN14"
),
TWL4030_ADC_CHANNEL
(
15
,
IIO_VOLTAGE
,
"ADCIN15"
),
};
static
struct
twl4030_madc_data
*
twl4030_madc
;
...
...
@@ -91,17 +155,16 @@ twl4030_divider_ratios[16] = {
};
/*
* Conversion table from -3 to 55 degree Celcius
*/
static
int
therm_tbl
[]
=
{
30800
,
29500
,
28300
,
27100
,
26000
,
24900
,
23900
,
22900
,
22000
,
21100
,
20300
,
19400
,
18700
,
17900
,
17200
,
16500
,
15900
,
15300
,
14700
,
14100
,
13600
,
13100
,
12600
,
12100
,
11600
,
11200
,
10800
,
10400
,
10000
,
9630
,
9280
,
8950
,
8620
,
8310
,
8020
,
7730
,
7460
,
7200
,
6950
,
6710
,
6470
,
6250
,
6040
,
5830
,
5640
,
5450
,
5260
,
5090
,
4920
,
4760
,
4600
,
4450
,
4310
,
4170
,
4040
,
3910
,
3790
,
3670
,
3550
/* Conversion table from -3 to 55 degrees Celcius */
static
int
twl4030_therm_tbl
[]
=
{
30800
,
29500
,
28300
,
27100
,
26000
,
24900
,
23900
,
22900
,
22000
,
21100
,
20300
,
19400
,
18700
,
17900
,
17200
,
16500
,
15900
,
15300
,
14700
,
14100
,
13600
,
13100
,
12600
,
12100
,
11600
,
11200
,
10800
,
10400
,
10000
,
9630
,
9280
,
8950
,
8620
,
8310
,
8020
,
7730
,
7460
,
7200
,
6950
,
6710
,
6470
,
6250
,
6040
,
5830
,
5640
,
5450
,
5260
,
5090
,
4920
,
4760
,
4600
,
4450
,
4310
,
4170
,
4040
,
3910
,
3790
,
3670
,
3550
};
/*
...
...
@@ -133,37 +196,32 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
},
};
/*
* Function to read a particular channel value.
* @madc - pointer to struct twl4030_madc_data
* @reg - lsb of ADC Channel
* If the i2c read fails it returns an error else returns 0.
/**
* twl4030_madc_channel_raw_read() - Function to read a particular channel value
* @madc: pointer to struct twl4030_madc_data
* @reg: lsb of ADC Channel
*
* Return: 0 on success, an error code otherwise.
*/
static
int
twl4030_madc_channel_raw_read
(
struct
twl4030_madc_data
*
madc
,
u8
reg
)
{
u
8
msb
,
lsb
;
u
16
val
;
int
ret
;
/*
* For each ADC channel, we have MSB and LSB register pair. MSB address
* is always LSB address+1. reg parameter is the address of LSB register
*/
ret
=
twl_i2c_read_u
8
(
TWL4030_MODULE_MADC
,
&
msb
,
reg
+
1
);
ret
=
twl_i2c_read_u
16
(
TWL4030_MODULE_MADC
,
&
val
,
reg
);
if
(
ret
)
{
dev_err
(
madc
->
dev
,
"unable to read MSB register 0x%X
\n
"
,
reg
+
1
);
return
ret
;
}
ret
=
twl_i2c_read_u8
(
TWL4030_MODULE_MADC
,
&
lsb
,
reg
);
if
(
ret
)
{
dev_err
(
madc
->
dev
,
"unable to read LSB register 0x%X
\n
"
,
reg
);
dev_err
(
madc
->
dev
,
"unable to read register 0x%X
\n
"
,
reg
);
return
ret
;
}
return
(
int
)(
((
msb
<<
8
)
|
lsb
)
>>
6
);
return
(
int
)(
val
>>
6
);
}
/*
* Return battery temperature
* Return battery temperature
in degrees Celsius
* Or < 0 on failure.
*/
static
int
twl4030battery_temperature
(
int
raw_volt
)
...
...
@@ -172,18 +230,18 @@ static int twl4030battery_temperature(int raw_volt)
int
temp
,
curr
,
volt
,
res
,
ret
;
volt
=
(
raw_volt
*
TEMP_STEP_SIZE
)
/
TEMP_PSR_R
;
/* Getting and calculating the supply current in micro ampers */
/* Getting and calculating the supply current in micro amper
e
s */
ret
=
twl_i2c_read_u8
(
TWL_MODULE_MAIN_CHARGE
,
&
val
,
REG_BCICTL2
);
if
(
ret
<
0
)
return
ret
;
curr
=
((
val
&
TWL4030_BCI_ITHEN
)
+
1
)
*
10
;
/* Getting and calculating the thermistor resistance in ohms */
res
=
volt
*
1000
/
curr
;
/* calculating temperature */
for
(
temp
=
58
;
temp
>=
0
;
temp
--
)
{
int
actual
=
therm_tbl
[
temp
];
int
actual
=
twl4030_therm_tbl
[
temp
];
if
((
actual
-
res
)
>=
0
)
break
;
}
...
...
@@ -205,11 +263,12 @@ static int twl4030battery_current(int raw_volt)
else
/* slope of 0.88 mV/mA */
return
(
raw_volt
*
CURR_STEP_SIZE
)
/
CURR_PSR_R2
;
}
/*
* Function to read channel values
* @madc - pointer to twl4030_madc_data struct
* @reg_base - Base address of the first channel
* @Channels - 16 bit bitmap. If the bit is set, channel value is read
* @Channels - 16 bit bitmap. If the bit is set, channel
's
value is read
* @buf - The channel values are stored here. if read fails error
* @raw - Return raw values without conversion
* value is stored
...
...
@@ -220,17 +279,17 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
long
channels
,
int
*
buf
,
bool
raw
)
{
int
count
=
0
,
count_req
=
0
,
i
;
int
count
=
0
;
int
i
;
u8
reg
;
for_each_set_bit
(
i
,
&
channels
,
TWL4030_MADC_MAX_CHANNELS
)
{
reg
=
reg_base
+
2
*
i
;
reg
=
reg_base
+
(
2
*
i
)
;
buf
[
i
]
=
twl4030_madc_channel_raw_read
(
madc
,
reg
);
if
(
buf
[
i
]
<
0
)
{
dev_err
(
madc
->
dev
,
"Unable to read register 0x%X
\n
"
,
reg
);
count_req
++
;
continue
;
dev_err
(
madc
->
dev
,
"Unable to read register 0x%X
\n
"
,
reg
);
return
buf
[
i
];
}
if
(
raw
)
{
count
++
;
...
...
@@ -241,7 +300,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
buf
[
i
]
=
twl4030battery_current
(
buf
[
i
]);
if
(
buf
[
i
]
<
0
)
{
dev_err
(
madc
->
dev
,
"err reading current
\n
"
);
count_req
++
;
return
buf
[
i
]
;
}
else
{
count
++
;
buf
[
i
]
=
buf
[
i
]
-
750
;
...
...
@@ -251,7 +310,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
buf
[
i
]
=
twl4030battery_temperature
(
buf
[
i
]);
if
(
buf
[
i
]
<
0
)
{
dev_err
(
madc
->
dev
,
"err reading temperature
\n
"
);
count_req
++
;
return
buf
[
i
]
;
}
else
{
buf
[
i
]
-=
3
;
count
++
;
...
...
@@ -272,8 +331,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
twl4030_divider_ratios
[
i
].
numerator
);
}
}
if
(
count_req
)
dev_err
(
madc
->
dev
,
"%d channel conversion failed
\n
"
,
count_req
);
return
count
;
}
...
...
@@ -297,13 +354,13 @@ static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
madc
->
imr
);
return
ret
;
}
val
&=
~
(
1
<<
id
);
ret
=
twl_i2c_write_u8
(
TWL4030_MODULE_MADC
,
val
,
madc
->
imr
);
if
(
ret
)
{
dev_err
(
madc
->
dev
,
"unable to write imr register 0x%X
\n
"
,
madc
->
imr
);
return
ret
;
}
return
0
;
...
...
@@ -366,7 +423,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
continue
;
ret
=
twl4030_madc_disable_irq
(
madc
,
i
);
if
(
ret
<
0
)
dev_dbg
(
madc
->
dev
,
"Disable interrupt failed%d
\n
"
,
i
);
dev_dbg
(
madc
->
dev
,
"Disable interrupt failed
%d
\n
"
,
i
);
madc
->
requests
[
i
].
result_pending
=
1
;
}
for
(
i
=
0
;
i
<
TWL4030_MADC_NUM_METHODS
;
i
++
)
{
...
...
@@ -448,21 +505,17 @@ static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
{
const
struct
twl4030_madc_conversion_method
*
method
;
int
ret
=
0
;
if
(
conv_method
!=
TWL4030_MADC_SW1
&&
conv_method
!=
TWL4030_MADC_SW2
)
return
-
ENOTSUPP
;
method
=
&
twl4030_conversion_methods
[
conv_method
];
switch
(
conv_method
)
{
case
TWL4030_MADC_SW1
:
case
TWL4030_MADC_SW2
:
ret
=
twl_i2c_write_u8
(
TWL4030_MODULE_MADC
,
TWL4030_MADC_SW_START
,
method
->
ctrl
);
if
(
ret
)
{
dev_err
(
madc
->
dev
,
"unable to write ctrl register 0x%X
\n
"
,
method
->
ctrl
);
return
ret
;
}
break
;
default:
break
;
ret
=
twl_i2c_write_u8
(
TWL4030_MODULE_MADC
,
TWL4030_MADC_SW_START
,
method
->
ctrl
);
if
(
ret
)
{
dev_err
(
madc
->
dev
,
"unable to write ctrl register 0x%X
\n
"
,
method
->
ctrl
);
return
ret
;
}
return
0
;
...
...
@@ -513,7 +566,6 @@ static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
int
twl4030_madc_conversion
(
struct
twl4030_madc_request
*
req
)
{
const
struct
twl4030_madc_conversion_method
*
method
;
u8
ch_msb
,
ch_lsb
;
int
ret
;
if
(
!
req
||
!
twl4030_madc
)
...
...
@@ -529,38 +581,22 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
ret
=
-
EBUSY
;
goto
out
;
}
ch_msb
=
(
req
->
channels
>>
8
)
&
0xff
;
ch_lsb
=
req
->
channels
&
0xff
;
method
=
&
twl4030_conversion_methods
[
req
->
method
];
/* Select channels to be converted */
ret
=
twl_i2c_write_u8
(
TWL4030_MODULE_MADC
,
ch_msb
,
method
->
sel
+
1
);
if
(
ret
)
{
dev_err
(
twl4030_madc
->
dev
,
"unable to write sel register 0x%X
\n
"
,
method
->
sel
+
1
);
goto
out
;
}
ret
=
twl_i2c_write_u8
(
TWL4030_MODULE_MADC
,
ch_lsb
,
method
->
sel
);
ret
=
twl_i2c_write_u16
(
TWL4030_MODULE_MADC
,
req
->
channels
,
method
->
sel
);
if
(
ret
)
{
dev_err
(
twl4030_madc
->
dev
,
"unable to write sel register 0x%X
\n
"
,
method
->
sel
+
1
);
"unable to write sel register 0x%X
\n
"
,
method
->
sel
);
goto
out
;
}
/* Select averaging for all channels if do_avg is set */
if
(
req
->
do_avg
)
{
ret
=
twl_i2c_write_u
8
(
TWL4030_MODULE_MADC
,
ch_msb
,
method
->
avg
+
1
);
ret
=
twl_i2c_write_u
16
(
TWL4030_MODULE_MADC
,
req
->
channels
,
method
->
avg
);
if
(
ret
)
{
dev_err
(
twl4030_madc
->
dev
,
"unable to write avg register 0x%X
\n
"
,
method
->
avg
+
1
);
goto
out
;
}
ret
=
twl_i2c_write_u8
(
TWL4030_MODULE_MADC
,
ch_lsb
,
method
->
avg
);
if
(
ret
)
{
dev_err
(
twl4030_madc
->
dev
,
"unable to write sel reg 0x%X
\n
"
,
method
->
sel
+
1
);
method
->
avg
);
goto
out
;
}
}
...
...
@@ -601,10 +637,6 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
}
EXPORT_SYMBOL_GPL
(
twl4030_madc_conversion
);
/*
* Return channel value
* Or < 0 on failure.
*/
int
twl4030_get_madc_conversion
(
int
channel_no
)
{
struct
twl4030_madc_request
req
;
...
...
@@ -625,20 +657,25 @@ int twl4030_get_madc_conversion(int channel_no)
}
EXPORT_SYMBOL_GPL
(
twl4030_get_madc_conversion
);
/*
/**
* twl4030_madc_set_current_generator() - setup bias current
*
* @madc: pointer to twl4030_madc_data struct
* @chan: can be one of the two values:
* TWL4030_BCI_ITHEN
* Enables bias current for main battery type reading
* TWL4030_BCI_TYPEN
* Enables bias current for main battery temperature sensing
* @on: enable or disable chan.
*
* Function to enable or disable bias current for
* main battery type reading or temperature sensing
* @madc - pointer to twl4030_madc_data struct
* @chan - can be one of the two values
* TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
* TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
* sensing
* @on - enable or disable chan.
*/
static
int
twl4030_madc_set_current_generator
(
struct
twl4030_madc_data
*
madc
,
int
chan
,
int
on
)
{
int
ret
;
int
regmask
;
u8
regval
;
ret
=
twl_i2c_read_u8
(
TWL_MODULE_MAIN_CHARGE
,
...
...
@@ -648,10 +685,13 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
TWL4030_BCI_BCICTL1
);
return
ret
;
}
regmask
=
chan
?
TWL4030_BCI_ITHEN
:
TWL4030_BCI_TYPEN
;
if
(
on
)
regval
|=
chan
?
TWL4030_BCI_ITHEN
:
TWL4030_BCI_TYPEN
;
regval
|=
regmask
;
else
regval
&=
chan
?
~
TWL4030_BCI_ITHEN
:
~
TWL4030_BCI_TYPEN
;
regval
&=
~
regmask
;
ret
=
twl_i2c_write_u8
(
TWL_MODULE_MAIN_CHARGE
,
regval
,
TWL4030_BCI_BCICTL1
);
if
(
ret
)
{
...
...
@@ -666,7 +706,7 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
/*
* Function that sets MADC software power on bit to enable MADC
* @madc - pointer to twl4030_madc_data struct
* @on - Enable or disable MADC software powe
n
on bit.
* @on - Enable or disable MADC software powe
r
on bit.
* returns error if i2c read/write fails else 0
*/
static
int
twl4030_madc_set_power
(
struct
twl4030_madc_data
*
madc
,
int
on
)
...
...
@@ -702,31 +742,52 @@ static int twl4030_madc_probe(struct platform_device *pdev)
{
struct
twl4030_madc_data
*
madc
;
struct
twl4030_madc_platform_data
*
pdata
=
dev_get_platdata
(
&
pdev
->
dev
);
int
ret
;
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
int
irq
,
ret
;
u8
regval
;
struct
iio_dev
*
iio_dev
=
NULL
;
if
(
!
pdata
)
{
dev_err
(
&
pdev
->
dev
,
"
platform_data not
available
\n
"
);
if
(
!
pdata
&&
!
np
)
{
dev_err
(
&
pdev
->
dev
,
"
neither platform data nor Device Tree node
available
\n
"
);
return
-
EINVAL
;
}
madc
=
kzalloc
(
sizeof
(
*
madc
),
GFP_KERNEL
);
if
(
!
madc
)
iio_dev
=
devm_iio_device_alloc
(
&
pdev
->
dev
,
sizeof
(
*
madc
));
if
(
!
iio_dev
)
{
dev_err
(
&
pdev
->
dev
,
"failed allocating iio device
\n
"
);
return
-
ENOMEM
;
}
madc
=
iio_priv
(
iio_dev
);
madc
->
dev
=
&
pdev
->
dev
;
iio_dev
->
name
=
dev_name
(
&
pdev
->
dev
);
iio_dev
->
dev
.
parent
=
&
pdev
->
dev
;
iio_dev
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
iio_dev
->
info
=
&
twl4030_madc_iio_info
;
iio_dev
->
modes
=
INDIO_DIRECT_MODE
;
iio_dev
->
channels
=
twl4030_madc_iio_channels
;
iio_dev
->
num_channels
=
ARRAY_SIZE
(
twl4030_madc_iio_channels
);
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
* the OMAP. The other one can be connected to the other processor such
* as modem. Hence two separate ISR and IMR registers.
*/
madc
->
imr
=
(
pdata
->
irq_line
==
1
)
?
TWL4030_MADC_IMR1
:
TWL4030_MADC_IMR2
;
madc
->
isr
=
(
pdata
->
irq_line
==
1
)
?
TWL4030_MADC_ISR1
:
TWL4030_MADC_ISR2
;
if
(
pdata
)
madc
->
use_second_irq
=
(
pdata
->
irq_line
!=
1
);
else
madc
->
use_second_irq
=
of_property_read_bool
(
np
,
"ti,system-uses-second-madc-irq"
);
madc
->
imr
=
madc
->
use_second_irq
?
TWL4030_MADC_IMR2
:
TWL4030_MADC_IMR1
;
madc
->
isr
=
madc
->
use_second_irq
?
TWL4030_MADC_ISR2
:
TWL4030_MADC_ISR1
;
ret
=
twl4030_madc_set_power
(
madc
,
1
);
if
(
ret
<
0
)
goto
err_power
;
return
ret
;
ret
=
twl4030_madc_set_current_generator
(
madc
,
0
,
1
);
if
(
ret
<
0
)
goto
err_current_generator
;
...
...
@@ -768,46 +829,63 @@ static int twl4030_madc_probe(struct platform_device *pdev)
}
}
platform_set_drvdata
(
pdev
,
madc
);
platform_set_drvdata
(
pdev
,
iio_dev
);
mutex_init
(
&
madc
->
lock
);
ret
=
request_threaded_irq
(
platform_get_irq
(
pdev
,
0
),
NULL
,
irq
=
platform_get_irq
(
pdev
,
0
);
ret
=
devm_request_threaded_irq
(
&
pdev
->
dev
,
irq
,
NULL
,
twl4030_madc_threaded_irq_handler
,
IRQF_TRIGGER_RISING
,
"twl4030_madc"
,
madc
);
if
(
ret
)
{
dev_
dbg
(
&
pdev
->
dev
,
"could not request irq
\n
"
);
dev_
err
(
&
pdev
->
dev
,
"could not request irq
\n
"
);
goto
err_i2c
;
}
twl4030_madc
=
madc
;
ret
=
iio_device_register
(
iio_dev
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"could not register iio device
\n
"
);
goto
err_i2c
;
}
return
0
;
err_i2c:
twl4030_madc_set_current_generator
(
madc
,
0
,
0
);
err_current_generator:
twl4030_madc_set_power
(
madc
,
0
);
err_power:
kfree
(
madc
);
return
ret
;
}
static
int
twl4030_madc_remove
(
struct
platform_device
*
pdev
)
{
struct
twl4030_madc_data
*
madc
=
platform_get_drvdata
(
pdev
);
struct
iio_dev
*
iio_dev
=
platform_get_drvdata
(
pdev
);
struct
twl4030_madc_data
*
madc
=
iio_priv
(
iio_dev
);
iio_device_unregister
(
iio_dev
);
free_irq
(
platform_get_irq
(
pdev
,
0
),
madc
);
twl4030_madc_set_current_generator
(
madc
,
0
,
0
);
twl4030_madc_set_power
(
madc
,
0
);
kfree
(
madc
);
return
0
;
}
#ifdef CONFIG_OF
static
const
struct
of_device_id
twl_madc_of_match
[]
=
{
{
.
compatible
=
"ti,twl4030-madc"
,
},
{
},
};
MODULE_DEVICE_TABLE
(
of
,
twl_madc_of_match
);
#endif
static
struct
platform_driver
twl4030_madc_driver
=
{
.
probe
=
twl4030_madc_probe
,
.
remove
=
twl4030_madc_remove
,
.
driver
=
{
.
name
=
"twl4030_madc"
,
.
owner
=
THIS_MODULE
,
},
.
of_match_table
=
of_match_ptr
(
twl_madc_of_match
),
},
};
module_platform_driver
(
twl4030_madc_driver
);
...
...
drivers/mfd/Kconfig
浏览文件 @
0caeaede
...
...
@@ -935,16 +935,6 @@ config TWL4030_CORE
high speed USB OTG transceiver, an audio codec (on most
versions) and many other features.
config TWL4030_MADC
tristate "TI TWL4030 MADC"
depends on TWL4030_CORE
help
This driver provides support for triton TWL4030-MADC. The
driver supports both RT and SW conversion methods.
This driver can be built as a module. If so it will be
named twl4030-madc
config TWL4030_POWER
bool "TI TWL4030 power resources"
depends on TWL4030_CORE && ARM
...
...
drivers/mfd/Makefile
浏览文件 @
0caeaede
...
...
@@ -71,7 +71,6 @@ obj-$(CONFIG_MFD_TPS80031) += tps80031.o
obj-$(CONFIG_MENELAUS)
+=
menelaus.o
obj-$(CONFIG_TWL4030_CORE)
+=
twl-core.o twl4030-irq.o twl6030-irq.o
obj-$(CONFIG_TWL4030_MADC)
+=
twl4030-madc.o
obj-$(CONFIG_TWL4030_POWER)
+=
twl4030-power.o
obj-$(CONFIG_MFD_TWL4030_AUDIO)
+=
twl4030-audio.o
obj-$(CONFIG_TWL6040_CORE)
+=
twl6040.o
...
...
include/linux/i2c/twl.h
浏览文件 @
0caeaede
...
...
@@ -195,6 +195,18 @@ static inline int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg) {
return
twl_i2c_read
(
mod_no
,
val
,
reg
,
1
);
}
static
inline
int
twl_i2c_write_u16
(
u8
mod_no
,
u16
val
,
u8
reg
)
{
val
=
cpu_to_le16
(
val
);
return
twl_i2c_write
(
mod_no
,
(
u8
*
)
&
val
,
reg
,
2
);
}
static
inline
int
twl_i2c_read_u16
(
u8
mod_no
,
u16
*
val
,
u8
reg
)
{
int
ret
;
ret
=
twl_i2c_read
(
mod_no
,
(
u8
*
)
val
,
reg
,
2
);
*
val
=
le16_to_cpu
(
*
val
);
return
ret
;
}
int
twl_get_type
(
void
);
int
twl_get_version
(
void
);
int
twl_get_hfclk_rate
(
void
);
...
...
include/linux/i2c/twl4030-madc.h
浏览文件 @
0caeaede
...
...
@@ -44,7 +44,7 @@ struct twl4030_madc_conversion_method {
struct
twl4030_madc_request
{
unsigned
long
channels
;
u16
do_avg
;
bool
do_avg
;
u16
method
;
u16
type
;
bool
active
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录