Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
0caeaede
Commit
0caeaede
authored
Mar 19, 2014
by
Lee Jones
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ib-mfd-io-3.15' into HEAD
parents
1a55361e
b2931b98
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
247 additions
and
133 deletions
+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
No files found.
Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
0 → 100644
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
;
...
...
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