mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge tag 'driver-core-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core changes from Greg Kroah-Hartman: "Here's the big driver core pull request for 3.6-rc1. Unlike 3.5, this kernel should be a lot tamer, with the printk changes now settled down. All we have here is some extcon driver updates, w1 driver updates, a few printk cleanups that weren't needed for 3.5, but are good to have now, and some other minor fixes/changes in the driver core. All of these have been in the linux-next releases for a while now. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'driver-core-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (38 commits) printk: Export struct log size and member offsets through vmcoreinfo Drivers: hv: Change the hex constant to a decimal constant driver core: don't trigger uevent after failure extcon: MAX77693: Add extcon-max77693 driver to support Maxim MAX77693 MUIC device sysfs: fail dentry revalidation after namespace change fix sysfs: fail dentry revalidation after namespace change extcon: spelling of detach in function doc extcon: arizona: Stop microphone detection if we give up on it extcon: arizona: Update cable reporting calls and split headset PM / Runtime: Do not increment device usage counts before probing kmsg - do not flush partial lines when the console is busy kmsg - export "continuation record" flag to /dev/kmsg kmsg - avoid warning for CONFIG_PRINTK=n compilations kmsg - properly print over-long continuation lines driver-core: Use kobj_to_dev instead of re-implementing it driver-core: Move kobj_to_dev from genhd.h to device.h driver core: Move deferred devices to the end of dpm_list before probing driver core: move uevent call to driver_register driver core: fix shutdown races with probe/remove(v3) Extcon: Arizona: Add driver for Wolfson Arizona class devices ...
This commit is contained in:
15
Documentation/ABI/stable/sysfs-driver-w1_ds28e04
Normal file
15
Documentation/ABI/stable/sysfs-driver-w1_ds28e04
Normal file
@@ -0,0 +1,15 @@
|
||||
What: /sys/bus/w1/devices/.../pio
|
||||
Date: May 2012
|
||||
Contact: Markus Franke <franm@hrz.tu-chemnitz.de>
|
||||
Description: read/write the contents of the two PIO's of the DS28E04-100
|
||||
see Documentation/w1/slaves/w1_ds28e04 for detailed information
|
||||
Users: any user space application which wants to communicate with DS28E04-100
|
||||
|
||||
|
||||
|
||||
What: /sys/bus/w1/devices/.../eeprom
|
||||
Date: May 2012
|
||||
Contact: Markus Franke <franm@hrz.tu-chemnitz.de>
|
||||
Description: read/write the contents of the EEPROM memory of the DS28E04-100
|
||||
see Documentation/w1/slaves/w1_ds28e04 for detailed information
|
||||
Users: any user space application which wants to communicate with DS28E04-100
|
||||
@@ -58,16 +58,18 @@ Description: The /dev/kmsg character device node provides userspace access
|
||||
|
||||
The output format consists of a prefix carrying the syslog
|
||||
prefix including priority and facility, the 64 bit message
|
||||
sequence number and the monotonic timestamp in microseconds.
|
||||
The values are separated by a ','. Future extensions might
|
||||
add more comma separated values before the terminating ';'.
|
||||
Unknown values should be gracefully ignored.
|
||||
sequence number and the monotonic timestamp in microseconds,
|
||||
and a flag field. All fields are separated by a ','.
|
||||
|
||||
Future extensions might add more comma separated values before
|
||||
the terminating ';'. Unknown fields and values should be
|
||||
gracefully ignored.
|
||||
|
||||
The human readable text string starts directly after the ';'
|
||||
and is terminated by a '\n'. Untrusted values derived from
|
||||
hardware or other facilities are printed, therefore
|
||||
all non-printable characters in the log message are escaped
|
||||
by "\x00" C-style hex encoding.
|
||||
all non-printable characters and '\' itself in the log message
|
||||
are escaped by "\x00" C-style hex encoding.
|
||||
|
||||
A line starting with ' ', is a continuation line, adding
|
||||
key/value pairs to the log message, which provide the machine
|
||||
@@ -75,11 +77,11 @@ Description: The /dev/kmsg character device node provides userspace access
|
||||
userspace.
|
||||
|
||||
Example:
|
||||
7,160,424069;pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] (ignored)
|
||||
7,160,424069,-;pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] (ignored)
|
||||
SUBSYSTEM=acpi
|
||||
DEVICE=+acpi:PNP0A03:00
|
||||
6,339,5140900;NET: Registered protocol family 10
|
||||
30,340,5690716;udevd[80]: starting version 181
|
||||
6,339,5140900,-;NET: Registered protocol family 10
|
||||
30,340,5690716,-;udevd[80]: starting version 181
|
||||
|
||||
The DEVICE= key uniquely identifies devices the following way:
|
||||
b12:8 - block dev_t
|
||||
@@ -87,4 +89,13 @@ Description: The /dev/kmsg character device node provides userspace access
|
||||
n8 - netdev ifindex
|
||||
+sound:card0 - subsystem:devname
|
||||
|
||||
The flags field carries '-' by default. A 'c' indicates a
|
||||
fragment of a line. All following fragments are flagged with
|
||||
'+'. Note, that these hints about continuation lines are not
|
||||
neccessarily correct, and the stream could be interleaved with
|
||||
unrelated messages, but merging the lines in the output
|
||||
usually produces better human readable results. A similar
|
||||
logic is used internally when messages are printed to the
|
||||
console, /proc/kmsg or the syslog() syscall.
|
||||
|
||||
Users: dmesg(1), userspace kernel log consumers
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Everything you ever wanted to know about Linux 2.6 -stable releases.
|
||||
Everything you ever wanted to know about Linux -stable releases.
|
||||
|
||||
Rules on what kind of patches are accepted, and which ones are not, into the
|
||||
"-stable" tree:
|
||||
@@ -42,10 +42,10 @@ Procedure for submitting patches to the -stable tree:
|
||||
cherry-picked than this can be specified in the following format in
|
||||
the sign-off area:
|
||||
|
||||
Cc: <stable@vger.kernel.org> # .32.x: a1f84a3: sched: Check for idle
|
||||
Cc: <stable@vger.kernel.org> # .32.x: 1b9508f: sched: Rate-limit newidle
|
||||
Cc: <stable@vger.kernel.org> # .32.x: fd21073: sched: Fix affinity logic
|
||||
Cc: <stable@vger.kernel.org> # .32.x
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
|
||||
Cc: <stable@vger.kernel.org> # 3.3.x
|
||||
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||||
|
||||
The tag sequence has the meaning of:
|
||||
@@ -79,6 +79,15 @@ Review cycle:
|
||||
security kernel team, and not go through the normal review cycle.
|
||||
Contact the kernel security team for more details on this procedure.
|
||||
|
||||
Trees:
|
||||
|
||||
- The queues of patches, for both completed versions and in progress
|
||||
versions can be found at:
|
||||
http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git
|
||||
- The finalized and tagged releases of all stable kernels can be found
|
||||
in separate branches per version at:
|
||||
http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git
|
||||
|
||||
|
||||
Review committee:
|
||||
|
||||
|
||||
36
Documentation/w1/slaves/w1_ds28e04
Normal file
36
Documentation/w1/slaves/w1_ds28e04
Normal file
@@ -0,0 +1,36 @@
|
||||
Kernel driver w1_ds28e04
|
||||
========================
|
||||
|
||||
Supported chips:
|
||||
* Maxim DS28E04-100 4096-Bit Addressable 1-Wire EEPROM with PIO
|
||||
|
||||
supported family codes:
|
||||
W1_FAMILY_DS28E04 0x1C
|
||||
|
||||
Author: Markus Franke, <franke.m@sebakmt.com> <franm@hrz.tu-chemnitz.de>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Support is provided through the sysfs files "eeprom" and "pio". CRC checking
|
||||
during memory accesses can optionally be enabled/disabled via the device
|
||||
attribute "crccheck". The strong pull-up can optionally be enabled/disabled
|
||||
via the module parameter "w1_strong_pullup".
|
||||
|
||||
Memory Access
|
||||
|
||||
A read operation on the "eeprom" file reads the given amount of bytes
|
||||
from the EEPROM of the DS28E04.
|
||||
|
||||
A write operation on the "eeprom" file writes the given byte sequence
|
||||
to the EEPROM of the DS28E04. If CRC checking mode is enabled only
|
||||
fully alligned blocks of 32 bytes with valid CRC16 values (in bytes 30
|
||||
and 31) are allowed to be written.
|
||||
|
||||
PIO Access
|
||||
|
||||
The 2 PIOs of the DS28E04-100 are accessible via the "pio" sysfs file.
|
||||
|
||||
The current status of the PIO's is returned as an 8 bit value. Bit 0/1
|
||||
represent the state of PIO_0/PIO_1. Bits 2..7 do not care. The PIO's are
|
||||
driven low-active, i.e. the driver delivers/expects low-active values.
|
||||
@@ -2728,6 +2728,14 @@ M: Mimi Zohar <zohar@us.ibm.com>
|
||||
S: Supported
|
||||
F: security/integrity/evm/
|
||||
|
||||
EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
|
||||
M: MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
M: Chanwoo Choi <cw00.choi@samsung.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/extcon/
|
||||
F: Documentation/extcon/
|
||||
|
||||
EXYNOS DP DRIVER
|
||||
M: Jingoo Han <jg1.han@samsung.com>
|
||||
L: linux-fbdev@vger.kernel.org
|
||||
|
||||
@@ -743,7 +743,6 @@ int bus_add_driver(struct device_driver *drv)
|
||||
}
|
||||
}
|
||||
|
||||
kobject_uevent(&priv->kobj, KOBJ_ADD);
|
||||
return 0;
|
||||
|
||||
out_unregister:
|
||||
|
||||
@@ -85,14 +85,13 @@ const char *dev_driver_string(const struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(dev_driver_string);
|
||||
|
||||
#define to_dev(obj) container_of(obj, struct device, kobj)
|
||||
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
|
||||
|
||||
static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct device_attribute *dev_attr = to_dev_attr(attr);
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
ssize_t ret = -EIO;
|
||||
|
||||
if (dev_attr->show)
|
||||
@@ -108,7 +107,7 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct device_attribute *dev_attr = to_dev_attr(attr);
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
ssize_t ret = -EIO;
|
||||
|
||||
if (dev_attr->store)
|
||||
@@ -182,7 +181,7 @@ EXPORT_SYMBOL_GPL(device_show_int);
|
||||
*/
|
||||
static void device_release(struct kobject *kobj)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct device_private *p = dev->p;
|
||||
|
||||
if (dev->release)
|
||||
@@ -200,7 +199,7 @@ static void device_release(struct kobject *kobj)
|
||||
|
||||
static const void *device_namespace(struct kobject *kobj)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
const void *ns = NULL;
|
||||
|
||||
if (dev->class && dev->class->ns_type)
|
||||
@@ -221,7 +220,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
|
||||
struct kobj_type *ktype = get_ktype(kobj);
|
||||
|
||||
if (ktype == &device_ktype) {
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
if (dev->bus)
|
||||
return 1;
|
||||
if (dev->class)
|
||||
@@ -232,7 +231,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
|
||||
|
||||
static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
|
||||
if (dev->bus)
|
||||
return dev->bus->name;
|
||||
@@ -244,7 +243,7 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
|
||||
static int dev_uevent(struct kset *kset, struct kobject *kobj,
|
||||
struct kobj_uevent_env *env)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
int retval = 0;
|
||||
|
||||
/* add device node properties if present */
|
||||
@@ -1132,7 +1131,7 @@ int device_register(struct device *dev)
|
||||
*/
|
||||
struct device *get_device(struct device *dev)
|
||||
{
|
||||
return dev ? to_dev(kobject_get(&dev->kobj)) : NULL;
|
||||
return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1754,25 +1753,25 @@ int device_move(struct device *dev, struct device *new_parent,
|
||||
set_dev_node(dev, dev_to_node(new_parent));
|
||||
}
|
||||
|
||||
if (!dev->class)
|
||||
goto out_put;
|
||||
error = device_move_class_links(dev, old_parent, new_parent);
|
||||
if (error) {
|
||||
/* We ignore errors on cleanup since we're hosed anyway... */
|
||||
device_move_class_links(dev, new_parent, old_parent);
|
||||
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
|
||||
if (new_parent)
|
||||
klist_remove(&dev->p->knode_parent);
|
||||
dev->parent = old_parent;
|
||||
if (old_parent) {
|
||||
klist_add_tail(&dev->p->knode_parent,
|
||||
&old_parent->p->klist_children);
|
||||
set_dev_node(dev, dev_to_node(old_parent));
|
||||
if (dev->class) {
|
||||
error = device_move_class_links(dev, old_parent, new_parent);
|
||||
if (error) {
|
||||
/* We ignore errors on cleanup since we're hosed anyway... */
|
||||
device_move_class_links(dev, new_parent, old_parent);
|
||||
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
|
||||
if (new_parent)
|
||||
klist_remove(&dev->p->knode_parent);
|
||||
dev->parent = old_parent;
|
||||
if (old_parent) {
|
||||
klist_add_tail(&dev->p->knode_parent,
|
||||
&old_parent->p->klist_children);
|
||||
set_dev_node(dev, dev_to_node(old_parent));
|
||||
}
|
||||
}
|
||||
cleanup_glue_dir(dev, new_parent_kobj);
|
||||
put_device(new_parent);
|
||||
goto out;
|
||||
}
|
||||
cleanup_glue_dir(dev, new_parent_kobj);
|
||||
put_device(new_parent);
|
||||
goto out;
|
||||
}
|
||||
switch (dpm_order) {
|
||||
case DPM_ORDER_NONE:
|
||||
@@ -1787,7 +1786,7 @@ int device_move(struct device *dev, struct device *new_parent,
|
||||
device_pm_move_last(dev);
|
||||
break;
|
||||
}
|
||||
out_put:
|
||||
|
||||
put_device(old_parent);
|
||||
out:
|
||||
device_pm_unlock();
|
||||
@@ -1812,6 +1811,13 @@ void device_shutdown(void)
|
||||
while (!list_empty(&devices_kset->list)) {
|
||||
dev = list_entry(devices_kset->list.prev, struct device,
|
||||
kobj.entry);
|
||||
|
||||
/*
|
||||
* hold reference count of device's parent to
|
||||
* prevent it from being freed because parent's
|
||||
* lock is to be held
|
||||
*/
|
||||
get_device(dev->parent);
|
||||
get_device(dev);
|
||||
/*
|
||||
* Make sure the device is off the kset list, in the
|
||||
@@ -1820,6 +1826,11 @@ void device_shutdown(void)
|
||||
list_del_init(&dev->kobj.entry);
|
||||
spin_unlock(&devices_kset->list_lock);
|
||||
|
||||
/* hold lock to avoid race with probe/release */
|
||||
if (dev->parent)
|
||||
device_lock(dev->parent);
|
||||
device_lock(dev);
|
||||
|
||||
/* Don't allow any more runtime suspends */
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_barrier(dev);
|
||||
@@ -1831,7 +1842,13 @@ void device_shutdown(void)
|
||||
dev_dbg(dev, "shutdown\n");
|
||||
dev->driver->shutdown(dev);
|
||||
}
|
||||
|
||||
device_unlock(dev);
|
||||
if (dev->parent)
|
||||
device_unlock(dev->parent);
|
||||
|
||||
put_device(dev);
|
||||
put_device(dev->parent);
|
||||
|
||||
spin_lock(&devices_kset->list_lock);
|
||||
}
|
||||
|
||||
@@ -85,8 +85,20 @@ static void deferred_probe_work_func(struct work_struct *work)
|
||||
* manipulate the deferred list
|
||||
*/
|
||||
mutex_unlock(&deferred_probe_mutex);
|
||||
|
||||
/*
|
||||
* Force the device to the end of the dpm_list since
|
||||
* the PM code assumes that the order we add things to
|
||||
* the list is a good order for suspend but deferred
|
||||
* probe makes that very unsafe.
|
||||
*/
|
||||
device_pm_lock();
|
||||
device_pm_move_last(dev);
|
||||
device_pm_unlock();
|
||||
|
||||
dev_dbg(dev, "Retrying from deferred list\n");
|
||||
bus_probe_device(dev);
|
||||
|
||||
mutex_lock(&deferred_probe_mutex);
|
||||
|
||||
put_device(dev);
|
||||
@@ -283,6 +295,7 @@ probe_failed:
|
||||
devres_release_all(dev);
|
||||
driver_sysfs_remove(dev);
|
||||
dev->driver = NULL;
|
||||
dev_set_drvdata(dev, NULL);
|
||||
|
||||
if (ret == -EPROBE_DEFER) {
|
||||
/* Driver requested deferred probing */
|
||||
@@ -356,10 +369,9 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
|
||||
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
|
||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_barrier(dev);
|
||||
ret = really_probe(dev, drv);
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_idle(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -406,9 +418,8 @@ int device_attach(struct device *dev)
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
pm_runtime_get_noresume(dev);
|
||||
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_idle(dev);
|
||||
}
|
||||
out_unlock:
|
||||
device_unlock(dev);
|
||||
@@ -487,6 +498,7 @@ static void __device_release_driver(struct device *dev)
|
||||
drv->remove(dev);
|
||||
devres_release_all(dev);
|
||||
dev->driver = NULL;
|
||||
dev_set_drvdata(dev, NULL);
|
||||
klist_remove(&dev->p->knode_driver);
|
||||
if (dev->bus)
|
||||
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
|
||||
|
||||
@@ -493,6 +493,7 @@ EXPORT_SYMBOL_GPL(dma_buf_vmap);
|
||||
/**
|
||||
* dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap.
|
||||
* @dmabuf: [in] buffer to vunmap
|
||||
* @vaddr: [in] vmap to vunmap
|
||||
*/
|
||||
void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
|
||||
{
|
||||
|
||||
@@ -186,6 +186,7 @@ EXPORT_SYMBOL(dma_release_from_coherent);
|
||||
* @vma: vm_area for the userspace memory
|
||||
* @vaddr: cpu address returned by dma_alloc_from_coherent
|
||||
* @size: size of the memory buffer allocated by dma_alloc_from_coherent
|
||||
* @ret: result from remap_pfn_range()
|
||||
*
|
||||
* This checks whether the memory was allocated from the per-device
|
||||
* coherent memory pool and if so, maps that memory to the provided vma.
|
||||
|
||||
@@ -185,8 +185,12 @@ int driver_register(struct device_driver *drv)
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = driver_add_groups(drv, drv->groups);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
bus_remove_driver(drv);
|
||||
return ret;
|
||||
}
|
||||
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(driver_register);
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#define to_dev(obj) container_of(obj, struct device, kobj)
|
||||
|
||||
MODULE_AUTHOR("Manuel Estrada Sainz");
|
||||
MODULE_DESCRIPTION("Multi purpose firmware loading support");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -290,7 +288,7 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t offset, size_t count)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct firmware_priv *fw_priv = to_firmware_priv(dev);
|
||||
struct firmware *fw;
|
||||
ssize_t ret_count;
|
||||
@@ -384,7 +382,7 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t offset, size_t count)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct firmware_priv *fw_priv = to_firmware_priv(dev);
|
||||
struct firmware *fw;
|
||||
ssize_t retval;
|
||||
|
||||
@@ -21,6 +21,16 @@ config EXTCON_GPIO
|
||||
Say Y here to enable GPIO based extcon support. Note that GPIO
|
||||
extcon supports single state per extcon instance.
|
||||
|
||||
config EXTCON_MAX77693
|
||||
tristate "MAX77693 EXTCON Support"
|
||||
depends on MFD_MAX77693
|
||||
select IRQ_DOMAIN
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the MUIC device of
|
||||
Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory
|
||||
detector and switch.
|
||||
|
||||
config EXTCON_MAX8997
|
||||
tristate "MAX8997 EXTCON Support"
|
||||
depends on MFD_MAX8997
|
||||
@@ -29,4 +39,12 @@ config EXTCON_MAX8997
|
||||
Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
|
||||
detector and switch.
|
||||
|
||||
config EXTCON_ARIZONA
|
||||
tristate "Wolfson Arizona EXTCON support"
|
||||
depends on MFD_ARIZONA
|
||||
help
|
||||
Say Y here to enable support for external accessory detection
|
||||
with Wolfson Arizona devices. These are audio CODECs with
|
||||
advanced audio accessory detection support.
|
||||
|
||||
endif # MULTISTATE_SWITCH
|
||||
|
||||
@@ -4,4 +4,6 @@
|
||||
|
||||
obj-$(CONFIG_EXTCON) += extcon_class.o
|
||||
obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o
|
||||
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
|
||||
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
|
||||
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
|
||||
|
||||
490
drivers/extcon/extcon-arizona.c
Normal file
490
drivers/extcon/extcon-arizona.c
Normal file
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* extcon-arizona.c - Extcon driver Wolfson Arizona devices
|
||||
*
|
||||
* Copyright (C) 2012 Wolfson Microelectronics plc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/extcon.h>
|
||||
|
||||
#include <linux/mfd/arizona/core.h>
|
||||
#include <linux/mfd/arizona/pdata.h>
|
||||
#include <linux/mfd/arizona/registers.h>
|
||||
|
||||
struct arizona_extcon_info {
|
||||
struct device *dev;
|
||||
struct arizona *arizona;
|
||||
struct mutex lock;
|
||||
struct regulator *micvdd;
|
||||
|
||||
int micd_mode;
|
||||
const struct arizona_micd_config *micd_modes;
|
||||
int micd_num_modes;
|
||||
|
||||
bool micd_reva;
|
||||
|
||||
bool mic;
|
||||
bool detecting;
|
||||
int jack_flips;
|
||||
|
||||
struct extcon_dev edev;
|
||||
};
|
||||
|
||||
static const struct arizona_micd_config micd_default_modes[] = {
|
||||
{ ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
|
||||
{ 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
|
||||
};
|
||||
|
||||
#define ARIZONA_CABLE_MECHANICAL 0
|
||||
#define ARIZONA_CABLE_MICROPHONE 1
|
||||
#define ARIZONA_CABLE_HEADPHONE 2
|
||||
|
||||
static const char *arizona_cable[] = {
|
||||
"Mechanical",
|
||||
"Microphone",
|
||||
"Headphone",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
|
||||
{
|
||||
struct arizona *arizona = info->arizona;
|
||||
|
||||
gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
|
||||
info->micd_modes[mode].gpio);
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||
ARIZONA_MICD_BIAS_SRC_MASK,
|
||||
info->micd_modes[mode].bias);
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
|
||||
ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
|
||||
|
||||
info->micd_mode = mode;
|
||||
|
||||
dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
|
||||
}
|
||||
|
||||
static void arizona_start_mic(struct arizona_extcon_info *info)
|
||||
{
|
||||
struct arizona *arizona = info->arizona;
|
||||
bool change;
|
||||
int ret;
|
||||
|
||||
info->detecting = true;
|
||||
info->mic = false;
|
||||
info->jack_flips = 0;
|
||||
|
||||
/* Microphone detection can't use idle mode */
|
||||
pm_runtime_get(info->dev);
|
||||
|
||||
ret = regulator_enable(info->micvdd);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (info->micd_reva) {
|
||||
regmap_write(arizona->regmap, 0x80, 0x3);
|
||||
regmap_write(arizona->regmap, 0x294, 0);
|
||||
regmap_write(arizona->regmap, 0x80, 0x0);
|
||||
}
|
||||
|
||||
regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||
ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
|
||||
&change);
|
||||
if (!change) {
|
||||
regulator_disable(info->micvdd);
|
||||
pm_runtime_put_autosuspend(info->dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void arizona_stop_mic(struct arizona_extcon_info *info)
|
||||
{
|
||||
struct arizona *arizona = info->arizona;
|
||||
bool change;
|
||||
|
||||
regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||
ARIZONA_MICD_ENA, 0,
|
||||
&change);
|
||||
|
||||
if (info->micd_reva) {
|
||||
regmap_write(arizona->regmap, 0x80, 0x3);
|
||||
regmap_write(arizona->regmap, 0x294, 2);
|
||||
regmap_write(arizona->regmap, 0x80, 0x0);
|
||||
}
|
||||
|
||||
if (change) {
|
||||
regulator_disable(info->micvdd);
|
||||
pm_runtime_put_autosuspend(info->dev);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t arizona_micdet(int irq, void *data)
|
||||
{
|
||||
struct arizona_extcon_info *info = data;
|
||||
struct arizona *arizona = info->arizona;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
dev_dbg(arizona->dev, "MICDET: %x\n", val);
|
||||
|
||||
if (!(val & ARIZONA_MICD_VALID)) {
|
||||
dev_warn(arizona->dev, "Microphone detection state invalid\n");
|
||||
mutex_unlock(&info->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Due to jack detect this should never happen */
|
||||
if (!(val & ARIZONA_MICD_STS)) {
|
||||
dev_warn(arizona->dev, "Detected open circuit\n");
|
||||
info->detecting = false;
|
||||
goto handled;
|
||||
}
|
||||
|
||||
/* If we got a high impedence we should have a headset, report it. */
|
||||
if (info->detecting && (val & 0x400)) {
|
||||
ret = extcon_update_state(&info->edev,
|
||||
1 << ARIZONA_CABLE_MICROPHONE |
|
||||
1 << ARIZONA_CABLE_HEADPHONE,
|
||||
1 << ARIZONA_CABLE_MICROPHONE |
|
||||
1 << ARIZONA_CABLE_HEADPHONE);
|
||||
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev, "Headset report failed: %d\n",
|
||||
ret);
|
||||
|
||||
info->mic = true;
|
||||
info->detecting = false;
|
||||
goto handled;
|
||||
}
|
||||
|
||||
/* If we detected a lower impedence during initial startup
|
||||
* then we probably have the wrong polarity, flip it. Don't
|
||||
* do this for the lowest impedences to speed up detection of
|
||||
* plain headphones. If both polarities report a low
|
||||
* impedence then give up and report headphones.
|
||||
*/
|
||||
if (info->detecting && (val & 0x3f8)) {
|
||||
info->jack_flips++;
|
||||
|
||||
if (info->jack_flips >= info->micd_num_modes) {
|
||||
dev_dbg(arizona->dev, "Detected headphone\n");
|
||||
info->detecting = false;
|
||||
arizona_stop_mic(info);
|
||||
|
||||
ret = extcon_set_cable_state_(&info->edev,
|
||||
ARIZONA_CABLE_HEADPHONE,
|
||||
true);
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev,
|
||||
"Headphone report failed: %d\n",
|
||||
ret);
|
||||
} else {
|
||||
info->micd_mode++;
|
||||
if (info->micd_mode == info->micd_num_modes)
|
||||
info->micd_mode = 0;
|
||||
arizona_extcon_set_mode(info, info->micd_mode);
|
||||
|
||||
info->jack_flips++;
|
||||
}
|
||||
|
||||
goto handled;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're still detecting and we detect a short then we've
|
||||
* got a headphone. Otherwise it's a button press, the
|
||||
* button reporting is stubbed out for now.
|
||||
*/
|
||||
if (val & 0x3fc) {
|
||||
if (info->mic) {
|
||||
dev_dbg(arizona->dev, "Mic button detected\n");
|
||||
|
||||
} else if (info->detecting) {
|
||||
dev_dbg(arizona->dev, "Headphone detected\n");
|
||||
info->detecting = false;
|
||||
arizona_stop_mic(info);
|
||||
|
||||
ret = extcon_set_cable_state_(&info->edev,
|
||||
ARIZONA_CABLE_HEADPHONE,
|
||||
true);
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev,
|
||||
"Headphone report failed: %d\n",
|
||||
ret);
|
||||
} else {
|
||||
dev_warn(arizona->dev, "Button with no mic: %x\n",
|
||||
val);
|
||||
}
|
||||
} else {
|
||||
dev_dbg(arizona->dev, "Mic button released\n");
|
||||
}
|
||||
|
||||
handled:
|
||||
pm_runtime_mark_last_busy(info->dev);
|
||||
mutex_unlock(&info->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t arizona_jackdet(int irq, void *data)
|
||||
{
|
||||
struct arizona_extcon_info *info = data;
|
||||
struct arizona *arizona = info->arizona;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(info->dev);
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
|
||||
ret);
|
||||
mutex_unlock(&info->lock);
|
||||
pm_runtime_put_autosuspend(info->dev);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (val & ARIZONA_JD1_STS) {
|
||||
dev_dbg(arizona->dev, "Detected jack\n");
|
||||
ret = extcon_set_cable_state_(&info->edev,
|
||||
ARIZONA_CABLE_MECHANICAL, true);
|
||||
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev, "Mechanical report failed: %d\n",
|
||||
ret);
|
||||
|
||||
arizona_start_mic(info);
|
||||
} else {
|
||||
dev_dbg(arizona->dev, "Detected jack removal\n");
|
||||
|
||||
arizona_stop_mic(info);
|
||||
|
||||
ret = extcon_update_state(&info->edev, 0xffffffff, 0);
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev, "Removal report failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
mutex_unlock(&info->lock);
|
||||
|
||||
pm_runtime_mark_last_busy(info->dev);
|
||||
pm_runtime_put_autosuspend(info->dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit arizona_extcon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
|
||||
struct arizona_pdata *pdata;
|
||||
struct arizona_extcon_info *info;
|
||||
int ret, mode;
|
||||
|
||||
pdata = dev_get_platdata(arizona->dev);
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
|
||||
if (IS_ERR(info->micvdd)) {
|
||||
ret = PTR_ERR(info->micvdd);
|
||||
dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mutex_init(&info->lock);
|
||||
info->arizona = arizona;
|
||||
info->dev = &pdev->dev;
|
||||
info->detecting = true;
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
switch (arizona->type) {
|
||||
case WM5102:
|
||||
switch (arizona->rev) {
|
||||
case 0:
|
||||
info->micd_reva = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
info->edev.name = "Headset Jack";
|
||||
info->edev.supported_cable = arizona_cable;
|
||||
|
||||
ret = extcon_dev_register(&info->edev, arizona->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(arizona->dev, "extcon_dev_regster() failed: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pdata->num_micd_configs) {
|
||||
info->micd_modes = pdata->micd_configs;
|
||||
info->micd_num_modes = pdata->num_micd_configs;
|
||||
} else {
|
||||
info->micd_modes = micd_default_modes;
|
||||
info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
|
||||
}
|
||||
|
||||
if (arizona->pdata.micd_pol_gpio > 0) {
|
||||
if (info->micd_modes[0].gpio)
|
||||
mode = GPIOF_OUT_INIT_HIGH;
|
||||
else
|
||||
mode = GPIOF_OUT_INIT_LOW;
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
arizona->pdata.micd_pol_gpio,
|
||||
mode,
|
||||
"MICD polarity");
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
|
||||
arizona->pdata.micd_pol_gpio, ret);
|
||||
goto err_register;
|
||||
}
|
||||
}
|
||||
|
||||
arizona_extcon_set_mode(info, 0);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_RISE,
|
||||
"JACKDET rise", arizona_jackdet, info);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
|
||||
ret);
|
||||
goto err_register;
|
||||
}
|
||||
|
||||
ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
|
||||
ret);
|
||||
goto err_rise;
|
||||
}
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_FALL,
|
||||
"JACKDET fall", arizona_jackdet, info);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
|
||||
goto err_rise_wake;
|
||||
}
|
||||
|
||||
ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
|
||||
ret);
|
||||
goto err_fall;
|
||||
}
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
|
||||
"MICDET", arizona_micdet, info);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
|
||||
goto err_fall_wake;
|
||||
}
|
||||
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||
ARIZONA_MICD_BIAS_STARTTIME_MASK |
|
||||
ARIZONA_MICD_RATE_MASK,
|
||||
7 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT |
|
||||
8 << ARIZONA_MICD_RATE_SHIFT);
|
||||
|
||||
arizona_clk32k_enable(arizona);
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
|
||||
ARIZONA_JD1_DB, ARIZONA_JD1_DB);
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
|
||||
ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_fall_wake:
|
||||
arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0);
|
||||
err_fall:
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info);
|
||||
err_rise_wake:
|
||||
arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
|
||||
err_rise:
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
|
||||
err_register:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
extcon_dev_unregister(&info->edev);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit arizona_extcon_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct arizona_extcon_info *info = platform_get_drvdata(pdev);
|
||||
struct arizona *arizona = info->arizona;
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
|
||||
arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0);
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info);
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
|
||||
ARIZONA_JD1_ENA, 0);
|
||||
arizona_clk32k_disable(arizona);
|
||||
extcon_dev_unregister(&info->edev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver arizona_extcon_driver = {
|
||||
.driver = {
|
||||
.name = "arizona-extcon",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = arizona_extcon_probe,
|
||||
.remove = __devexit_p(arizona_extcon_remove),
|
||||
};
|
||||
|
||||
module_platform_driver(arizona_extcon_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Arizona Extcon driver");
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:extcon-arizona");
|
||||
779
drivers/extcon/extcon-max77693.c
Normal file
779
drivers/extcon/extcon-max77693.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -65,7 +65,7 @@ const char *extcon_cable_name[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct class *extcon_class;
|
||||
static struct class *extcon_class;
|
||||
#if defined(CONFIG_ANDROID)
|
||||
static struct class_compat *switch_class;
|
||||
#endif /* CONFIG_ANDROID */
|
||||
|
||||
@@ -105,25 +105,25 @@ static int __devinit gpio_extcon_probe(struct platform_device *pdev)
|
||||
|
||||
ret = extcon_dev_register(&extcon_data->edev, &pdev->dev);
|
||||
if (ret < 0)
|
||||
goto err_extcon_dev_register;
|
||||
return ret;
|
||||
|
||||
ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
|
||||
if (ret < 0)
|
||||
goto err_request_gpio;
|
||||
goto err;
|
||||
|
||||
INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
|
||||
|
||||
extcon_data->irq = gpio_to_irq(extcon_data->gpio);
|
||||
if (extcon_data->irq < 0) {
|
||||
ret = extcon_data->irq;
|
||||
goto err_detect_irq_num_failed;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
|
||||
pdata->irq_flags, pdev->name,
|
||||
extcon_data);
|
||||
if (ret < 0)
|
||||
goto err_request_irq;
|
||||
goto err;
|
||||
|
||||
platform_set_drvdata(pdev, extcon_data);
|
||||
/* Perform initial detection */
|
||||
@@ -131,13 +131,8 @@ static int __devinit gpio_extcon_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
err_detect_irq_num_failed:
|
||||
gpio_free(extcon_data->gpio);
|
||||
err_request_gpio:
|
||||
err:
|
||||
extcon_dev_unregister(&extcon_data->edev);
|
||||
err_extcon_dev_register:
|
||||
devm_kfree(&pdev->dev, extcon_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -148,9 +143,7 @@ static int __devexit gpio_extcon_remove(struct platform_device *pdev)
|
||||
|
||||
cancel_delayed_work_sync(&extcon_data->work);
|
||||
free_irq(extcon_data->irq, extcon_data);
|
||||
gpio_free(extcon_data->gpio);
|
||||
extcon_dev_unregister(&extcon_data->edev);
|
||||
devm_kfree(&pdev->dev, extcon_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ enum {
|
||||
#define HV_PRESENT_BIT 0x80000000
|
||||
|
||||
#define HV_LINUX_GUEST_ID_LO 0x00000000
|
||||
#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
|
||||
#define HV_LINUX_GUEST_ID_HI 2976579765
|
||||
#define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
|
||||
HV_LINUX_GUEST_ID_LO)
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ struct ds2780_device_info {
|
||||
struct device *dev;
|
||||
struct power_supply bat;
|
||||
struct device *w1_dev;
|
||||
struct task_struct *mutex_holder;
|
||||
};
|
||||
|
||||
enum current_types {
|
||||
@@ -64,10 +63,7 @@ static inline struct power_supply *to_power_supply(struct device *dev)
|
||||
static inline int ds2780_battery_io(struct ds2780_device_info *dev_info,
|
||||
char *buf, int addr, size_t count, int io)
|
||||
{
|
||||
if (dev_info->mutex_holder == current)
|
||||
return w1_ds2780_io_nolock(dev_info->w1_dev, buf, addr, count, io);
|
||||
else
|
||||
return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
|
||||
return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
|
||||
}
|
||||
|
||||
static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val,
|
||||
@@ -779,7 +775,6 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
|
||||
dev_info->bat.properties = ds2780_battery_props;
|
||||
dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props);
|
||||
dev_info->bat.get_property = ds2780_battery_get_property;
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
ret = power_supply_register(&pdev->dev, &dev_info->bat);
|
||||
if (ret) {
|
||||
@@ -809,8 +804,6 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
|
||||
goto fail_remove_bin_file;
|
||||
}
|
||||
|
||||
dev_info->mutex_holder = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_bin_file:
|
||||
@@ -830,8 +823,6 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
|
||||
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
/* remove attributes */
|
||||
sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user