-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 324414 b: refs/heads/master c: 1993986 h: refs/heads/master v: v3
- Loading branch information
anish kumar
authored and
Greg Kroah-Hartman
committed
Sep 5, 2012
1 parent
112ed24
commit d88ccaf
Showing
5 changed files
with
277 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: c338bb0380b1cd64ae566d1ea7d1bfd6c811297d | ||
refs/heads/master: 19939860dcae5a3b2e11318eb7d65b4db2e55e2b |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/* | ||
* drivers/extcon/extcon-adc-jack.c | ||
* | ||
* Analog Jack extcon driver with ADC-based detection capability. | ||
* | ||
* Copyright (C) 2012 Samsung Electronics | ||
* MyungJoo Ham <myungjoo.ham@samsung.com> | ||
* | ||
* Modified for calling to IIO to get adc by <anish.singh@samsung.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
*/ | ||
|
||
#include <linux/slab.h> | ||
#include <linux/device.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/err.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/workqueue.h> | ||
#include <linux/iio/consumer.h> | ||
#include <linux/extcon/extcon-adc-jack.h> | ||
#include <linux/extcon.h> | ||
|
||
/** | ||
* struct adc_jack_data - internal data for adc_jack device driver | ||
* @edev - extcon device. | ||
* @cable_names - list of supported cables. | ||
* @num_cables - size of cable_names. | ||
* @adc_conditions - list of adc value conditions. | ||
* @num_conditions - size of adc_conditions. | ||
* @irq - irq number of attach/detach event (0 if not exist). | ||
* @handling_delay - interrupt handler will schedule extcon event | ||
* handling at handling_delay jiffies. | ||
* @handler - extcon event handler called by interrupt handler. | ||
* @chan - iio channel being queried. | ||
*/ | ||
struct adc_jack_data { | ||
struct extcon_dev edev; | ||
|
||
const char **cable_names; | ||
int num_cables; | ||
struct adc_jack_cond *adc_conditions; | ||
int num_conditions; | ||
|
||
int irq; | ||
unsigned long handling_delay; /* in jiffies */ | ||
struct delayed_work handler; | ||
|
||
struct iio_channel *chan; | ||
}; | ||
|
||
static void adc_jack_handler(struct work_struct *work) | ||
{ | ||
struct adc_jack_data *data = container_of(to_delayed_work(work), | ||
struct adc_jack_data, | ||
handler); | ||
u32 state = 0; | ||
int ret, adc_val; | ||
int i; | ||
|
||
ret = iio_read_channel_raw(data->chan, &adc_val); | ||
if (ret < 0) { | ||
dev_err(data->edev.dev, "read channel() error: %d\n", ret); | ||
return; | ||
} | ||
|
||
/* Get state from adc value with adc_conditions */ | ||
for (i = 0; i < data->num_conditions; i++) { | ||
struct adc_jack_cond *def = &data->adc_conditions[i]; | ||
if (!def->state) | ||
break; | ||
if (def->min_adc <= adc_val && def->max_adc >= adc_val) { | ||
state = def->state; | ||
break; | ||
} | ||
} | ||
/* if no def has met, it means state = 0 (no cables attached) */ | ||
|
||
extcon_set_state(&data->edev, state); | ||
} | ||
|
||
static irqreturn_t adc_jack_irq_thread(int irq, void *_data) | ||
{ | ||
struct adc_jack_data *data = _data; | ||
|
||
schedule_delayed_work(&data->handler, data->handling_delay); | ||
return IRQ_HANDLED; | ||
} | ||
|
||
static int __devinit adc_jack_probe(struct platform_device *pdev) | ||
{ | ||
struct adc_jack_data *data; | ||
struct adc_jack_pdata *pdata = pdev->dev.platform_data; | ||
int i, err = 0; | ||
|
||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
if (!data) | ||
return -ENOMEM; | ||
|
||
data->edev.name = pdata->name; | ||
|
||
if (!pdata->cable_names) { | ||
err = -EINVAL; | ||
dev_err(&pdev->dev, "error: cable_names not defined.\n"); | ||
goto out; | ||
} | ||
|
||
data->edev.supported_cable = pdata->cable_names; | ||
|
||
/* Check the length of array and set num_cables */ | ||
for (i = 0; data->edev.supported_cable[i]; i++) | ||
; | ||
if (i == 0 || i > SUPPORTED_CABLE_MAX) { | ||
err = -EINVAL; | ||
dev_err(&pdev->dev, "error: pdata->cable_names size = %d\n", | ||
i - 1); | ||
goto out; | ||
} | ||
data->num_cables = i; | ||
|
||
if (!pdata->adc_conditions || | ||
!pdata->adc_conditions[0].state) { | ||
err = -EINVAL; | ||
dev_err(&pdev->dev, "error: adc_conditions not defined.\n"); | ||
goto out; | ||
} | ||
data->adc_conditions = pdata->adc_conditions; | ||
|
||
/* Check the length of array and set num_conditions */ | ||
for (i = 0; data->adc_conditions[i].state; i++) | ||
; | ||
data->num_conditions = i; | ||
|
||
data->chan = iio_channel_get(dev_name(&pdev->dev), | ||
pdata->consumer_channel); | ||
if (IS_ERR(data->chan)) { | ||
err = PTR_ERR(data->chan); | ||
goto out; | ||
} | ||
|
||
data->handling_delay = msecs_to_jiffies(pdata->handling_delay_ms); | ||
|
||
INIT_DELAYED_WORK_DEFERRABLE(&data->handler, adc_jack_handler); | ||
|
||
platform_set_drvdata(pdev, data); | ||
|
||
err = extcon_dev_register(&data->edev, &pdev->dev); | ||
if (err) | ||
goto out; | ||
|
||
data->irq = platform_get_irq(pdev, 0); | ||
if (!data->irq) { | ||
dev_err(&pdev->dev, "platform_get_irq failed\n"); | ||
err = -ENODEV; | ||
goto err_irq; | ||
} | ||
|
||
err = request_any_context_irq(data->irq, adc_jack_irq_thread, | ||
pdata->irq_flags, pdata->name, data); | ||
|
||
if (err) { | ||
dev_err(&pdev->dev, "error: irq %d\n", data->irq); | ||
err = -EINVAL; | ||
goto err_irq; | ||
} | ||
|
||
goto out; | ||
|
||
err_irq: | ||
extcon_dev_unregister(&data->edev); | ||
out: | ||
return err; | ||
} | ||
|
||
static int __devexit adc_jack_remove(struct platform_device *pdev) | ||
{ | ||
struct adc_jack_data *data = platform_get_drvdata(pdev); | ||
|
||
free_irq(data->irq, data); | ||
cancel_work_sync(&data->handler.work); | ||
extcon_dev_unregister(&data->edev); | ||
|
||
return 0; | ||
} | ||
|
||
static struct platform_driver adc_jack_driver = { | ||
.probe = adc_jack_probe, | ||
.remove = __devexit_p(adc_jack_remove), | ||
.driver = { | ||
.name = "adc-jack", | ||
.owner = THIS_MODULE, | ||
}, | ||
}; | ||
|
||
module_platform_driver(adc_jack_driver); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* include/linux/extcon/extcon-adc-jack.h | ||
* | ||
* Analog Jack extcon driver with ADC-based detection capability. | ||
* | ||
* Copyright (C) 2012 Samsung Electronics | ||
* MyungJoo Ham <myungjoo.ham@samsung.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
*/ | ||
|
||
#ifndef _EXTCON_ADC_JACK_H_ | ||
#define _EXTCON_ADC_JACK_H_ __FILE__ | ||
|
||
#include <linux/module.h> | ||
#include <linux/extcon.h> | ||
|
||
/** | ||
* struct adc_jack_cond - condition to use an extcon state | ||
* @state - the corresponding extcon state (if 0, this struct denotes | ||
* the last adc_jack_cond element among the array) | ||
* @min_adc - min adc value for this condition | ||
* @max_adc - max adc value for this condition | ||
* | ||
* For example, if { .state = 0x3, .min_adc = 100, .max_adc = 200}, it means | ||
* that if ADC value is between (inclusive) 100 and 200, than the cable 0 and | ||
* 1 are attached (1<<0 | 1<<1 == 0x3) | ||
* | ||
* Note that you don't need to describe condition for "no cable attached" | ||
* because when no adc_jack_cond is met, state = 0 is automatically chosen. | ||
*/ | ||
struct adc_jack_cond { | ||
u32 state; /* extcon state value. 0 if invalid */ | ||
u32 min_adc; | ||
u32 max_adc; | ||
}; | ||
|
||
/** | ||
* struct adc_jack_pdata - platform data for adc jack device. | ||
* @name - name of the extcon device. If null, "adc-jack" is used. | ||
* @consumer_channel - Unique name to identify the channel on the consumer | ||
* side. This typically describes the channels used within | ||
* the consumer. E.g. 'battery_voltage' | ||
* @cable_names - array of cable names ending with null. | ||
* @adc_contitions - array of struct adc_jack_cond conditions ending | ||
* with .state = 0 entry. This describes how to decode | ||
* adc values into extcon state. | ||
* @irq_flags - irq flags used for the @irq | ||
* @handling_delay_ms - in some devices, we need to read ADC value some | ||
* milli-seconds after the interrupt occurs. You may | ||
* describe such delays with @handling_delay_ms, which | ||
* is rounded-off by jiffies. | ||
*/ | ||
struct adc_jack_pdata { | ||
const char *name; | ||
const char *consumer_channel; | ||
/* | ||
* The last entry should be NULL | ||
*/ | ||
const char **cable_names; | ||
/* The last entry's state should be 0 */ | ||
struct adc_jack_cond *adc_conditions; | ||
|
||
unsigned long irq_flags; | ||
unsigned long handling_delay_ms; /* in ms */ | ||
}; | ||
|
||
#endif /* _EXTCON_ADC_JACK_H */ |