mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
Merge 3.5-rc7 into driver-core-next
This pulls in the printk fixes to the driver-core-next branch. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
commit
28a78e46f0
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
|
@ -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.
|
@ -2709,6 +2709,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,8 +1753,7 @@ 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;
|
||||
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... */
|
||||
@ -1774,6 +1772,7 @@ int device_move(struct device *dev, struct device *new_parent,
|
||||
put_device(new_parent);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
switch (dpm_order) {
|
||||
case DPM_ORDER_NONE:
|
||||
break;
|
||||
@ -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 */
|
||||
@ -487,6 +500,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.
|
||||
|
@ -187,6 +187,9 @@ int driver_register(struct device_driver *drv)
|
||||
ret = driver_add_groups(drv, drv->groups);
|
||||
if (ret)
|
||||
bus_remove_driver(drv);
|
||||
|
||||
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;
|
||||
|
@ -29,4 +29,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
|
||||
|
@ -5,3 +5,4 @@
|
||||
obj-$(CONFIG_EXTCON) += extcon_class.o
|
||||
obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o
|
||||
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
|
||||
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
|
||||
|
491
drivers/extcon/extcon-arizona.c
Normal file
491
drivers/extcon/extcon-arizona.c
Normal file
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* 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 "Mechanical"
|
||||
#define ARIZONA_CABLE_HEADPHONE "Headphone"
|
||||
#define ARIZONA_CABLE_HEADSET "Headset"
|
||||
|
||||
static const char *arizona_cable[] = {
|
||||
ARIZONA_CABLE_MECHANICAL,
|
||||
ARIZONA_CABLE_HEADSET,
|
||||
ARIZONA_CABLE_HEADPHONE,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const u32 arizona_exclusions[] = {
|
||||
0x6, /* Headphone and headset */
|
||||
0,
|
||||
};
|
||||
|
||||
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_set_cable_state(&info->edev,
|
||||
ARIZONA_CABLE_HEADSET, true);
|
||||
|
||||
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;
|
||||
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;
|
||||
info->edev.mutually_exclusive = arizona_exclusions;
|
||||
|
||||
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");
|
@ -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;
|
||||
}
|
||||
|
@ -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,9 +63,6 @@ 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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
@ -37,7 +37,6 @@ struct ds2781_device_info {
|
||||
struct device *dev;
|
||||
struct power_supply bat;
|
||||
struct device *w1_dev;
|
||||
struct task_struct *mutex_holder;
|
||||
};
|
||||
|
||||
enum current_types {
|
||||
@ -62,10 +61,6 @@ static inline struct power_supply *to_power_supply(struct device *dev)
|
||||
static inline int ds2781_battery_io(struct ds2781_device_info *dev_info,
|
||||
char *buf, int addr, size_t count, int io)
|
||||
{
|
||||
if (dev_info->mutex_holder == current)
|
||||
return w1_ds2781_io_nolock(dev_info->w1_dev, buf, addr,
|
||||
count, io);
|
||||
else
|
||||
return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io);
|
||||
}
|
||||
|
||||
@ -775,7 +770,6 @@ static int __devinit ds2781_battery_probe(struct platform_device *pdev)
|
||||
dev_info->bat.properties = ds2781_battery_props;
|
||||
dev_info->bat.num_properties = ARRAY_SIZE(ds2781_battery_props);
|
||||
dev_info->bat.get_property = ds2781_battery_get_property;
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
ret = power_supply_register(&pdev->dev, &dev_info->bat);
|
||||
if (ret) {
|
||||
@ -805,8 +799,6 @@ static int __devinit ds2781_battery_probe(struct platform_device *pdev)
|
||||
goto fail_remove_bin_file;
|
||||
}
|
||||
|
||||
dev_info->mutex_holder = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_bin_file:
|
||||
@ -826,8 +818,6 @@ static int __devexit ds2781_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ds2781_device_info *dev_info = platform_get_drvdata(pdev);
|
||||
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
/* remove attributes */
|
||||
sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group);
|
||||
|
||||
|
@ -334,7 +334,9 @@ static void ds1wm_search(void *data, struct w1_master *master_dev,
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&master_dev->bus_mutex);
|
||||
if (ds1wm_reset(ds1wm_data)) {
|
||||
mutex_unlock(&master_dev->bus_mutex);
|
||||
dev_dbg(&ds1wm_data->pdev->dev,
|
||||
"pass: %d reset error (or no slaves)\n", pass);
|
||||
break;
|
||||
@ -387,6 +389,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev,
|
||||
|
||||
}
|
||||
if (ds1wm_data->read_error) {
|
||||
mutex_unlock(&master_dev->bus_mutex);
|
||||
dev_err(&ds1wm_data->pdev->dev,
|
||||
"pass: %d read error, retrying\n", pass);
|
||||
break;
|
||||
@ -400,6 +403,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev,
|
||||
dev_dbg(&ds1wm_data->pdev->dev,
|
||||
"pass: %d resetting bus\n", pass);
|
||||
ds1wm_reset(ds1wm_data);
|
||||
mutex_unlock(&master_dev->bus_mutex);
|
||||
if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) {
|
||||
dev_err(&ds1wm_data->pdev->dev,
|
||||
"pass: %d bus error, retrying\n", pass);
|
||||
|
@ -180,6 +180,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
|
||||
hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
|
||||
if (ret == 0) {
|
||||
dev_dbg(hdq_data->dev, "TX wait elapsed\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -187,7 +188,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
|
||||
/* check irqstatus */
|
||||
if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
|
||||
dev_dbg(hdq_data->dev, "timeout waiting for"
|
||||
"TXCOMPLETE/RXCOMPLETE, %x", *status);
|
||||
" TXCOMPLETE/RXCOMPLETE, %x", *status);
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
@ -198,7 +199,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
|
||||
OMAP_HDQ_FLAG_CLEAR, &tmp_status);
|
||||
if (ret) {
|
||||
dev_dbg(hdq_data->dev, "timeout waiting GO bit"
|
||||
"return to zero, %x", tmp_status);
|
||||
" return to zero, %x", tmp_status);
|
||||
}
|
||||
|
||||
out:
|
||||
@ -341,7 +342,7 @@ static int omap_hdq_break(struct hdq_data *hdq_data)
|
||||
&tmp_status);
|
||||
if (ret)
|
||||
dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
|
||||
"return to zero, %x", tmp_status);
|
||||
" return to zero, %x", tmp_status);
|
||||
|
||||
out:
|
||||
mutex_unlock(&hdq_data->hdq_mutex);
|
||||
@ -353,7 +354,6 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 status;
|
||||
unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
|
||||
|
||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
||||
if (ret < 0) {
|
||||
@ -371,22 +371,20 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
|
||||
OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
|
||||
OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
|
||||
/*
|
||||
* The RX comes immediately after TX. It
|
||||
* triggers another interrupt before we
|
||||
* sleep. So we have to wait for RXCOMPLETE bit.
|
||||
* The RX comes immediately after TX.
|
||||
*/
|
||||
while (!(hdq_data->hdq_irqstatus
|
||||
& OMAP_HDQ_INT_STATUS_RXCOMPLETE)
|
||||
&& time_before(jiffies, timeout)) {
|
||||
schedule_timeout_uninterruptible(1);
|
||||
}
|
||||
wait_event_timeout(hdq_wait_queue,
|
||||
(hdq_data->hdq_irqstatus
|
||||
& OMAP_HDQ_INT_STATUS_RXCOMPLETE),
|
||||
OMAP_HDQ_TIMEOUT);
|
||||
|
||||
hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0,
|
||||
OMAP_HDQ_CTRL_STATUS_DIR);
|
||||
status = hdq_data->hdq_irqstatus;
|
||||
/* check irqstatus */
|
||||
if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
|
||||
dev_dbg(hdq_data->dev, "timeout waiting for"
|
||||
"RXCOMPLETE, %x", status);
|
||||
" RXCOMPLETE, %x", status);
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
@ -396,7 +394,7 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
|
||||
out:
|
||||
mutex_unlock(&hdq_data->hdq_mutex);
|
||||
rtn:
|
||||
return 0;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@ -470,7 +468,7 @@ static int omap_hdq_put(struct hdq_data *hdq_data)
|
||||
|
||||
if (0 == hdq_data->hdq_usecount) {
|
||||
dev_dbg(hdq_data->dev, "attempt to decrement use count"
|
||||
"when it is zero");
|
||||
" when it is zero");
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
hdq_data->hdq_usecount--;
|
||||
@ -540,7 +538,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
|
||||
mutex_unlock(&hdq_data->hdq_mutex);
|
||||
|
||||
ret = hdq_write_byte(hdq_data, byte, &status);
|
||||
if (ret == 0) {
|
||||
if (ret < 0) {
|
||||
dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
|
||||
return;
|
||||
}
|
||||
|
@ -94,6 +94,19 @@ config W1_SLAVE_DS2781
|
||||
|
||||
If you are unsure, say N.
|
||||
|
||||
config W1_SLAVE_DS28E04
|
||||
tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
|
||||
depends on W1
|
||||
select CRC16
|
||||
help
|
||||
If you enable this you will have the DS28E04-100
|
||||
chip support.
|
||||
|
||||
Say Y here if you want to use a 1-wire
|
||||
4kb EEPROM with PIO family device (DS28E04).
|
||||
|
||||
If you are unsure, say N.
|
||||
|
||||
config W1_SLAVE_BQ27000
|
||||
tristate "BQ27000 slave support"
|
||||
depends on W1
|
||||
|
@ -12,3 +12,4 @@ obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o
|
||||
obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
|
||||
|
@ -31,10 +31,10 @@ static int w1_bq27000_read(struct device *dev, unsigned int reg)
|
||||
u8 val;
|
||||
struct w1_slave *sl = container_of(dev->parent, struct w1_slave, dev);
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
w1_write_8(sl->master, HDQ_CMD_READ | reg);
|
||||
val = w1_read_8(sl->master);
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -52,11 +52,11 @@ static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
|
||||
if (!buf)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
dev_dbg(&sl->dev, "mutex locked");
|
||||
|
||||
if (w1_reset_select_slave(sl)) {
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
|
||||
w1_write_block(sl->master, wrbuf, 3);
|
||||
*buf = w1_read_8(sl->master);
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
dev_dbg(&sl->dev, "mutex unlocked");
|
||||
return 1;
|
||||
}
|
||||
@ -165,7 +165,7 @@ static ssize_t w1_f29_write_output(
|
||||
return -EFAULT;
|
||||
|
||||
dev_dbg(&sl->dev, "locking mutex for write_output");
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
dev_dbg(&sl->dev, "mutex locked");
|
||||
|
||||
if (w1_reset_select_slave(sl))
|
||||
@ -200,14 +200,14 @@ static ssize_t w1_f29_write_output(
|
||||
/* read the result of the READ_PIO_REGS command */
|
||||
if (w1_read_8(sl->master) == *buf) {
|
||||
/* success! */
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
dev_dbg(&sl->dev,
|
||||
"mutex unlocked, retries:%d", retries);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
error:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
|
||||
|
||||
return -EIO;
|
||||
@ -228,7 +228,7 @@ static ssize_t w1_f29_write_activity(
|
||||
if (count != 1 || off != 0)
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
if (w1_reset_select_slave(sl))
|
||||
goto error;
|
||||
@ -236,7 +236,7 @@ static ssize_t w1_f29_write_activity(
|
||||
while (retries--) {
|
||||
w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
|
||||
if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
return 1;
|
||||
}
|
||||
if (w1_reset_resume_command(sl->master))
|
||||
@ -244,7 +244,7 @@ static ssize_t w1_f29_write_activity(
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -263,7 +263,7 @@ static ssize_t w1_f29_write_status_control(
|
||||
if (count != 1 || off != 0)
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
if (w1_reset_select_slave(sl))
|
||||
goto error;
|
||||
@ -285,12 +285,12 @@ static ssize_t w1_f29_write_status_control(
|
||||
w1_write_block(sl->master, w1_buf, 3);
|
||||
if (w1_read_8(sl->master) == *buf) {
|
||||
/* success! */
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
error:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ static ssize_t w1_counter_read(struct device *device,
|
||||
wrbuf[0] = 0xA5;
|
||||
wrbuf[1] = rom_addr & 0xFF;
|
||||
wrbuf[2] = rom_addr >> 8;
|
||||
mutex_lock(&dev->mutex);
|
||||
mutex_lock(&dev->bus_mutex);
|
||||
if (!w1_reset_select_slave(sl)) {
|
||||
w1_write_block(dev, wrbuf, 3);
|
||||
read_byte_count = 0;
|
||||
@ -124,7 +124,7 @@ static ssize_t w1_counter_read(struct device *device,
|
||||
} else {
|
||||
c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error");
|
||||
}
|
||||
mutex_unlock(&dev->mutex);
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
return PAGE_SIZE - c;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ static ssize_t w1_f2d_read_bin(struct file *filp, struct kobject *kobj,
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
/* read directly from the EEPROM in chunks of W1_F2D_READ_MAXLEN */
|
||||
while (todo > 0) {
|
||||
@ -126,7 +126,7 @@ static ssize_t w1_f2d_read_bin(struct file *filp, struct kobject *kobj,
|
||||
off += W1_F2D_READ_MAXLEN;
|
||||
}
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -214,7 +214,7 @@ static ssize_t w1_f2d_write_bin(struct file *filp, struct kobject *kobj,
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
/* Can only write data in blocks of the size of the scratchpad */
|
||||
addr = off;
|
||||
@ -259,7 +259,7 @@ static ssize_t w1_f2d_write_bin(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
|
||||
out_up:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj,
|
||||
if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
|
||||
|
||||
@ -138,7 +138,7 @@ static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj,
|
||||
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
|
||||
|
||||
out_up:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -233,7 +233,7 @@ static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
/* Can only write data to one page at a time */
|
||||
idx = 0;
|
||||
@ -251,7 +251,7 @@ static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
|
||||
out_up:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
if (addr > DS2760_DATA_SIZE || addr < 0) {
|
||||
count = 0;
|
||||
@ -54,7 +54,7 @@ static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -76,14 +76,14 @@ static int w1_ds2760_eeprom_cmd(struct device *dev, int addr, int cmd)
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
if (w1_reset_select_slave(sl) == 0) {
|
||||
w1_write_8(sl->master, cmd);
|
||||
w1_write_8(sl->master, addr);
|
||||
}
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -60,30 +60,16 @@ int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
ret = w1_ds2780_do_io(dev, buf, addr, count, io);
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2780_io);
|
||||
|
||||
int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
ret = w1_ds2780_do_io(dev, buf, addr, count, io);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2780_io_nolock);
|
||||
|
||||
int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
|
||||
{
|
||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
||||
@ -91,14 +77,14 @@ int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
if (w1_reset_select_slave(sl) == 0) {
|
||||
w1_write_8(sl->master, cmd);
|
||||
w1_write_8(sl->master, addr);
|
||||
}
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2780_eeprom_cmd);
|
||||
|
@ -124,8 +124,6 @@
|
||||
|
||||
extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io);
|
||||
extern int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr,
|
||||
size_t count, int io);
|
||||
extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd);
|
||||
|
||||
#endif /* !_W1_DS2780_H */
|
||||
|
@ -58,30 +58,16 @@ int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
ret = w1_ds2781_do_io(dev, buf, addr, count, io);
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2781_io);
|
||||
|
||||
int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
ret = w1_ds2781_do_io(dev, buf, addr, count, io);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2781_io_nolock);
|
||||
|
||||
int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd)
|
||||
{
|
||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
||||
@ -89,14 +75,14 @@ int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd)
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
if (w1_reset_select_slave(sl) == 0) {
|
||||
w1_write_8(sl->master, cmd);
|
||||
w1_write_8(sl->master, addr);
|
||||
}
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2781_eeprom_cmd);
|
||||
|
@ -129,8 +129,6 @@
|
||||
|
||||
extern int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io);
|
||||
extern int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr,
|
||||
size_t count, int io);
|
||||
extern int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd);
|
||||
|
||||
#endif /* !_W1_DS2781_H */
|
||||
|
469
drivers/w1/slaves/w1_ds28e04.c
Normal file
469
drivers/w1/slaves/w1_ds28e04.c
Normal file
@ -0,0 +1,469 @@
|
||||
/*
|
||||
* w1_ds28e04.c - w1 family 1C (DS28E04) driver
|
||||
*
|
||||
* Copyright (c) 2012 Markus Franke <franke.m@sebakmt.com>
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2. See the file COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/crc16.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define CRC16_INIT 0
|
||||
#define CRC16_VALID 0xb001
|
||||
|
||||
#include "../w1.h"
|
||||
#include "../w1_int.h"
|
||||
#include "../w1_family.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Markus Franke <franke.m@sebakmt.com>, <franm@hrz.tu-chemnitz.de>");
|
||||
MODULE_DESCRIPTION("w1 family 1C driver for DS28E04, 4kb EEPROM and PIO");
|
||||
|
||||
/* Allow the strong pullup to be disabled, but default to enabled.
|
||||
* If it was disabled a parasite powered device might not get the required
|
||||
* current to copy the data from the scratchpad to EEPROM. If it is enabled
|
||||
* parasite powered devices have a better chance of getting the current
|
||||
* required.
|
||||
*/
|
||||
static int w1_strong_pullup = 1;
|
||||
module_param_named(strong_pullup, w1_strong_pullup, int, 0);
|
||||
|
||||
/* enable/disable CRC checking on DS28E04-100 memory accesses */
|
||||
static char w1_enable_crccheck = 1;
|
||||
|
||||
#define W1_EEPROM_SIZE 512
|
||||
#define W1_PAGE_COUNT 16
|
||||
#define W1_PAGE_SIZE 32
|
||||
#define W1_PAGE_BITS 5
|
||||
#define W1_PAGE_MASK 0x1F
|
||||
|
||||
#define W1_F1C_READ_EEPROM 0xF0
|
||||
#define W1_F1C_WRITE_SCRATCH 0x0F
|
||||
#define W1_F1C_READ_SCRATCH 0xAA
|
||||
#define W1_F1C_COPY_SCRATCH 0x55
|
||||
#define W1_F1C_ACCESS_WRITE 0x5A
|
||||
|
||||
#define W1_1C_REG_LOGIC_STATE 0x220
|
||||
|
||||
struct w1_f1C_data {
|
||||
u8 memory[W1_EEPROM_SIZE];
|
||||
u32 validcrc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check the file size bounds and adjusts count as needed.
|
||||
* This would not be needed if the file size didn't reset to 0 after a write.
|
||||
*/
|
||||
static inline size_t w1_f1C_fix_count(loff_t off, size_t count, size_t size)
|
||||
{
|
||||
if (off > size)
|
||||
return 0;
|
||||
|
||||
if ((off + count) > size)
|
||||
return size - off;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int w1_f1C_refresh_block(struct w1_slave *sl, struct w1_f1C_data *data,
|
||||
int block)
|
||||
{
|
||||
u8 wrbuf[3];
|
||||
int off = block * W1_PAGE_SIZE;
|
||||
|
||||
if (data->validcrc & (1 << block))
|
||||
return 0;
|
||||
|
||||
if (w1_reset_select_slave(sl)) {
|
||||
data->validcrc = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
wrbuf[0] = W1_F1C_READ_EEPROM;
|
||||
wrbuf[1] = off & 0xff;
|
||||
wrbuf[2] = off >> 8;
|
||||
w1_write_block(sl->master, wrbuf, 3);
|
||||
w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE);
|
||||
|
||||
/* cache the block if the CRC is valid */
|
||||
if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
|
||||
data->validcrc |= (1 << block);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w1_f1C_read(struct w1_slave *sl, int addr, int len, char *data)
|
||||
{
|
||||
u8 wrbuf[3];
|
||||
|
||||
/* read directly from the EEPROM */
|
||||
if (w1_reset_select_slave(sl))
|
||||
return -EIO;
|
||||
|
||||
wrbuf[0] = W1_F1C_READ_EEPROM;
|
||||
wrbuf[1] = addr & 0xff;
|
||||
wrbuf[2] = addr >> 8;
|
||||
|
||||
w1_write_block(sl->master, wrbuf, sizeof(wrbuf));
|
||||
return w1_read_block(sl->master, data, len);
|
||||
}
|
||||
|
||||
static ssize_t w1_f1C_read_bin(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
struct w1_f1C_data *data = sl->family_data;
|
||||
int i, min_page, max_page;
|
||||
|
||||
count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
|
||||
if (w1_enable_crccheck) {
|
||||
min_page = (off >> W1_PAGE_BITS);
|
||||
max_page = (off + count - 1) >> W1_PAGE_BITS;
|
||||
for (i = min_page; i <= max_page; i++) {
|
||||
if (w1_f1C_refresh_block(sl, data, i)) {
|
||||
count = -EIO;
|
||||
goto out_up;
|
||||
}
|
||||
}
|
||||
memcpy(buf, &data->memory[off], count);
|
||||
} else {
|
||||
count = w1_f1C_read(sl, off, count, buf);
|
||||
}
|
||||
|
||||
out_up:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes to the scratchpad and reads it back for verification.
|
||||
* Then copies the scratchpad to EEPROM.
|
||||
* The data must be on one page.
|
||||
* The master must be locked.
|
||||
*
|
||||
* @param sl The slave structure
|
||||
* @param addr Address for the write
|
||||
* @param len length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK))
|
||||
* @param data The data to write
|
||||
* @return 0=Success -1=failure
|
||||
*/
|
||||
static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data)
|
||||
{
|
||||
u8 wrbuf[4];
|
||||
u8 rdbuf[W1_PAGE_SIZE + 3];
|
||||
u8 es = (addr + len - 1) & 0x1f;
|
||||
unsigned int tm = 10;
|
||||
int i;
|
||||
struct w1_f1C_data *f1C = sl->family_data;
|
||||
|
||||
/* Write the data to the scratchpad */
|
||||
if (w1_reset_select_slave(sl))
|
||||
return -1;
|
||||
|
||||
wrbuf[0] = W1_F1C_WRITE_SCRATCH;
|
||||
wrbuf[1] = addr & 0xff;
|
||||
wrbuf[2] = addr >> 8;
|
||||
|
||||
w1_write_block(sl->master, wrbuf, 3);
|
||||
w1_write_block(sl->master, data, len);
|
||||
|
||||
/* Read the scratchpad and verify */
|
||||
if (w1_reset_select_slave(sl))
|
||||
return -1;
|
||||
|
||||
w1_write_8(sl->master, W1_F1C_READ_SCRATCH);
|
||||
w1_read_block(sl->master, rdbuf, len + 3);
|
||||
|
||||
/* Compare what was read against the data written */
|
||||
if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
|
||||
(rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0))
|
||||
return -1;
|
||||
|
||||
/* Copy the scratchpad to EEPROM */
|
||||
if (w1_reset_select_slave(sl))
|
||||
return -1;
|
||||
|
||||
wrbuf[0] = W1_F1C_COPY_SCRATCH;
|
||||
wrbuf[3] = es;
|
||||
|
||||
for (i = 0; i < sizeof(wrbuf); ++i) {
|
||||
/* issue 10ms strong pullup (or delay) on the last byte
|
||||
for writing the data from the scratchpad to EEPROM */
|
||||
if (w1_strong_pullup && i == sizeof(wrbuf)-1)
|
||||
w1_next_pullup(sl->master, tm);
|
||||
|
||||
w1_write_8(sl->master, wrbuf[i]);
|
||||
}
|
||||
|
||||
if (!w1_strong_pullup)
|
||||
msleep(tm);
|
||||
|
||||
if (w1_enable_crccheck) {
|
||||
/* invalidate cached data */
|
||||
f1C->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
|
||||
}
|
||||
|
||||
/* Reset the bus to wake up the EEPROM (this may not be needed) */
|
||||
w1_reset_bus(sl->master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t w1_f1C_write_bin(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
int addr, len, idx;
|
||||
|
||||
count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE);
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
if (w1_enable_crccheck) {
|
||||
/* can only write full blocks in cached mode */
|
||||
if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
|
||||
dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
|
||||
(int)off, count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* make sure the block CRCs are valid */
|
||||
for (idx = 0; idx < count; idx += W1_PAGE_SIZE) {
|
||||
if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE)
|
||||
!= CRC16_VALID) {
|
||||
dev_err(&sl->dev, "bad CRC at offset %d\n",
|
||||
(int)off);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
|
||||
/* Can only write data to one page at a time */
|
||||
idx = 0;
|
||||
while (idx < count) {
|
||||
addr = off + idx;
|
||||
len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK);
|
||||
if (len > (count - idx))
|
||||
len = count - idx;
|
||||
|
||||
if (w1_f1C_write(sl, addr, len, &buf[idx]) < 0) {
|
||||
count = -EIO;
|
||||
goto out_up;
|
||||
}
|
||||
idx += len;
|
||||
}
|
||||
|
||||
out_up:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t w1_f1C_read_pio(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
int ret;
|
||||
|
||||
/* check arguments */
|
||||
if (off != 0 || count != 1 || buf == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
ret = w1_f1C_read(sl, W1_1C_REG_LOGIC_STATE, count, buf);
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t w1_f1C_write_pio(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
|
||||
{
|
||||
struct w1_slave *sl = kobj_to_w1_slave(kobj);
|
||||
u8 wrbuf[3];
|
||||
u8 ack;
|
||||
|
||||
/* check arguments */
|
||||
if (off != 0 || count != 1 || buf == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
|
||||
/* Write the PIO data */
|
||||
if (w1_reset_select_slave(sl)) {
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set bit 7..2 to value '1' */
|
||||
*buf = *buf | 0xFC;
|
||||
|
||||
wrbuf[0] = W1_F1C_ACCESS_WRITE;
|
||||
wrbuf[1] = *buf;
|
||||
wrbuf[2] = ~(*buf);
|
||||
w1_write_block(sl->master, wrbuf, 3);
|
||||
|
||||
w1_read_block(sl->master, &ack, sizeof(ack));
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
|
||||
/* check for acknowledgement */
|
||||
if (ack != 0xAA)
|
||||
return -EIO;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t w1_f1C_show_crccheck(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (put_user(w1_enable_crccheck + 0x30, buf))
|
||||
return -EFAULT;
|
||||
|
||||
return sizeof(w1_enable_crccheck);
|
||||
}
|
||||
|
||||
static ssize_t w1_f1C_store_crccheck(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char val;
|
||||
|
||||
if (count != 1 || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (get_user(val, buf))
|
||||
return -EFAULT;
|
||||
|
||||
/* convert to decimal */
|
||||
val = val - 0x30;
|
||||
if (val != 0 && val != 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* set the new value */
|
||||
w1_enable_crccheck = val;
|
||||
|
||||
return sizeof(w1_enable_crccheck);
|
||||
}
|
||||
|
||||
#define NB_SYSFS_BIN_FILES 2
|
||||
static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
|
||||
{
|
||||
.attr = {
|
||||
.name = "eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
},
|
||||
.size = W1_EEPROM_SIZE,
|
||||
.read = w1_f1C_read_bin,
|
||||
.write = w1_f1C_write_bin,
|
||||
},
|
||||
{
|
||||
.attr = {
|
||||
.name = "pio",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
},
|
||||
.size = 1,
|
||||
.read = w1_f1C_read_pio,
|
||||
.write = w1_f1C_write_pio,
|
||||
}
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO,
|
||||
w1_f1C_show_crccheck, w1_f1C_store_crccheck);
|
||||
|
||||
static int w1_f1C_add_slave(struct w1_slave *sl)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
struct w1_f1C_data *data = NULL;
|
||||
|
||||
if (w1_enable_crccheck) {
|
||||
data = kzalloc(sizeof(struct w1_f1C_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
sl->family_data = data;
|
||||
}
|
||||
|
||||
/* create binary sysfs attributes */
|
||||
for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
|
||||
err = sysfs_create_bin_file(
|
||||
&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
|
||||
|
||||
if (!err) {
|
||||
/* create device attributes */
|
||||
err = device_create_file(&sl->dev, &dev_attr_crccheck);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
/* remove binary sysfs attributes */
|
||||
for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
|
||||
sysfs_remove_bin_file(
|
||||
&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void w1_f1C_remove_slave(struct w1_slave *sl)
|
||||
{
|
||||
int i;
|
||||
|
||||
kfree(sl->family_data);
|
||||
sl->family_data = NULL;
|
||||
|
||||
/* remove device attributes */
|
||||
device_remove_file(&sl->dev, &dev_attr_crccheck);
|
||||
|
||||
/* remove binary sysfs attributes */
|
||||
for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
|
||||
sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
|
||||
}
|
||||
|
||||
static struct w1_family_ops w1_f1C_fops = {
|
||||
.add_slave = w1_f1C_add_slave,
|
||||
.remove_slave = w1_f1C_remove_slave,
|
||||
};
|
||||
|
||||
static struct w1_family w1_family_1C = {
|
||||
.fid = W1_FAMILY_DS28E04,
|
||||
.fops = &w1_f1C_fops,
|
||||
};
|
||||
|
||||
static int __init w1_f1C_init(void)
|
||||
{
|
||||
return w1_register_family(&w1_family_1C);
|
||||
}
|
||||
|
||||
static void __exit w1_f1C_fini(void)
|
||||
{
|
||||
w1_unregister_family(&w1_family_1C);
|
||||
}
|
||||
|
||||
module_init(w1_f1C_init);
|
||||
module_exit(w1_f1C_fini);
|
@ -179,7 +179,7 @@ static ssize_t w1_therm_read(struct device *device,
|
||||
int i, max_trying = 10;
|
||||
ssize_t c = PAGE_SIZE;
|
||||
|
||||
i = mutex_lock_interruptible(&dev->mutex);
|
||||
i = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (i != 0)
|
||||
return i;
|
||||
|
||||
@ -207,19 +207,19 @@ static ssize_t w1_therm_read(struct device *device,
|
||||
w1_write_8(dev, W1_CONVERT_TEMP);
|
||||
|
||||
if (external_power) {
|
||||
mutex_unlock(&dev->mutex);
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
|
||||
sleep_rem = msleep_interruptible(tm);
|
||||
if (sleep_rem != 0)
|
||||
return -EINTR;
|
||||
|
||||
i = mutex_lock_interruptible(&dev->mutex);
|
||||
i = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (i != 0)
|
||||
return i;
|
||||
} else if (!w1_strong_pullup) {
|
||||
sleep_rem = msleep_interruptible(tm);
|
||||
if (sleep_rem != 0) {
|
||||
mutex_unlock(&dev->mutex);
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
return -EINTR;
|
||||
}
|
||||
}
|
||||
@ -258,7 +258,7 @@ static ssize_t w1_therm_read(struct device *device,
|
||||
|
||||
c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
|
||||
w1_convert_temp(rom, sl->family->fid));
|
||||
mutex_unlock(&dev->mutex);
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
|
||||
return PAGE_SIZE - c;
|
||||
}
|
||||
|
@ -557,7 +557,7 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
struct w1_master *md = NULL;
|
||||
struct w1_slave *sl = NULL;
|
||||
char *event_owner, *name;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
if (dev->driver == &w1_master_driver) {
|
||||
md = container_of(dev, struct w1_master, dev);
|
||||
@ -576,19 +576,17 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
event_owner, name, dev_name(dev));
|
||||
|
||||
if (dev->driver != &w1_slave_driver || !sl)
|
||||
return 0;
|
||||
goto end;
|
||||
|
||||
err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
|
||||
if (err)
|
||||
return err;
|
||||
goto end;
|
||||
|
||||
err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
|
||||
(unsigned long long)sl->reg_num.id);
|
||||
if (err)
|
||||
end:
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
#else
|
||||
static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
@ -887,16 +885,21 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
|
||||
*
|
||||
* Return 0 - device(s) present, 1 - no devices present.
|
||||
*/
|
||||
mutex_lock(&dev->bus_mutex);
|
||||
if (w1_reset_bus(dev)) {
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
dev_dbg(&dev->dev, "No devices present on the wire.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do fast search on single slave bus */
|
||||
if (dev->max_slave_count == 1) {
|
||||
int rv;
|
||||
w1_write_8(dev, W1_READ_ROM);
|
||||
rv = w1_read_block(dev, (u8 *)&rn, 8);
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
|
||||
if (w1_read_block(dev, (u8 *)&rn, 8) == 8 && rn)
|
||||
if (rv == 8 && rn)
|
||||
cb(dev, rn);
|
||||
|
||||
break;
|
||||
@ -929,10 +932,12 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
|
||||
rn |= (tmp64 << i);
|
||||
|
||||
if (kthread_should_stop()) {
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
dev_dbg(&dev->dev, "Abort w1_search\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
|
||||
if ( (triplet_ret & 0x03) != 0x03 ) {
|
||||
if ( (desc_bit == last_zero) || (last_zero < 0))
|
||||
|
@ -180,6 +180,7 @@ struct w1_master
|
||||
|
||||
struct task_struct *thread;
|
||||
struct mutex mutex;
|
||||
struct mutex bus_mutex;
|
||||
|
||||
struct device_driver *driver;
|
||||
struct device dev;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#define W1_FAMILY_SMEM_01 0x01
|
||||
#define W1_FAMILY_SMEM_81 0x81
|
||||
#define W1_THERM_DS18S20 0x10
|
||||
#define W1_FAMILY_DS28E04 0x1C
|
||||
#define W1_COUNTER_DS2423 0x1D
|
||||
#define W1_THERM_DS1822 0x22
|
||||
#define W1_EEPROM_DS2433 0x23
|
||||
|
@ -76,6 +76,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
|
||||
|
||||
INIT_LIST_HEAD(&dev->slist);
|
||||
mutex_init(&dev->mutex);
|
||||
mutex_init(&dev->bus_mutex);
|
||||
|
||||
memcpy(&dev->dev, device, sizeof(struct device));
|
||||
dev_set_name(&dev->dev, "w1_bus_master%u", dev->id);
|
||||
@ -117,7 +118,7 @@ int w1_add_master_device(struct w1_bus_master *master)
|
||||
return(-EINVAL);
|
||||
}
|
||||
/* While it would be electrically possible to make a device that
|
||||
* generated a strong pullup in bit bang mode, only hardare that
|
||||
* generated a strong pullup in bit bang mode, only hardware that
|
||||
* controls 1-wire time frames are even expected to support a strong
|
||||
* pullup. w1_io.c would need to support calling set_pullup before
|
||||
* the last write_bit operation of a w1_write_8 which it currently
|
||||
|
@ -498,7 +498,7 @@ void debugfs_remove(struct dentry *dentry)
|
||||
struct dentry *parent;
|
||||
int ret;
|
||||
|
||||
if (!dentry)
|
||||
if (IS_ERR_OR_NULL(dentry))
|
||||
return;
|
||||
|
||||
parent = dentry->d_parent;
|
||||
@ -530,7 +530,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
|
||||
struct dentry *child;
|
||||
struct dentry *parent;
|
||||
|
||||
if (!dentry)
|
||||
if (IS_ERR_OR_NULL(dentry))
|
||||
return;
|
||||
|
||||
parent = dentry->d_parent;
|
||||
|
@ -689,6 +689,11 @@ struct device {
|
||||
void (*release)(struct device *dev);
|
||||
};
|
||||
|
||||
static inline struct device *kobj_to_dev(struct kobject *kobj)
|
||||
{
|
||||
return container_of(kobj, struct device, kobj);
|
||||
}
|
||||
|
||||
/* Get the wakeup routines, which depend on struct device */
|
||||
#include <linux/pm_wakeup.h>
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
|
||||
#define kobj_to_dev(k) container_of((k), struct device, kobj)
|
||||
#define dev_to_disk(device) container_of((device), struct gendisk, part0.__dev)
|
||||
#define dev_to_part(device) container_of((device), struct hd_struct, __dev)
|
||||
#define disk_to_dev(disk) (&(disk)->part0.__dev)
|
||||
|
Loading…
Reference in New Issue
Block a user