Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
extcon
extcon-adc-jack.c
Go to the documentation of this file.
1
/*
2
* drivers/extcon/extcon-adc-jack.c
3
*
4
* Analog Jack extcon driver with ADC-based detection capability.
5
*
6
* Copyright (C) 2012 Samsung Electronics
7
* MyungJoo Ham <
[email protected]
>
8
*
9
* Modified for calling to IIO to get adc by <
[email protected]
>
10
*
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License version 2 as
13
* published by the Free Software Foundation.
14
*
15
*/
16
17
#include <linux/module.h>
18
#include <linux/slab.h>
19
#include <linux/device.h>
20
#include <
linux/platform_device.h
>
21
#include <
linux/err.h
>
22
#include <
linux/interrupt.h
>
23
#include <
linux/workqueue.h
>
24
#include <
linux/iio/consumer.h
>
25
#include <
linux/extcon/extcon-adc-jack.h
>
26
#include <
linux/extcon.h
>
27
41
struct
adc_jack_data
{
42
struct
extcon_dev
edev
;
43
44
const
char
**
cable_names
;
45
int
num_cables
;
46
struct
adc_jack_cond
*
adc_conditions
;
47
int
num_conditions
;
48
49
int
irq
;
50
unsigned
long
handling_delay
;
/* in jiffies */
51
struct
delayed_work
handler
;
52
53
struct
iio_channel
*
chan
;
54
};
55
56
static
void
adc_jack_handler(
struct
work_struct
*
work
)
57
{
58
struct
adc_jack_data
*
data
=
container_of
(to_delayed_work(work),
59
struct
adc_jack_data
,
60
handler
);
61
u32
state
= 0;
62
int
ret
, adc_val;
63
int
i
;
64
65
ret =
iio_read_channel_raw
(data->
chan
, &adc_val);
66
if
(ret < 0) {
67
dev_err
(data->
edev
.dev,
"read channel() error: %d\n"
, ret);
68
return
;
69
}
70
71
/* Get state from adc value with adc_conditions */
72
for
(i = 0; i < data->
num_conditions
; i++) {
73
struct
adc_jack_cond
*def = &data->
adc_conditions
[
i
];
74
if
(!def->
state
)
75
break
;
76
if
(def->
min_adc
<= adc_val && def->
max_adc
>= adc_val) {
77
state = def->
state
;
78
break
;
79
}
80
}
81
/* if no def has met, it means state = 0 (no cables attached) */
82
83
extcon_set_state
(&data->
edev
, state);
84
}
85
86
static
irqreturn_t
adc_jack_irq_thread(
int
irq,
void
*_data)
87
{
88
struct
adc_jack_data
*data = _data;
89
90
schedule_delayed_work
(&data->
handler
, data->
handling_delay
);
91
return
IRQ_HANDLED
;
92
}
93
94
static
int
__devinit
adc_jack_probe(
struct
platform_device
*pdev)
95
{
96
struct
adc_jack_data
*
data
;
97
struct
adc_jack_pdata
*
pdata
= pdev->
dev
.platform_data;
98
int
i
,
err
= 0;
99
100
data =
devm_kzalloc
(&pdev->
dev
,
sizeof
(*data),
GFP_KERNEL
);
101
if
(!data)
102
return
-
ENOMEM
;
103
104
data->
edev
.name = pdata->
name
;
105
106
if
(!pdata->
cable_names
) {
107
err = -
EINVAL
;
108
dev_err
(&pdev->
dev
,
"error: cable_names not defined.\n"
);
109
goto
out
;
110
}
111
112
data->
edev
.supported_cable = pdata->
cable_names
;
113
114
/* Check the length of array and set num_cables */
115
for
(i = 0; data->
edev
.supported_cable[
i
]; i++)
116
;
117
if
(i == 0 || i >
SUPPORTED_CABLE_MAX
) {
118
err = -
EINVAL
;
119
dev_err
(&pdev->
dev
,
"error: pdata->cable_names size = %d\n"
,
120
i - 1);
121
goto
out
;
122
}
123
data->
num_cables
=
i
;
124
125
if
(!pdata->
adc_conditions
||
126
!pdata->
adc_conditions
[0].state) {
127
err = -
EINVAL
;
128
dev_err
(&pdev->
dev
,
"error: adc_conditions not defined.\n"
);
129
goto
out
;
130
}
131
data->
adc_conditions
= pdata->
adc_conditions
;
132
133
/* Check the length of array and set num_conditions */
134
for
(i = 0; data->
adc_conditions
[
i
].state; i++)
135
;
136
data->
num_conditions
=
i
;
137
138
data->
chan
=
iio_channel_get
(dev_name(&pdev->
dev
),
139
pdata->
consumer_channel
);
140
if
(IS_ERR(data->
chan
)) {
141
err = PTR_ERR(data->
chan
);
142
goto
out
;
143
}
144
145
data->
handling_delay
=
msecs_to_jiffies
(pdata->
handling_delay_ms
);
146
147
INIT_DEFERRABLE_WORK
(&data->
handler
, adc_jack_handler);
148
149
platform_set_drvdata(pdev, data);
150
151
err =
extcon_dev_register
(&data->
edev
, &pdev->
dev
);
152
if
(err)
153
goto
out
;
154
155
data->
irq
=
platform_get_irq
(pdev, 0);
156
if
(!data->
irq
) {
157
dev_err
(&pdev->
dev
,
"platform_get_irq failed\n"
);
158
err = -
ENODEV
;
159
goto
err_irq;
160
}
161
162
err =
request_any_context_irq
(data->
irq
, adc_jack_irq_thread,
163
pdata->
irq_flags
, pdata->
name
, data);
164
165
if
(err < 0) {
166
dev_err
(&pdev->
dev
,
"error: irq %d\n"
, data->
irq
);
167
goto
err_irq;
168
}
169
170
return
0;
171
172
err_irq:
173
extcon_dev_unregister
(&data->
edev
);
174
out
:
175
return
err
;
176
}
177
178
static
int
__devexit
adc_jack_remove(
struct
platform_device
*pdev)
179
{
180
struct
adc_jack_data
*data = platform_get_drvdata(pdev);
181
182
free_irq
(data->
irq
, data);
183
cancel_work_sync
(&data->
handler
.work);
184
extcon_dev_unregister
(&data->
edev
);
185
186
return
0;
187
}
188
189
static
struct
platform_driver
adc_jack_driver = {
190
.probe = adc_jack_probe,
191
.remove =
__devexit_p
(adc_jack_remove),
192
.driver = {
193
.name =
"adc-jack"
,
194
.owner =
THIS_MODULE
,
195
},
196
};
197
198
module_platform_driver
(adc_jack_driver);
199
200
MODULE_AUTHOR
(
"MyungJoo Ham <
[email protected]
>"
);
201
MODULE_DESCRIPTION
(
"ADC Jack extcon driver"
);
202
MODULE_LICENSE
(
"GPL v2"
);
Generated on Thu Jan 10 2013 13:30:09 for Linux Kernel by
1.8.2