aboutsummaryrefslogtreecommitdiff
path: root/drivers/w1/masters
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/w1/masters')
-rw-r--r--drivers/w1/masters/Kconfig24
-rw-r--r--drivers/w1/masters/Makefile3
-rw-r--r--drivers/w1/masters/ds1wm.c426
-rw-r--r--drivers/w1/masters/ds2482.c165
-rw-r--r--drivers/w1/masters/ds2490.c521
-rw-r--r--drivers/w1/masters/matrox_w1.c16
-rw-r--r--drivers/w1/masters/mxc_w1.c182
-rw-r--r--drivers/w1/masters/omap_hdq.c635
-rw-r--r--drivers/w1/masters/w1-gpio.c192
9 files changed, 1679 insertions, 485 deletions
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index c4493091c65..1708b2300c7 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -12,7 +12,7 @@ config W1_MASTER_MATROX
using Matrox's G400 GPIO pins.
This support is also available as a module. If so, the module
- will be called matrox_w1.ko.
+ will be called matrox_w1.
config W1_MASTER_DS2490
tristate "DS2490 USB <-> W1 transport layer for 1-wire"
@@ -22,11 +22,11 @@ config W1_MASTER_DS2490
for example DS9490*.
This support is also available as a module. If so, the module
- will be called ds2490.ko.
+ will be called ds2490.
config W1_MASTER_DS2482
tristate "Maxim DS2482 I2C to 1-Wire bridge"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Maxim DS2482
I2C to 1-Wire bridge.
@@ -34,9 +34,14 @@ config W1_MASTER_DS2482
This driver can also be built as a module. If so, the module
will be called ds2482.
+config W1_MASTER_MXC
+ tristate "Freescale MXC 1-wire busmaster"
+ depends on ARCH_MXC || COMPILE_TEST
+ help
+ Say Y here to enable MXC 1-wire host
+
config W1_MASTER_DS1WM
tristate "Maxim DS1WM 1-wire busmaster"
- depends on W1 && ARM
help
Say Y here to enable the DS1WM 1-wire driver, such as that
in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
@@ -44,13 +49,20 @@ config W1_MASTER_DS1WM
config W1_MASTER_GPIO
tristate "GPIO 1-wire busmaster"
- depends on GENERIC_GPIO
+ depends on GPIOLIB
help
Say Y here if you want to communicate with your 1-wire devices using
GPIO pins. This driver uses the GPIO API to control the wire.
This support is also available as a module. If so, the module
- will be called w1-gpio.ko.
+ will be called w1-gpio.
+
+config HDQ_MASTER_OMAP
+ tristate "OMAP HDQ driver"
+ depends on ARCH_OMAP
+ help
+ Say Y here if you want support for the 1-wire or HDQ Interface
+ on an OMAP processor.
endmenu
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index 1420b5bbdda..c5a3e96fcba 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -5,5 +5,8 @@
obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
+obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o
+
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
+obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 10211e49300..02df3b1381d 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -13,13 +13,15 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
-#include <linux/clk.h>
#include <linux/err.h>
#include <linux/delay.h>
-#include <linux/ds1wm.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ds1wm.h>
+#include <linux/slab.h>
#include <asm/io.h>
@@ -32,6 +34,7 @@
#define DS1WM_INT 0x02 /* R/W interrupt status */
#define DS1WM_INT_EN 0x03 /* R/W interrupt enable */
#define DS1WM_CLKDIV 0x04 /* R/W 5 bits of divisor and pre-scale */
+#define DS1WM_CNTRL 0x05 /* R/W master control register (not used yet) */
#define DS1WM_CMD_1W_RESET (1 << 0) /* force reset on 1-wire bus */
#define DS1WM_CMD_SRA (1 << 1) /* enable Search ROM accelerator mode */
@@ -55,6 +58,7 @@
#define DS1WM_INTEN_ERSRF (1 << 5) /* enable rx shift register full int */
#define DS1WM_INTEN_DQO (1 << 6) /* enable direct bus driving ops */
+#define DS1WM_INTEN_NOT_IAS (~DS1WM_INTEN_IAS) /* all but INTR active state */
#define DS1WM_TIMEOUT (HZ * 5)
@@ -62,42 +66,51 @@ static struct {
unsigned long freq;
unsigned long divisor;
} freq[] = {
- { 4000000, 0x8 },
- { 5000000, 0x2 },
- { 6000000, 0x5 },
- { 7000000, 0x3 },
- { 8000000, 0xc },
- { 10000000, 0x6 },
- { 12000000, 0x9 },
- { 14000000, 0x7 },
- { 16000000, 0x10 },
- { 20000000, 0xa },
- { 24000000, 0xd },
- { 28000000, 0xb },
- { 32000000, 0x14 },
- { 40000000, 0xe },
- { 48000000, 0x11 },
- { 56000000, 0xf },
- { 64000000, 0x18 },
- { 80000000, 0x12 },
- { 96000000, 0x15 },
- { 112000000, 0x13 },
- { 128000000, 0x1c },
+ { 1000000, 0x80 },
+ { 2000000, 0x84 },
+ { 3000000, 0x81 },
+ { 4000000, 0x88 },
+ { 5000000, 0x82 },
+ { 6000000, 0x85 },
+ { 7000000, 0x83 },
+ { 8000000, 0x8c },
+ { 10000000, 0x86 },
+ { 12000000, 0x89 },
+ { 14000000, 0x87 },
+ { 16000000, 0x90 },
+ { 20000000, 0x8a },
+ { 24000000, 0x8d },
+ { 28000000, 0x8b },
+ { 32000000, 0x94 },
+ { 40000000, 0x8e },
+ { 48000000, 0x91 },
+ { 56000000, 0x8f },
+ { 64000000, 0x98 },
+ { 80000000, 0x92 },
+ { 96000000, 0x95 },
+ { 112000000, 0x93 },
+ { 128000000, 0x9c },
+/* you can continue this table, consult the OPERATION - CLOCK DIVISOR
+ section of the ds1wm spec sheet. */
};
struct ds1wm_data {
- void __iomem *map;
- int bus_shift; /* # of shifts to calc register offsets */
+ void __iomem *map;
+ int bus_shift; /* # of shifts to calc register offsets */
struct platform_device *pdev;
- struct ds1wm_platform_data *pdata;
- int irq;
- int active_high;
- struct clk *clk;
- int slave_present;
- void *reset_complete;
- void *read_complete;
- void *write_complete;
- u8 read_byte; /* last byte received */
+ const struct mfd_cell *cell;
+ int irq;
+ int slave_present;
+ void *reset_complete;
+ void *read_complete;
+ void *write_complete;
+ int read_error;
+ /* last byte received */
+ u8 read_byte;
+ /* byte to write that makes all intr disabled, */
+ /* considering active_state (IAS) (optimization) */
+ u8 int_en_reg_none;
+ unsigned int reset_recover_delay; /* see ds1wm.h */
};
static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg,
@@ -115,23 +128,39 @@ static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg)
static irqreturn_t ds1wm_isr(int isr, void *data)
{
struct ds1wm_data *ds1wm_data = data;
- u8 intr = ds1wm_read_register(ds1wm_data, DS1WM_INT);
+ u8 intr;
+ u8 inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN);
+ /* if no bits are set in int enable register (except the IAS)
+ than go no further, reading the regs below has side effects */
+ if (!(inten & DS1WM_INTEN_NOT_IAS))
+ return IRQ_NONE;
- ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1;
+ ds1wm_write_register(ds1wm_data,
+ DS1WM_INT_EN, ds1wm_data->int_en_reg_none);
- if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete)
- complete(ds1wm_data->reset_complete);
+ /* this read action clears the INTR and certain flags in ds1wm */
+ intr = ds1wm_read_register(ds1wm_data, DS1WM_INT);
- if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete)
- complete(ds1wm_data->write_complete);
+ ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1;
+ if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete) {
+ inten &= ~DS1WM_INTEN_ETMT;
+ complete(ds1wm_data->write_complete);
+ }
if (intr & DS1WM_INT_RBF) {
+ /* this read clears the RBF flag */
ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data,
- DS1WM_DATA);
+ DS1WM_DATA);
+ inten &= ~DS1WM_INTEN_ERBF;
if (ds1wm_data->read_complete)
complete(ds1wm_data->read_complete);
}
+ if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete) {
+ inten &= ~DS1WM_INTEN_EPD;
+ complete(ds1wm_data->reset_complete);
+ }
+ ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, inten);
return IRQ_HANDLED;
}
@@ -142,61 +171,73 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
ds1wm_data->reset_complete = &reset_done;
+ /* enable Presence detect only */
ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD |
- (ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
+ ds1wm_data->int_en_reg_none);
ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET);
timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT);
ds1wm_data->reset_complete = NULL;
if (!timeleft) {
- dev_err(&ds1wm_data->pdev->dev, "reset failed\n");
+ dev_err(&ds1wm_data->pdev->dev, "reset failed, timed out\n");
return 1;
}
- /* Wait for the end of the reset. According to the specs, the time
- * from when the interrupt is asserted to the end of the reset is:
- * tRSTH - tPDH - tPDL - tPDI
- * 625 us - 60 us - 240 us - 100 ns = 324.9 us
- *
- * We'll wait a bit longer just to be sure.
- */
- udelay(500);
-
- ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
- DS1WM_INTEN_ERBF | DS1WM_INTEN_ETMT | DS1WM_INTEN_EPD |
- (ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
-
if (!ds1wm_data->slave_present) {
dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n");
return 1;
}
+ if (ds1wm_data->reset_recover_delay)
+ msleep(ds1wm_data->reset_recover_delay);
+
return 0;
}
static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data)
{
+ unsigned long timeleft;
DECLARE_COMPLETION_ONSTACK(write_done);
ds1wm_data->write_complete = &write_done;
+ ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+ ds1wm_data->int_en_reg_none | DS1WM_INTEN_ETMT);
+
ds1wm_write_register(ds1wm_data, DS1WM_DATA, data);
- wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT);
+ timeleft = wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT);
+
ds1wm_data->write_complete = NULL;
+ if (!timeleft) {
+ dev_err(&ds1wm_data->pdev->dev, "write failed, timed out\n");
+ return -ETIMEDOUT;
+ }
return 0;
}
-static int ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
+static u8 ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
{
+ unsigned long timeleft;
+ u8 intEnable = DS1WM_INTEN_ERBF | ds1wm_data->int_en_reg_none;
DECLARE_COMPLETION_ONSTACK(read_done);
+
+ ds1wm_read_register(ds1wm_data, DS1WM_DATA);
+
ds1wm_data->read_complete = &read_done;
+ ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, intEnable);
- ds1wm_write(ds1wm_data, write_data);
- wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT);
- ds1wm_data->read_complete = NULL;
+ ds1wm_write_register(ds1wm_data, DS1WM_DATA, write_data);
+ timeleft = wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT);
+ ds1wm_data->read_complete = NULL;
+ if (!timeleft) {
+ dev_err(&ds1wm_data->pdev->dev, "read failed, timed out\n");
+ ds1wm_data->read_error = -ETIMEDOUT;
+ return 0xFF;
+ }
+ ds1wm_data->read_error = 0;
return ds1wm_data->read_byte;
}
@@ -204,8 +245,8 @@ static int ds1wm_find_divisor(int gclk)
{
int i;
- for (i = 0; i < ARRAY_SIZE(freq); i++)
- if (gclk <= freq[i].freq)
+ for (i = ARRAY_SIZE(freq)-1; i >= 0; --i)
+ if (gclk >= freq[i].freq)
return freq[i].divisor;
return 0;
@@ -213,17 +254,19 @@ static int ds1wm_find_divisor(int gclk)
static void ds1wm_up(struct ds1wm_data *ds1wm_data)
{
- int gclk, divisor;
+ int divisor;
+ struct device *dev = &ds1wm_data->pdev->dev;
+ struct ds1wm_driver_data *plat = dev_get_platdata(dev);
- if (ds1wm_data->pdata->enable)
- ds1wm_data->pdata->enable(ds1wm_data->pdev);
+ if (ds1wm_data->cell->enable)
+ ds1wm_data->cell->enable(ds1wm_data->pdev);
- gclk = clk_get_rate(ds1wm_data->clk);
- clk_enable(ds1wm_data->clk);
- divisor = ds1wm_find_divisor(gclk);
+ divisor = ds1wm_find_divisor(plat->clock_rate);
+ dev_dbg(dev, "found divisor 0x%x for clock %d\n",
+ divisor, plat->clock_rate);
if (divisor == 0) {
- dev_err(&ds1wm_data->pdev->dev,
- "no suitable divisor for %dHz clock\n", gclk);
+ dev_err(dev, "no suitable divisor for %dHz clock\n",
+ plat->clock_rate);
return;
}
ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor);
@@ -240,12 +283,10 @@ static void ds1wm_down(struct ds1wm_data *ds1wm_data)
/* Disable interrupts. */
ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
- ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0);
+ ds1wm_data->int_en_reg_none);
- if (ds1wm_data->pdata->disable)
- ds1wm_data->pdata->disable(ds1wm_data->pdev);
-
- clk_disable(ds1wm_data->clk);
+ if (ds1wm_data->cell->disable)
+ ds1wm_data->cell->disable(ds1wm_data->pdev);
}
/* --------------------------------------------------------------------- */
@@ -274,46 +315,130 @@ static u8 ds1wm_reset_bus(void *data)
return 0;
}
-static void ds1wm_search(void *data, u8 search_type,
- w1_slave_found_callback slave_found)
+static void ds1wm_search(void *data, struct w1_master *master_dev,
+ u8 search_type, w1_slave_found_callback slave_found)
{
struct ds1wm_data *ds1wm_data = data;
int i;
- unsigned long long rom_id;
-
- /* XXX We need to iterate for multiple devices per the DS1WM docs.
- * See http://www.maxim-ic.com/appnotes.cfm/appnote_number/120. */
- if (ds1wm_reset(ds1wm_data))
- return;
-
- ds1wm_write(ds1wm_data, search_type);
- ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
-
- for (rom_id = 0, i = 0; i < 16; i++) {
-
- unsigned char resp, r, d;
-
- resp = ds1wm_read(ds1wm_data, 0x00);
-
- r = ((resp & 0x02) >> 1) |
- ((resp & 0x08) >> 2) |
- ((resp & 0x20) >> 3) |
- ((resp & 0x80) >> 4);
-
- d = ((resp & 0x01) >> 0) |
- ((resp & 0x04) >> 1) |
- ((resp & 0x10) >> 2) |
- ((resp & 0x40) >> 3);
-
- rom_id |= (unsigned long long) r << (i * 4);
-
- }
- dev_dbg(&ds1wm_data->pdev->dev, "found 0x%08llX\n", rom_id);
-
- ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
- ds1wm_reset(ds1wm_data);
-
- slave_found(ds1wm_data, rom_id);
+ int ms_discrep_bit = -1;
+ u64 r = 0; /* holds the progress of the search */
+ u64 r_prime, d;
+ unsigned slaves_found = 0;
+ unsigned int pass = 0;
+
+ dev_dbg(&ds1wm_data->pdev->dev, "search begin\n");
+ while (true) {
+ ++pass;
+ if (pass > 100) {
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "too many attempts (100), search aborted\n");
+ 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;
+ }
+
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d r : %0#18llx writing SEARCH_ROM\n", pass, r);
+ ds1wm_write(ds1wm_data, search_type);
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d entering ASM\n", pass);
+ ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d beginning nibble loop\n", pass);
+
+ r_prime = 0;
+ d = 0;
+ /* we work one nibble at a time */
+ /* each nibble is interleaved to form a byte */
+ for (i = 0; i < 16; i++) {
+
+ unsigned char resp, _r, _r_prime, _d;
+
+ _r = (r >> (4*i)) & 0xf;
+ _r = ((_r & 0x1) << 1) |
+ ((_r & 0x2) << 2) |
+ ((_r & 0x4) << 3) |
+ ((_r & 0x8) << 4);
+
+ /* writes _r, then reads back: */
+ resp = ds1wm_read(ds1wm_data, _r);
+
+ if (ds1wm_data->read_error) {
+ dev_err(&ds1wm_data->pdev->dev,
+ "pass: %d nibble: %d read error\n", pass, i);
+ break;
+ }
+
+ _r_prime = ((resp & 0x02) >> 1) |
+ ((resp & 0x08) >> 2) |
+ ((resp & 0x20) >> 3) |
+ ((resp & 0x80) >> 4);
+
+ _d = ((resp & 0x01) >> 0) |
+ ((resp & 0x04) >> 1) |
+ ((resp & 0x10) >> 2) |
+ ((resp & 0x40) >> 3);
+
+ r_prime |= (unsigned long long) _r_prime << (i * 4);
+ d |= (unsigned long long) _d << (i * 4);
+
+ }
+ 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;
+ }
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d r\': %0#18llx d:%0#18llx\n",
+ pass, r_prime, d);
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d nibble loop complete, exiting ASM\n", pass);
+ ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
+ 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);
+ continue; /* start over */
+ }
+
+
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d found %0#18llx\n", pass, r_prime);
+ slave_found(master_dev, r_prime);
+ ++slaves_found;
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d complete, preparing next pass\n", pass);
+
+ /* any discrepency found which we already choose the
+ '1' branch is now is now irrelevant we reveal the
+ next branch with this: */
+ d &= ~r;
+ /* find last bit set, i.e. the most signif. bit set */
+ ms_discrep_bit = fls64(d) - 1;
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d new d:%0#18llx MS discrep bit:%d\n",
+ pass, d, ms_discrep_bit);
+
+ /* prev_ms_discrep_bit = ms_discrep_bit;
+ prepare for next ROM search: */
+ if (ms_discrep_bit == -1)
+ break;
+
+ r = (r & ~(~0ull << (ms_discrep_bit))) | 1 << ms_discrep_bit;
+ } /* end while true */
+ dev_dbg(&ds1wm_data->pdev->dev,
+ "pass: %d total: %d search done ms d bit pos: %d\n", pass,
+ slaves_found, ms_discrep_bit);
}
/* --------------------------------------------------------------------- */
@@ -328,57 +453,54 @@ static struct w1_bus_master ds1wm_master = {
static int ds1wm_probe(struct platform_device *pdev)
{
struct ds1wm_data *ds1wm_data;
- struct ds1wm_platform_data *plat;
+ struct ds1wm_driver_data *plat;
struct resource *res;
int ret;
if (!pdev)
return -ENODEV;
- ds1wm_data = kzalloc(sizeof(*ds1wm_data), GFP_KERNEL);
+ ds1wm_data = devm_kzalloc(&pdev->dev, sizeof(*ds1wm_data), GFP_KERNEL);
if (!ds1wm_data)
return -ENOMEM;
platform_set_drvdata(pdev, ds1wm_data);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENXIO;
- goto err0;
- }
- ds1wm_data->map = ioremap(res->start, res->end - res->start + 1);
- if (!ds1wm_data->map) {
- ret = -ENOMEM;
- goto err0;
- }
- plat = pdev->dev.platform_data;
- ds1wm_data->bus_shift = plat->bus_shift;
+ if (!res)
+ return -ENXIO;
+ ds1wm_data->map = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ds1wm_data->map)
+ return -ENOMEM;
+
+ /* calculate bus shift from mem resource */
+ ds1wm_data->bus_shift = resource_size(res) >> 3;
+
ds1wm_data->pdev = pdev;
- ds1wm_data->pdata = plat;
+ ds1wm_data->cell = mfd_get_cell(pdev);
+ if (!ds1wm_data->cell)
+ return -ENODEV;
+ plat = dev_get_platdata(&pdev->dev);
+ if (!plat)
+ return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- ret = -ENXIO;
- goto err1;
- }
+ if (!res)
+ return -ENXIO;
ds1wm_data->irq = res->start;
- ds1wm_data->active_high = plat->active_high;
+ ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0);
+ ds1wm_data->reset_recover_delay = plat->reset_recover_delay;
if (res->flags & IORESOURCE_IRQ_HIGHEDGE)
- set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING);
+ irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING);
if (res->flags & IORESOURCE_IRQ_LOWEDGE)
- set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING);
+ irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING);
- ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED,
- "ds1wm", ds1wm_data);
+ ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr,
+ IRQF_SHARED, "ds1wm", ds1wm_data);
if (ret)
- goto err1;
-
- ds1wm_data->clk = clk_get(&pdev->dev, "ds1wm");
- if (IS_ERR(ds1wm_data->clk)) {
- ret = PTR_ERR(ds1wm_data->clk);
- goto err2;
- }
+ return ret;
ds1wm_up(ds1wm_data);
@@ -386,19 +508,12 @@ static int ds1wm_probe(struct platform_device *pdev)
ret = w1_add_master_device(&ds1wm_master);
if (ret)
- goto err3;
+ goto err;
return 0;
-err3:
+err:
ds1wm_down(ds1wm_data);
- clk_put(ds1wm_data->clk);
-err2:
- free_irq(ds1wm_data->irq, ds1wm_data);
-err1:
- iounmap(ds1wm_data->map);
-err0:
- kfree(ds1wm_data);
return ret;
}
@@ -432,10 +547,6 @@ static int ds1wm_remove(struct platform_device *pdev)
w1_remove_master_device(&ds1wm_master);
ds1wm_down(ds1wm_data);
- clk_put(ds1wm_data->clk);
- free_irq(ds1wm_data->irq, ds1wm_data);
- iounmap(ds1wm_data->map);
- kfree(ds1wm_data);
return 0;
}
@@ -466,5 +577,6 @@ module_exit(ds1wm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
- "Matt Reimer <mreimer@vpop.net>");
+ "Matt Reimer <mreimer@vpop.net>,"
+ "Jean-Francois Dagenais <dagenaisj@sonatest.com>");
MODULE_DESCRIPTION("DS1WM w1 busmaster driver");
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index 0fd5820d5c6..e033491fe30 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -24,19 +24,6 @@
#include "../w1_int.h"
/**
- * Address is selected using 2 pins, resulting in 4 possible addresses.
- * 0x18, 0x19, 0x1a, 0x1b
- * However, the chip cannot be detected without doing an i2c write,
- * so use the force module parameter.
- */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/**
- * Insmod parameters
- */
-I2C_CLIENT_INSMOD_1(ds2482);
-
-/**
* The DS2482 registers - there are 3 registers that are addressed by a read
* pointer. The read pointer is set by the last command executed.
*
@@ -64,10 +51,10 @@ I2C_CLIENT_INSMOD_1(ds2482);
* The top 4 bits always read 0.
* To write, the top nibble must be the 1's compl. of the low nibble.
*/
-#define DS2482_REG_CFG_1WS 0x08
-#define DS2482_REG_CFG_SPU 0x04
-#define DS2482_REG_CFG_PPM 0x02
-#define DS2482_REG_CFG_APU 0x01
+#define DS2482_REG_CFG_1WS 0x08 /* 1-wire speed */
+#define DS2482_REG_CFG_SPU 0x04 /* strong pull-up */
+#define DS2482_REG_CFG_PPM 0x02 /* presence pulse masking */
+#define DS2482_REG_CFG_APU 0x01 /* active pull-up */
/**
@@ -94,21 +81,27 @@ static const u8 ds2482_chan_rd[8] =
#define DS2482_REG_STS_1WB 0x01
-static int ds2482_attach_adapter(struct i2c_adapter *adapter);
-static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind);
-static int ds2482_detach_client(struct i2c_client *client);
+static int ds2482_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int ds2482_remove(struct i2c_client *client);
/**
* Driver data (common to all clients)
*/
+static const struct i2c_device_id ds2482_id[] = {
+ { "ds2482", 0 },
+ { }
+};
+
static struct i2c_driver ds2482_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ds2482",
},
- .attach_adapter = ds2482_attach_adapter,
- .detach_client = ds2482_detach_client,
+ .probe = ds2482_probe,
+ .remove = ds2482_remove,
+ .id_table = ds2482_id,
};
/*
@@ -124,7 +117,7 @@ struct ds2482_w1_chan {
};
struct ds2482_data {
- struct i2c_client client;
+ struct i2c_client *client;
struct mutex access_lock;
/* 1-wire interface(s) */
@@ -139,6 +132,17 @@ struct ds2482_data {
/**
+ * Helper to calculate values for configuration register
+ * @param conf the raw config value
+ * @return the value w/ complements that can be written to register
+ */
+static inline u8 ds2482_calculate_config(u8 conf)
+{
+ return conf | ((~conf & 0x0f) << 4);
+}
+
+
+/**
* Sets the read pointer.
* @param pdev The ds2482 client pointer
* @param read_ptr see DS2482_PTR_CODE_xxx above
@@ -147,7 +151,7 @@ struct ds2482_data {
static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
{
if (pdev->read_prt != read_ptr) {
- if (i2c_smbus_write_byte_data(&pdev->client,
+ if (i2c_smbus_write_byte_data(pdev->client,
DS2482_CMD_SET_READ_PTR,
read_ptr) < 0)
return -1;
@@ -167,7 +171,7 @@ static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
*/
static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
{
- if (i2c_smbus_write_byte(&pdev->client, cmd) < 0)
+ if (i2c_smbus_write_byte(pdev->client, cmd) < 0)
return -1;
pdev->read_prt = DS2482_PTR_CODE_STATUS;
@@ -187,7 +191,7 @@ static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
u8 cmd, u8 byte)
{
- if (i2c_smbus_write_byte_data(&pdev->client, cmd, byte) < 0)
+ if (i2c_smbus_write_byte_data(pdev->client, cmd, byte) < 0)
return -1;
/* all cmds leave in STATUS, except CONFIG */
@@ -216,12 +220,12 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
if (!ds2482_select_register(pdev, DS2482_PTR_CODE_STATUS)) {
do {
- temp = i2c_smbus_read_byte(&pdev->client);
+ temp = i2c_smbus_read_byte(pdev->client);
} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
(++retries < DS2482_WAIT_IDLE_TIMEOUT));
}
- if (retries > DS2482_WAIT_IDLE_TIMEOUT)
+ if (retries >= DS2482_WAIT_IDLE_TIMEOUT)
printk(KERN_ERR "%s: timeout on channel %d\n",
__func__, pdev->channel);
@@ -238,13 +242,13 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
*/
static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
{
- if (i2c_smbus_write_byte_data(&pdev->client, DS2482_CMD_CHANNEL_SELECT,
+ if (i2c_smbus_write_byte_data(pdev->client, DS2482_CMD_CHANNEL_SELECT,
ds2482_chan_wr[channel]) < 0)
return -1;
pdev->read_prt = DS2482_PTR_CODE_CHANNEL;
pdev->channel = -1;
- if (i2c_smbus_read_byte(&pdev->client) == ds2482_chan_rd[channel]) {
+ if (i2c_smbus_read_byte(pdev->client) == ds2482_chan_rd[channel]) {
pdev->channel = channel;
return 0;
}
@@ -368,7 +372,7 @@ static u8 ds2482_w1_read_byte(void *data)
ds2482_select_register(pdev, DS2482_PTR_CODE_DATA);
/* Read the data byte */
- result = i2c_smbus_read_byte(&pdev->client);
+ result = i2c_smbus_read_byte(pdev->client);
mutex_unlock(&pdev->access_lock);
@@ -406,7 +410,7 @@ static u8 ds2482_w1_reset_bus(void *data)
/* If the chip did reset since detect, re-config it */
if (err & DS2482_REG_STS_RST)
ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
- 0xF0);
+ ds2482_calculate_config(0x00));
}
mutex_unlock(&pdev->access_lock);
@@ -414,48 +418,57 @@ static u8 ds2482_w1_reset_bus(void *data)
return retval;
}
-
-/**
- * Called to see if the device exists on an i2c bus.
- */
-static int ds2482_attach_adapter(struct i2c_adapter *adapter)
+static u8 ds2482_w1_set_pullup(void *data, int delay)
{
- return i2c_probe(adapter, &addr_data, ds2482_detect);
+ struct ds2482_w1_chan *pchan = data;
+ struct ds2482_data *pdev = pchan->pdev;
+ u8 retval = 1;
+
+ /* if delay is non-zero activate the pullup,
+ * the strong pullup will be automatically deactivated
+ * by the master, so do not explicitly deactive it
+ */
+ if (delay) {
+ /* both waits are crucial, otherwise devices might not be
+ * powered long enough, causing e.g. a w1_therm sensor to
+ * provide wrong conversion results
+ */
+ ds2482_wait_1wire_idle(pdev);
+ /* note: it seems like both SPU and APU have to be set! */
+ retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+ ds2482_calculate_config(DS2482_REG_CFG_SPU |
+ DS2482_REG_CFG_APU));
+ ds2482_wait_1wire_idle(pdev);
+ }
+
+ return retval;
}
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
+static int ds2482_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds2482_data *data;
- struct i2c_client *new_client;
- int err = 0;
+ int err = -ENODEV;
int temp1;
int idx;
- if (!i2c_check_functionality(adapter,
+ if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
I2C_FUNC_SMBUS_BYTE))
- goto exit;
+ return -ENODEV;
if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->driver = &ds2482_driver;
- new_client->adapter = adapter;
+ data->client = client;
+ i2c_set_clientdata(client, data);
/* Reset the device (sets the read_ptr to status) */
if (ds2482_send_cmd(data, DS2482_CMD_RESET) < 0) {
- dev_dbg(&adapter->dev, "DS2482 reset failed at 0x%02x.\n",
- address);
+ dev_warn(&client->dev, "DS2482 reset failed.\n");
goto exit_free;
}
@@ -463,10 +476,10 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
ndelay(525);
/* Read the status byte - only reset bit and line should be set */
- temp1 = i2c_smbus_read_byte(new_client);
+ temp1 = i2c_smbus_read_byte(client);
if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) {
- dev_dbg(&adapter->dev, "DS2482 (0x%02x) reset status "
- "0x%02X - not a DS2482\n", address, temp1);
+ dev_warn(&client->dev, "DS2482 reset status "
+ "0x%02X - not a DS2482\n", temp1);
goto exit_free;
}
@@ -476,18 +489,11 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
data->w1_count = 8;
/* Set all config items to 0 (off) */
- ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, 0xF0);
-
- /* We can fill in the remaining client fields */
- snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00",
- data->w1_count);
+ ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG,
+ ds2482_calculate_config(0x00));
mutex_init(&data->access_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Register 1-wire interface(s) */
for (idx = 0; idx < data->w1_count; idx++) {
data->w1_ch[idx].pdev = data;
@@ -500,6 +506,7 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
data->w1_ch[idx].w1_bm.touch_bit = ds2482_w1_touch_bit;
data->w1_ch[idx].w1_bm.triplet = ds2482_w1_triplet;
data->w1_ch[idx].w1_bm.reset_bus = ds2482_w1_reset_bus;
+ data->w1_ch[idx].w1_bm.set_pullup = ds2482_w1_set_pullup;
err = w1_add_master_device(&data->w1_ch[idx].w1_bm);
if (err) {
@@ -511,8 +518,6 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_w1_remove:
- i2c_detach_client(new_client);
-
for (idx = 0; idx < data->w1_count; idx++) {
if (data->w1_ch[idx].pdev != NULL)
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
@@ -523,10 +528,10 @@ exit:
return err;
}
-static int ds2482_detach_client(struct i2c_client *client)
+static int ds2482_remove(struct i2c_client *client)
{
struct ds2482_data *data = i2c_get_clientdata(client);
- int err, idx;
+ int idx;
/* Unregister the 1-wire bridge(s) */
for (idx = 0; idx < data->w1_count; idx++) {
@@ -534,31 +539,13 @@ static int ds2482_detach_client(struct i2c_client *client)
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
}
- /* Detach the i2c device */
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Deregistration failed, client not detached.\n");
- return err;
- }
-
/* Free the memory */
kfree(data);
return 0;
}
-static int __init sensors_ds2482_init(void)
-{
- return i2c_add_driver(&ds2482_driver);
-}
-
-static void __exit sensors_ds2482_exit(void)
-{
- i2c_del_driver(&ds2482_driver);
-}
+module_i2c_driver(ds2482_driver);
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
MODULE_DESCRIPTION("DS2482 driver");
MODULE_LICENSE("GPL");
-
-module_init(sensors_ds2482_init);
-module_exit(sensors_ds2482_exit);
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index b63b5e044a4..7404ad3062b 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -1,7 +1,7 @@
/*
- * dscore.c
+ * ds2490.c USB to one wire bridge
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -23,10 +23,15 @@
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/usb.h>
+#include <linux/slab.h>
#include "../w1_int.h"
#include "../w1.h"
+/* USB Standard */
+/* USB Control request vendor type */
+#define VENDOR 0x40
+
/* COMMAND TYPE CODES */
#define CONTROL_CMD 0x00
#define COMM_CMD 0x01
@@ -88,7 +93,7 @@
#define COMM_DT 0x2000
#define COMM_SPU 0x1000
#define COMM_F 0x0800
-#define COMM_NTP 0x0400
+#define COMM_NTF 0x0400
#define COMM_ICP 0x0200
#define COMM_RST 0x0100
@@ -98,11 +103,6 @@
#define BRANCH_MAIN 0xCC
#define BRANCH_AUX 0x33
-/*
- * Duration of the strong pull-up pulse in milliseconds.
- */
-#define PULLUP_PULSE_DURATION 750
-
/* Status flags */
#define ST_SPUA 0x01 /* Strong Pull-up is active */
#define ST_PRGA 0x02 /* 12V programming pulse is being generated */
@@ -111,6 +111,19 @@
#define ST_HALT 0x10 /* DS2490 is currently halted */
#define ST_IDLE 0x20 /* DS2490 is currently idle */
#define ST_EPOF 0x80
+/* Status transfer size, 16 bytes status, 16 byte result flags */
+#define ST_SIZE 0x20
+
+/* Result Register flags */
+#define RR_DETECT 0xA5 /* New device detected */
+#define RR_NRS 0x01 /* Reset no presence or ... */
+#define RR_SH 0x02 /* short on reset or set path */
+#define RR_APP 0x04 /* alarming presence on reset */
+#define RR_VPP 0x08 /* 12V expected not seen */
+#define RR_CMP 0x10 /* compare error */
+#define RR_CRC 0x20 /* CRC error detected */
+#define RR_RDP 0x40 /* redirected page */
+#define RR_EOS 0x80 /* end of search error */
#define SPEED_NORMAL 0x00
#define SPEED_FLEXIBLE 0x01
@@ -131,6 +144,15 @@ struct ds_device
int ep[NUM_EP];
+ /* Strong PullUp
+ * 0: pullup not active, else duration in milliseconds
+ */
+ int spu_sleep;
+ /* spu_bit contains COMM_SPU or 0 depending on if the strong pullup
+ * should be active or not for writes.
+ */
+ u16 spu_bit;
+
struct w1_bus_master master;
};
@@ -164,7 +186,6 @@ MODULE_DEVICE_TABLE(usb, ds_id_table);
static int ds_probe(struct usb_interface *, const struct usb_device_id *);
static void ds_disconnect(struct usb_interface *);
-static inline void ds_dump_status(unsigned char *, unsigned char *, int);
static int ds_send_control(struct ds_device *, u16, u16);
static int ds_send_control_cmd(struct ds_device *, u16, u16);
@@ -183,7 +204,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
+ CONTROL_CMD, VENDOR, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
value, index, err);
@@ -192,13 +213,13 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
return err;
}
-#if 0
+
static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
{
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- MODE_CMD, 0x40, value, index, NULL, 0, 1000);
+ MODE_CMD, VENDOR, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
value, index, err);
@@ -207,13 +228,13 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
return err;
}
-#endif
+
static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
{
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- COMM_CMD, 0x40, value, index, NULL, 0, 1000);
+ COMM_CMD, VENDOR, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
value, index, err);
@@ -223,11 +244,6 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
return err;
}
-static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off)
-{
- printk("%45s: %8x\n", str, buf[off]);
-}
-
static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
unsigned char *buf, int size)
{
@@ -236,7 +252,8 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
memset(st, 0, sizeof(*st));
count = 0;
- err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
+ err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(dev->udev,
+ dev->ep[EP_STATUS]), buf, size, &count, 100);
if (err < 0) {
printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
return err;
@@ -248,62 +265,81 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
return count;
}
-static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
+static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
{
- unsigned char buf[64];
- int count, err = 0, i;
-
- memcpy(st, buf, sizeof(*st));
+ printk(KERN_INFO "%45s: %8x\n", str, buf[off]);
+}
- count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
- if (count < 0)
- return err;
+static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count)
+{
+ int i;
- printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
+ printk(KERN_INFO "0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
for (i=0; i<count; ++i)
printk("%02x ", buf[i]);
- printk("\n");
+ printk(KERN_INFO "\n");
if (count >= 16) {
- ds_dump_status(buf, "enable flag", 0);
- ds_dump_status(buf, "1-wire speed", 1);
- ds_dump_status(buf, "strong pullup duration", 2);
- ds_dump_status(buf, "programming pulse duration", 3);
- ds_dump_status(buf, "pulldown slew rate control", 4);
- ds_dump_status(buf, "write-1 low time", 5);
- ds_dump_status(buf, "data sample offset/write-0 recovery time", 6);
- ds_dump_status(buf, "reserved (test register)", 7);
- ds_dump_status(buf, "device status flags", 8);
- ds_dump_status(buf, "communication command byte 1", 9);
- ds_dump_status(buf, "communication command byte 2", 10);
- ds_dump_status(buf, "communication command buffer status", 11);
- ds_dump_status(buf, "1-wire data output buffer status", 12);
- ds_dump_status(buf, "1-wire data input buffer status", 13);
- ds_dump_status(buf, "reserved", 14);
- ds_dump_status(buf, "reserved", 15);
+ ds_print_msg(buf, "enable flag", 0);
+ ds_print_msg(buf, "1-wire speed", 1);
+ ds_print_msg(buf, "strong pullup duration", 2);
+ ds_print_msg(buf, "programming pulse duration", 3);
+ ds_print_msg(buf, "pulldown slew rate control", 4);
+ ds_print_msg(buf, "write-1 low time", 5);
+ ds_print_msg(buf, "data sample offset/write-0 recovery time",
+ 6);
+ ds_print_msg(buf, "reserved (test register)", 7);
+ ds_print_msg(buf, "device status flags", 8);
+ ds_print_msg(buf, "communication command byte 1", 9);
+ ds_print_msg(buf, "communication command byte 2", 10);
+ ds_print_msg(buf, "communication command buffer status", 11);
+ ds_print_msg(buf, "1-wire data output buffer status", 12);
+ ds_print_msg(buf, "1-wire data input buffer status", 13);
+ ds_print_msg(buf, "reserved", 14);
+ ds_print_msg(buf, "reserved", 15);
}
-
- memcpy(st, buf, sizeof(*st));
-
- if (st->status & ST_EPOF) {
- printk(KERN_INFO "Resetting device after ST_EPOF.\n");
- err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
- if (err)
- return err;
- count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
- if (count < 0)
- return err;
- }
-#if 0
- if (st->status & ST_IDLE) {
- printk(KERN_INFO "Resetting pulse after ST_IDLE.\n");
- err = ds_start_pulse(dev, PULLUP_PULSE_DURATION);
- if (err)
- return err;
+ for (i = 16; i < count; ++i) {
+ if (buf[i] == RR_DETECT) {
+ ds_print_msg(buf, "new device detect", i);
+ continue;
+ }
+ ds_print_msg(buf, "Result Register Value: ", i);
+ if (buf[i] & RR_NRS)
+ printk(KERN_INFO "NRS: Reset no presence or ...\n");
+ if (buf[i] & RR_SH)
+ printk(KERN_INFO "SH: short on reset or set path\n");
+ if (buf[i] & RR_APP)
+ printk(KERN_INFO "APP: alarming presence on reset\n");
+ if (buf[i] & RR_VPP)
+ printk(KERN_INFO "VPP: 12V expected not seen\n");
+ if (buf[i] & RR_CMP)
+ printk(KERN_INFO "CMP: compare error\n");
+ if (buf[i] & RR_CRC)
+ printk(KERN_INFO "CRC: CRC error detected\n");
+ if (buf[i] & RR_RDP)
+ printk(KERN_INFO "RDP: redirected page\n");
+ if (buf[i] & RR_EOS)
+ printk(KERN_INFO "EOS: end of search error\n");
}
-#endif
+}
- return err;
+static void ds_reset_device(struct ds_device *dev)
+{
+ ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+ /* Always allow strong pullup which allow individual writes to use
+ * the strong pullup.
+ */
+ if (ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE))
+ printk(KERN_ERR "ds_reset_device: "
+ "Error allowing strong pullup\n");
+ /* Chip strong pullup time was cleared. */
+ if (dev->spu_sleep) {
+ /* lower 4 bits are 0, see ds_set_pullup */
+ u8 del = dev->spu_sleep>>4;
+ if (ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del))
+ printk(KERN_ERR "ds_reset_device: "
+ "Error setting duration\n");
+ }
}
static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
@@ -311,13 +347,27 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
int count, err;
struct ds_status st;
+ /* Careful on size. If size is less than what is available in
+ * the input buffer, the device fails the bulk transfer and
+ * clears the input buffer. It could read the maximum size of
+ * the data buffer, but then do you return the first, last, or
+ * some set of the middle size bytes? As long as the rest of
+ * the code is correct there will be size bytes waiting. A
+ * call to ds_wait_status will wait until the device is idle
+ * and any data to be received would have been available.
+ */
count = 0;
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
buf, size, &count, 1000);
if (err < 0) {
+ u8 buf[ST_SIZE];
+ int count;
+
printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
- ds_recv_status(dev, &st);
+
+ count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+ ds_dump_status(dev, buf, count);
return err;
}
@@ -341,7 +391,8 @@ static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
count = 0;
err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
if (err < 0) {
- printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
+ printk(KERN_ERR "Failed to write 1-wire data to ep0x%x: "
+ "err=%d.\n", dev->ep[EP_DATA_OUT], err);
return err;
}
@@ -354,7 +405,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
{
struct ds_status st;
int count = 0, err = 0;
- u8 buf[0x20];
+ u8 buf[ST_SIZE];
do {
err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
@@ -397,7 +448,7 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
if (err)
return err;
- err = ds_recv_status(dev, st);
+ err = ds_dump_status(dev, st);
return err;
}
@@ -406,10 +457,11 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
{
- u8 buf[0x20];
+ u8 buf[ST_SIZE];
int err, count = 0;
do {
+ st->status = 0;
err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
#if 0
if (err >= 0) {
@@ -420,33 +472,49 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
printk("\n");
}
#endif
- } while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100);
+ } while (!(st->status & ST_IDLE) && !(err < 0) && ++count < 100);
+ if (err >= 16 && st->status & ST_EPOF) {
+ printk(KERN_INFO "Resetting device after ST_EPOF.\n");
+ ds_reset_device(dev);
+ /* Always dump the device status. */
+ count = 101;
+ }
+
+ /* Dump the status for errors or if there is extended return data.
+ * The extended status includes new device detection (maybe someone
+ * can do something with it).
+ */
+ if (err > 16 || count >= 100 || err < 0)
+ ds_dump_status(dev, buf, err);
- if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
- ds_recv_status(dev, st);
+ /* Extended data isn't an error. Well, a short is, but the dump
+ * would have already told the user that and we can't do anything
+ * about it in software anyway.
+ */
+ if (count >= 100 || err < 0)
return -1;
- } else
+ else
return 0;
}
-static int ds_reset(struct ds_device *dev, struct ds_status *st)
+static int ds_reset(struct ds_device *dev)
{
int err;
- //err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE);
- err = ds_send_control(dev, 0x43, SPEED_NORMAL);
+ /* Other potentionally interesting flags for reset.
+ *
+ * COMM_NTF: Return result register feedback. This could be used to
+ * detect some conditions such as short, alarming presence, or
+ * detect if a new device was detected.
+ *
+ * COMM_SE which allows SPEED_NORMAL, SPEED_FLEXIBLE, SPEED_OVERDRIVE:
+ * Select the data transfer rate.
+ */
+ err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_IM, SPEED_NORMAL);
if (err)
return err;
- ds_wait_status(dev, st);
-#if 0
- if (st->command_buffer_status) {
- printk(KERN_INFO "Short circuit.\n");
- return -EIO;
- }
-#endif
-
return 0;
}
@@ -471,60 +539,43 @@ static int ds_set_speed(struct ds_device *dev, int speed)
}
#endif /* 0 */
-static int ds_start_pulse(struct ds_device *dev, int delay)
+static int ds_set_pullup(struct ds_device *dev, int delay)
{
- int err;
+ int err = 0;
u8 del = 1 + (u8)(delay >> 4);
- struct ds_status st;
-
-#if 0
- err = ds_stop_pulse(dev, 10);
- if (err)
+ /* Just storing delay would not get the trunication and roundup. */
+ int ms = del<<4;
+
+ /* Enable spu_bit if a delay is set. */
+ dev->spu_bit = delay ? COMM_SPU : 0;
+ /* If delay is zero, it has already been disabled, if the time is
+ * the same as the hardware was last programmed to, there is also
+ * nothing more to do. Compare with the recalculated value ms
+ * rather than del or delay which can have a different value.
+ */
+ if (delay == 0 || ms == dev->spu_sleep)
return err;
- err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
- if (err)
- return err;
-#endif
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
if (err)
return err;
- err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0);
- if (err)
- return err;
-
- mdelay(delay);
-
- ds_wait_status(dev, &st);
+ dev->spu_sleep = ms;
return err;
}
static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
{
- int err, count;
+ int err;
struct ds_status st;
- u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
- u16 cmd;
- err = ds_send_control(dev, value, 0);
+ err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit ? COMM_D : 0),
+ 0);
if (err)
return err;
- count = 0;
- do {
- err = ds_wait_status(dev, &st);
- if (err)
- return err;
-
- cmd = st.command0 | (st.command1 << 8);
- } while (cmd != value && ++count < 10);
-
- if (err < 0 || count >= 10) {
- printk(KERN_ERR "Failed to obtain status.\n");
- return -EINVAL;
- }
+ ds_wait_status(dev, &st);
err = ds_recv_data(dev, tbit, sizeof(*tbit));
if (err < 0)
@@ -533,12 +584,18 @@ static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
return 0;
}
+#if 0
static int ds_write_bit(struct ds_device *dev, u8 bit)
{
int err;
struct ds_status st;
- err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
+ /* Set COMM_ICP to write without a readback. Note, this will
+ * produce one time slot, a down followed by an up with COMM_D
+ * only determing the timing.
+ */
+ err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_ICP |
+ (bit ? COMM_D : 0), 0);
if (err)
return err;
@@ -546,6 +603,7 @@ static int ds_write_bit(struct ds_device *dev, u8 bit)
return 0;
}
+#endif
static int ds_write_byte(struct ds_device *dev, u8 byte)
{
@@ -553,10 +611,13 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
struct ds_status st;
u8 rbyte;
- err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
+ err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte);
if (err)
return err;
+ if (dev->spu_bit)
+ msleep(dev->spu_sleep);
+
err = ds_wait_status(dev, &st);
if (err)
return err;
@@ -565,8 +626,6 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
if (err < 0)
return err;
- ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
return !(byte == rbyte);
}
@@ -602,7 +661,7 @@ static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
if (err < 0)
return err;
- err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+ err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM, len);
if (err)
return err;
@@ -623,54 +682,122 @@ static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
if (err < 0)
return err;
- ds_wait_status(dev, &st);
-
- err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+ err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | dev->spu_bit, len);
if (err)
return err;
+ if (dev->spu_bit)
+ msleep(dev->spu_sleep);
+
ds_wait_status(dev, &st);
err = ds_recv_data(dev, buf, len);
if (err < 0)
return err;
- ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
return !(err == len);
}
-#if 0
-
-static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
+static void ds9490r_search(void *data, struct w1_master *master,
+ u8 search_type, w1_slave_found_callback callback)
{
+ /* When starting with an existing id, the first id returned will
+ * be that device (if it is still on the bus most likely).
+ *
+ * If the number of devices found is less than or equal to the
+ * search_limit, that number of IDs will be returned. If there are
+ * more, search_limit IDs will be returned followed by a non-zero
+ * discrepency value.
+ */
+ struct ds_device *dev = data;
int err;
u16 value, index;
struct ds_status st;
+ u8 st_buf[ST_SIZE];
+ int search_limit;
+ int found = 0;
+ int i;
- memset(buf, 0, sizeof(buf));
+ /* DS18b20 spec, 13.16 ms per device, 75 per second, sleep for
+ * discovering 8 devices (1 bulk transfer and 1/2 FIFO size) at a time.
+ */
+ const unsigned long jtime = msecs_to_jiffies(1000*8/75);
+ /* FIFO 128 bytes, bulk packet size 64, read a multiple of the
+ * packet size.
+ */
+ u64 buf[2*64/8];
- err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
- if (err)
- return err;
+ mutex_lock(&master->bus_mutex);
- ds_wait_status(ds_dev, &st);
+ /* address to start searching at */
+ if (ds_send_data(dev, (u8 *)&master->search_id, 8) < 0)
+ goto search_out;
+ master->search_id = 0;
- value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
- index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8);
- err = ds_send_control(ds_dev, value, index);
- if (err)
- return err;
+ value = COMM_SEARCH_ACCESS | COMM_IM | COMM_RST | COMM_SM | COMM_F |
+ COMM_RTS;
+ search_limit = master->max_slave_count;
+ if (search_limit > 255)
+ search_limit = 0;
+ index = search_type | (search_limit << 8);
+ if (ds_send_control(dev, value, index) < 0)
+ goto search_out;
- ds_wait_status(ds_dev, &st);
+ do {
+ schedule_timeout(jtime);
- err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number);
- if (err < 0)
- return err;
+ if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) <
+ sizeof(st)) {
+ break;
+ }
- return err/8;
+ if (st.data_in_buffer_status) {
+ /* Bulk in can receive partial ids, but when it does
+ * they fail crc and will be discarded anyway.
+ * That has only been seen when status in buffer
+ * is 0 and bulk is read anyway, so don't read
+ * bulk without first checking if status says there
+ * is data to read.
+ */
+ err = ds_recv_data(dev, (u8 *)buf, sizeof(buf));
+ if (err < 0)
+ break;
+ for (i = 0; i < err/8; ++i) {
+ ++found;
+ if (found <= search_limit)
+ callback(master, buf[i]);
+ /* can't know if there will be a discrepancy
+ * value after until the next id */
+ if (found == search_limit)
+ master->search_id = buf[i];
+ }
+ }
+
+ if (test_bit(W1_ABORT_SEARCH, &master->flags))
+ break;
+ } while (!(st.status & (ST_IDLE | ST_HALT)));
+
+ /* only continue the search if some weren't found */
+ if (found <= search_limit) {
+ master->search_id = 0;
+ } else if (!test_bit(W1_WARN_MAX_COUNT, &master->flags)) {
+ /* Only max_slave_count will be scanned in a search,
+ * but it will start where it left off next search
+ * until all ids are identified and then it will start
+ * over. A continued search will report the previous
+ * last id as the first id (provided it is still on the
+ * bus).
+ */
+ dev_info(&dev->udev->dev, "%s: max_slave_count %d reached, "
+ "will continue next search.\n", __func__,
+ master->max_slave_count);
+ set_bit(W1_WARN_MAX_COUNT, &master->flags);
+ }
+search_out:
+ mutex_unlock(&master->bus_mutex);
}
+#if 0
static int ds_match_access(struct ds_device *dev, u64 init)
{
int err;
@@ -728,6 +855,7 @@ static u8 ds9490r_touch_bit(void *data, u8 bit)
return ret;
}
+#if 0
static void ds9490r_write_bit(void *data, u8 bit)
{
struct ds_device *dev = data;
@@ -735,13 +863,6 @@ static void ds9490r_write_bit(void *data, u8 bit)
ds_write_bit(dev, bit);
}
-static void ds9490r_write_byte(void *data, u8 byte)
-{
- struct ds_device *dev = data;
-
- ds_write_byte(dev, byte);
-}
-
static u8 ds9490r_read_bit(void *data)
{
struct ds_device *dev = data;
@@ -754,6 +875,14 @@ static u8 ds9490r_read_bit(void *data)
return bit & 1;
}
+#endif
+
+static void ds9490r_write_byte(void *data, u8 byte)
+{
+ struct ds_device *dev = data;
+
+ ds_write_byte(dev, byte);
+}
static u8 ds9490r_read_byte(void *data)
{
@@ -790,31 +919,59 @@ static u8 ds9490r_read_block(void *data, u8 *buf, int len)
static u8 ds9490r_reset(void *data)
{
struct ds_device *dev = data;
- struct ds_status st;
int err;
- memset(&st, 0, sizeof(st));
-
- err = ds_reset(dev, &st);
+ err = ds_reset(dev);
if (err)
return 1;
return 0;
}
+static u8 ds9490r_set_pullup(void *data, int delay)
+{
+ struct ds_device *dev = data;
+
+ if (ds_set_pullup(dev, delay))
+ return 1;
+
+ return 0;
+}
+
static int ds_w1_init(struct ds_device *dev)
{
memset(&dev->master, 0, sizeof(struct w1_bus_master));
+ /* Reset the device as it can be in a bad state.
+ * This is necessary because a block write will wait for data
+ * to be placed in the output buffer and block any later
+ * commands which will keep accumulating and the device will
+ * not be idle. Another case is removing the ds2490 module
+ * while a bus search is in progress, somehow a few commands
+ * get through, but the input transfers fail leaving data in
+ * the input buffer. This will cause the next read to fail
+ * see the note in ds_recv_data.
+ */
+ ds_reset_device(dev);
+
dev->master.data = dev;
dev->master.touch_bit = &ds9490r_touch_bit;
+ /* read_bit and write_bit in w1_bus_master are expected to set and
+ * sample the line level. For write_bit that means it is expected to
+ * set it to that value and leave it there. ds2490 only supports an
+ * individual time slot at the lowest level. The requirement from
+ * pulling the bus state down to reading the state is 15us, something
+ * that isn't realistic on the USB bus anyway.
dev->master.read_bit = &ds9490r_read_bit;
dev->master.write_bit = &ds9490r_write_bit;
+ */
dev->master.read_byte = &ds9490r_read_byte;
dev->master.write_byte = &ds9490r_write_byte;
dev->master.read_block = &ds9490r_read_block;
dev->master.write_block = &ds9490r_write_block;
dev->master.reset_bus = &ds9490r_reset;
+ dev->master.set_pullup = &ds9490r_set_pullup;
+ dev->master.search = &ds9490r_search;
return w1_add_master_device(&dev->master);
}
@@ -831,9 +988,9 @@ static int ds_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *endpoint;
struct usb_host_interface *iface_desc;
struct ds_device *dev;
- int i, err;
+ int i, err, alt;
- dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct ds_device), GFP_KERNEL);
if (!dev) {
printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
return -ENOMEM;
@@ -847,20 +1004,25 @@ static int ds_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
- err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
+ err = usb_reset_configuration(dev->udev);
if (err) {
- printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
- intf->altsetting[0].desc.bInterfaceNumber, err);
+ dev_err(&dev->udev->dev,
+ "Failed to reset configuration: err=%d.\n", err);
goto err_out_clear;
}
- err = usb_reset_configuration(dev->udev);
+ /* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */
+ alt = 3;
+ err = usb_set_interface(dev->udev,
+ intf->altsetting[alt].desc.bInterfaceNumber, alt);
if (err) {
- printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
+ dev_err(&dev->udev->dev, "Failed to set alternative setting %d "
+ "for %d interface: err=%d.\n", alt,
+ intf->altsetting[alt].desc.bInterfaceNumber, err);
goto err_out_clear;
}
- iface_desc = &intf->altsetting[0];
+ iface_desc = &intf->altsetting[alt];
if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
err = -EINVAL;
@@ -921,27 +1083,8 @@ static void ds_disconnect(struct usb_interface *intf)
kfree(dev);
}
-static int ds_init(void)
-{
- int err;
-
- err = usb_register(&ds_driver);
- if (err) {
- printk(KERN_INFO "Failed to register DS9490R USB device: err=%d.\n", err);
- return err;
- }
-
- return 0;
-}
-
-static void ds_fini(void)
-{
- usb_deregister(&ds_driver);
-}
-
-module_init(ds_init);
-module_exit(ds_fini);
+module_usb_driver(ds_driver);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)");
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
index 1550431ccb6..d8667b0212d 100644
--- a/drivers/w1/masters/matrox_w1.c
+++ b/drivers/w1/masters/matrox_w1.c
@@ -1,7 +1,7 @@
/*
* matrox_w1.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
*/
#include <asm/types.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/io.h>
#include <linux/delay.h>
@@ -39,7 +39,7 @@
#include "../w1_log.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio).");
static struct pci_device_id matrox_w1_tbl[] = {
@@ -48,14 +48,14 @@ static struct pci_device_id matrox_w1_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
-static int __devinit matrox_w1_probe(struct pci_dev *, const struct pci_device_id *);
-static void __devexit matrox_w1_remove(struct pci_dev *);
+static int matrox_w1_probe(struct pci_dev *, const struct pci_device_id *);
+static void matrox_w1_remove(struct pci_dev *);
static struct pci_driver matrox_w1_pci_driver = {
.name = "matrox_w1",
.id_table = matrox_w1_tbl,
.probe = matrox_w1_probe,
- .remove = __devexit_p(matrox_w1_remove),
+ .remove = matrox_w1_remove,
};
/*
@@ -152,7 +152,7 @@ static void matrox_w1_hw_init(struct matrox_device *dev)
matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
}
-static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct matrox_device *dev;
int err;
@@ -220,7 +220,7 @@ err_out_free_device:
return err;
}
-static void __devexit matrox_w1_remove(struct pci_dev *pdev)
+static void matrox_w1_remove(struct pci_dev *pdev)
{
struct matrox_device *dev = pci_get_drvdata(pdev);
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c
new file mode 100644
index 00000000000..a5df5e89d45
--- /dev/null
+++ b/drivers/w1/masters/mxc_w1.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Luotao Fu, kernel@pengutronix.de
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+/* According to the mx27 Datasheet the reset procedure should take up to about
+ * 1350us. We set the timeout to 500*100us = 50ms for sure */
+#define MXC_W1_RESET_TIMEOUT 500
+
+/*
+ * MXC W1 Register offsets
+ */
+#define MXC_W1_CONTROL 0x00
+# define MXC_W1_CONTROL_RDST BIT(3)
+# define MXC_W1_CONTROL_WR(x) BIT(5 - (x))
+# define MXC_W1_CONTROL_PST BIT(6)
+# define MXC_W1_CONTROL_RPP BIT(7)
+#define MXC_W1_TIME_DIVIDER 0x02
+#define MXC_W1_RESET 0x04
+
+struct mxc_w1_device {
+ void __iomem *regs;
+ struct clk *clk;
+ struct w1_bus_master bus_master;
+};
+
+/*
+ * this is the low level routine to
+ * reset the device on the One Wire interface
+ * on the hardware
+ */
+static u8 mxc_w1_ds2_reset_bus(void *data)
+{
+ u8 reg_val;
+ unsigned int timeout_cnt = 0;
+ struct mxc_w1_device *dev = data;
+
+ writeb(MXC_W1_CONTROL_RPP, (dev->regs + MXC_W1_CONTROL));
+
+ while (1) {
+ reg_val = readb(dev->regs + MXC_W1_CONTROL);
+
+ if (!(reg_val & MXC_W1_CONTROL_RPP) ||
+ timeout_cnt > MXC_W1_RESET_TIMEOUT)
+ break;
+ else
+ timeout_cnt++;
+
+ udelay(100);
+ }
+ return !(reg_val & MXC_W1_CONTROL_PST);
+}
+
+/*
+ * this is the low level routine to read/write a bit on the One Wire
+ * interface on the hardware. It does write 0 if parameter bit is set
+ * to 0, otherwise a write 1/read.
+ */
+static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
+{
+ struct mxc_w1_device *mdev = data;
+ void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL;
+ unsigned int timeout_cnt = 400; /* Takes max. 120us according to
+ * datasheet.
+ */
+
+ writeb(MXC_W1_CONTROL_WR(bit), ctrl_addr);
+
+ while (timeout_cnt--) {
+ if (!(readb(ctrl_addr) & MXC_W1_CONTROL_WR(bit)))
+ break;
+
+ udelay(1);
+ }
+
+ return !!(readb(ctrl_addr) & MXC_W1_CONTROL_RDST);
+}
+
+static int mxc_w1_probe(struct platform_device *pdev)
+{
+ struct mxc_w1_device *mdev;
+ unsigned long clkrate;
+ struct resource *res;
+ unsigned int clkdiv;
+ int err;
+
+ mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
+ GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+
+ mdev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mdev->clk))
+ return PTR_ERR(mdev->clk);
+
+ clkrate = clk_get_rate(mdev->clk);
+ if (clkrate < 10000000)
+ dev_warn(&pdev->dev,
+ "Low clock frequency causes improper function\n");
+
+ clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000);
+ clkrate /= clkdiv;
+ if ((clkrate < 980000) || (clkrate > 1020000))
+ dev_warn(&pdev->dev,
+ "Incorrect time base frequency %lu Hz\n", clkrate);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mdev->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mdev->regs))
+ return PTR_ERR(mdev->regs);
+
+ err = clk_prepare_enable(mdev->clk);
+ if (err)
+ return err;
+
+ writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
+
+ mdev->bus_master.data = mdev;
+ mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
+ mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
+
+ platform_set_drvdata(pdev, mdev);
+
+ err = w1_add_master_device(&mdev->bus_master);
+ if (err)
+ clk_disable_unprepare(mdev->clk);
+
+ return err;
+}
+
+/*
+ * disassociate the w1 device from the driver
+ */
+static int mxc_w1_remove(struct platform_device *pdev)
+{
+ struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
+
+ w1_remove_master_device(&mdev->bus_master);
+
+ clk_disable_unprepare(mdev->clk);
+
+ return 0;
+}
+
+static struct of_device_id mxc_w1_dt_ids[] = {
+ { .compatible = "fsl,imx21-owire" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
+
+static struct platform_driver mxc_w1_driver = {
+ .driver = {
+ .name = "mxc_w1",
+ .owner = THIS_MODULE,
+ .of_match_table = mxc_w1_dt_ids,
+ },
+ .probe = mxc_w1_probe,
+ .remove = mxc_w1_remove,
+};
+module_platform_driver(mxc_w1_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductors Inc");
+MODULE_DESCRIPTION("Driver for One-Wire on MXC");
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
new file mode 100644
index 00000000000..9900e8ec739
--- /dev/null
+++ b/drivers/w1/masters/omap_hdq.c
@@ -0,0 +1,635 @@
+/*
+ * drivers/w1/masters/omap_hdq.c
+ *
+ * Copyright (C) 2007,2012 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/pm_runtime.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#define MOD_NAME "OMAP_HDQ:"
+
+#define OMAP_HDQ_REVISION 0x00
+#define OMAP_HDQ_TX_DATA 0x04
+#define OMAP_HDQ_RX_DATA 0x08
+#define OMAP_HDQ_CTRL_STATUS 0x0c
+#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK (1<<6)
+#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE (1<<5)
+#define OMAP_HDQ_CTRL_STATUS_GO (1<<4)
+#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION (1<<2)
+#define OMAP_HDQ_CTRL_STATUS_DIR (1<<1)
+#define OMAP_HDQ_CTRL_STATUS_MODE (1<<0)
+#define OMAP_HDQ_INT_STATUS 0x10
+#define OMAP_HDQ_INT_STATUS_TXCOMPLETE (1<<2)
+#define OMAP_HDQ_INT_STATUS_RXCOMPLETE (1<<1)
+#define OMAP_HDQ_INT_STATUS_TIMEOUT (1<<0)
+#define OMAP_HDQ_SYSCONFIG 0x14
+#define OMAP_HDQ_SYSCONFIG_SOFTRESET (1<<1)
+#define OMAP_HDQ_SYSCONFIG_AUTOIDLE (1<<0)
+#define OMAP_HDQ_SYSSTATUS 0x18
+#define OMAP_HDQ_SYSSTATUS_RESETDONE (1<<0)
+
+#define OMAP_HDQ_FLAG_CLEAR 0
+#define OMAP_HDQ_FLAG_SET 1
+#define OMAP_HDQ_TIMEOUT (HZ/5)
+
+#define OMAP_HDQ_MAX_USER 4
+
+static DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue);
+static int w1_id;
+
+struct hdq_data {
+ struct device *dev;
+ void __iomem *hdq_base;
+ /* lock status update */
+ struct mutex hdq_mutex;
+ int hdq_usecount;
+ u8 hdq_irqstatus;
+ /* device lock */
+ spinlock_t hdq_spinlock;
+ /*
+ * Used to control the call to omap_hdq_get and omap_hdq_put.
+ * HDQ Protocol: Write the CMD|REG_address first, followed by
+ * the data wrire or read.
+ */
+ int init_trans;
+};
+
+static int omap_hdq_probe(struct platform_device *pdev);
+static int omap_hdq_remove(struct platform_device *pdev);
+
+static struct platform_driver omap_hdq_driver = {
+ .probe = omap_hdq_probe,
+ .remove = omap_hdq_remove,
+ .driver = {
+ .name = "omap_hdq",
+ },
+};
+
+static u8 omap_w1_read_byte(void *_hdq);
+static void omap_w1_write_byte(void *_hdq, u8 byte);
+static u8 omap_w1_reset_bus(void *_hdq);
+static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
+ u8 search_type, w1_slave_found_callback slave_found);
+
+
+static struct w1_bus_master omap_w1_master = {
+ .read_byte = omap_w1_read_byte,
+ .write_byte = omap_w1_write_byte,
+ .reset_bus = omap_w1_reset_bus,
+ .search = omap_w1_search_bus,
+};
+
+/* HDQ register I/O routines */
+static inline u8 hdq_reg_in(struct hdq_data *hdq_data, u32 offset)
+{
+ return __raw_readl(hdq_data->hdq_base + offset);
+}
+
+static inline void hdq_reg_out(struct hdq_data *hdq_data, u32 offset, u8 val)
+{
+ __raw_writel(val, hdq_data->hdq_base + offset);
+}
+
+static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
+ u8 val, u8 mask)
+{
+ u8 new_val = (__raw_readl(hdq_data->hdq_base + offset) & ~mask)
+ | (val & mask);
+ __raw_writel(new_val, hdq_data->hdq_base + offset);
+
+ return new_val;
+}
+
+/*
+ * Wait for one or more bits in flag change.
+ * HDQ_FLAG_SET: wait until any bit in the flag is set.
+ * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared.
+ * return 0 on success and -ETIMEDOUT in the case of timeout.
+ */
+static int hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
+ u8 flag, u8 flag_set, u8 *status)
+{
+ int ret = 0;
+ unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+
+ if (flag_set == OMAP_HDQ_FLAG_CLEAR) {
+ /* wait for the flag clear */
+ while (((*status = hdq_reg_in(hdq_data, offset)) & flag)
+ && time_before(jiffies, timeout)) {
+ schedule_timeout_uninterruptible(1);
+ }
+ if (*status & flag)
+ ret = -ETIMEDOUT;
+ } else if (flag_set == OMAP_HDQ_FLAG_SET) {
+ /* wait for the flag set */
+ while (!((*status = hdq_reg_in(hdq_data, offset)) & flag)
+ && time_before(jiffies, timeout)) {
+ schedule_timeout_uninterruptible(1);
+ }
+ if (!(*status & flag))
+ ret = -ETIMEDOUT;
+ } else
+ return -EINVAL;
+
+ return ret;
+}
+
+/* write out a byte and fill *status with HDQ_INT_STATUS */
+static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
+{
+ int ret;
+ u8 tmp_status;
+ unsigned long irqflags;
+
+ *status = 0;
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ /* clear interrupt flags via a dummy read */
+ hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+ /* ISR loads it with new INT_STATUS */
+ hdq_data->hdq_irqstatus = 0;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+ hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
+
+ /* set the GO bit */
+ hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
+ OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+ /* wait for the TXCOMPLETE bit */
+ ret = wait_event_timeout(hdq_wait_queue,
+ hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+ if (ret == 0) {
+ dev_dbg(hdq_data->dev, "TX wait elapsed\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ *status = hdq_data->hdq_irqstatus;
+ /* check irqstatus */
+ if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
+ dev_dbg(hdq_data->dev, "timeout waiting for"
+ " TXCOMPLETE/RXCOMPLETE, %x", *status);
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ /* wait for the GO bit return to zero */
+ ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_GO,
+ OMAP_HDQ_FLAG_CLEAR, &tmp_status);
+ if (ret) {
+ dev_dbg(hdq_data->dev, "timeout waiting GO bit"
+ " return to zero, %x", tmp_status);
+ }
+
+out:
+ return ret;
+}
+
+/* HDQ Interrupt service routine */
+static irqreturn_t hdq_isr(int irq, void *_hdq)
+{
+ struct hdq_data *hdq_data = _hdq;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+ dev_dbg(hdq_data->dev, "hdq_isr: %x", hdq_data->hdq_irqstatus);
+
+ if (hdq_data->hdq_irqstatus &
+ (OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
+ | OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+ /* wake up sleeping process */
+ wake_up(&hdq_wait_queue);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* HDQ Mode: always return success */
+static u8 omap_w1_reset_bus(void *_hdq)
+{
+ return 0;
+}
+
+/* W1 search callback function */
+static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
+ u8 search_type, w1_slave_found_callback slave_found)
+{
+ u64 module_id, rn_le, cs, id;
+
+ if (w1_id)
+ module_id = w1_id;
+ else
+ module_id = 0x1;
+
+ rn_le = cpu_to_le64(module_id);
+ /*
+ * HDQ might not obey truly the 1-wire spec.
+ * So calculate CRC based on module parameter.
+ */
+ cs = w1_calc_crc8((u8 *)&rn_le, 7);
+ id = (cs << 56) | module_id;
+
+ slave_found(master_dev, id);
+}
+
+static int _omap_hdq_reset(struct hdq_data *hdq_data)
+{
+ int ret;
+ u8 tmp_status;
+
+ hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_SOFTRESET);
+ /*
+ * Select HDQ mode & enable clocks.
+ * It is observed that INT flags can't be cleared via a read and GO/INIT
+ * won't return to zero if interrupt is disabled. So we always enable
+ * interrupt.
+ */
+ hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+ OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+
+ /* wait for reset to complete */
+ ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS,
+ OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status);
+ if (ret)
+ dev_dbg(hdq_data->dev, "timeout waiting HDQ reset, %x",
+ tmp_status);
+ else {
+ hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+ OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+ hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+ OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+ }
+
+ return ret;
+}
+
+/* Issue break pulse to the device */
+static int omap_hdq_break(struct hdq_data *hdq_data)
+{
+ int ret = 0;
+ u8 tmp_status;
+ unsigned long irqflags;
+
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0) {
+ dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+ ret = -EINTR;
+ goto rtn;
+ }
+
+ spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+ /* clear interrupt flags via a dummy read */
+ hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+ /* ISR loads it with new INT_STATUS */
+ hdq_data->hdq_irqstatus = 0;
+ spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+ /* set the INIT and GO bit */
+ hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
+ OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+ OMAP_HDQ_CTRL_STATUS_GO);
+
+ /* wait for the TIMEOUT bit */
+ ret = wait_event_timeout(hdq_wait_queue,
+ hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+ if (ret == 0) {
+ dev_dbg(hdq_data->dev, "break wait elapsed\n");
+ ret = -EINTR;
+ goto out;
+ }
+
+ tmp_status = hdq_data->hdq_irqstatus;
+ /* check irqstatus */
+ if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+ dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x",
+ tmp_status);
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ /*
+ * wait for both INIT and GO bits rerurn to zero.
+ * zero wait time expected for interrupt mode.
+ */
+ ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+ OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR,
+ &tmp_status);
+ if (ret)
+ dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
+ " return to zero, %x", tmp_status);
+
+out:
+ mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+ return ret;
+}
+
+static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
+{
+ int ret = 0;
+ u8 status;
+
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0) {
+ ret = -EINTR;
+ goto rtn;
+ }
+
+ if (!hdq_data->hdq_usecount) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+ hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ 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.
+ */
+ 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);
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ }
+ /* the data is ready. Read it in! */
+ *val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
+out:
+ mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+ return ret;
+
+}
+
+/* Enable clocks and set the controller to HDQ mode */
+static int omap_hdq_get(struct hdq_data *hdq_data)
+{
+ int ret = 0;
+
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0) {
+ ret = -EINTR;
+ goto rtn;
+ }
+
+ if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) {
+ dev_dbg(hdq_data->dev, "attempt to exceed the max use count");
+ ret = -EINVAL;
+ goto out;
+ } else {
+ hdq_data->hdq_usecount++;
+ try_module_get(THIS_MODULE);
+ if (1 == hdq_data->hdq_usecount) {
+
+ pm_runtime_get_sync(hdq_data->dev);
+
+ /* make sure HDQ is out of reset */
+ if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) &
+ OMAP_HDQ_SYSSTATUS_RESETDONE)) {
+ ret = _omap_hdq_reset(hdq_data);
+ if (ret)
+ /* back up the count */
+ hdq_data->hdq_usecount--;
+ } else {
+ /* select HDQ mode & enable clocks */
+ hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+ OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+ OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+ hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+ OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+ hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+ }
+ }
+ }
+
+out:
+ mutex_unlock(&hdq_data->hdq_mutex);
+rtn:
+ return ret;
+}
+
+/* Disable clocks to the module */
+static int omap_hdq_put(struct hdq_data *hdq_data)
+{
+ int ret = 0;
+
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0)
+ return -EINTR;
+
+ if (0 == hdq_data->hdq_usecount) {
+ dev_dbg(hdq_data->dev, "attempt to decrement use count"
+ " when it is zero");
+ ret = -EINVAL;
+ } else {
+ hdq_data->hdq_usecount--;
+ module_put(THIS_MODULE);
+ if (0 == hdq_data->hdq_usecount)
+ pm_runtime_put_sync(hdq_data->dev);
+ }
+ mutex_unlock(&hdq_data->hdq_mutex);
+
+ return ret;
+}
+
+/* Read a byte of data from the device */
+static u8 omap_w1_read_byte(void *_hdq)
+{
+ struct hdq_data *hdq_data = _hdq;
+ u8 val = 0;
+ int ret;
+
+ ret = hdq_read_byte(hdq_data, &val);
+ if (ret) {
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0) {
+ dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+ return -EINTR;
+ }
+ hdq_data->init_trans = 0;
+ mutex_unlock(&hdq_data->hdq_mutex);
+ omap_hdq_put(hdq_data);
+ return -1;
+ }
+
+ /* Write followed by a read, release the module */
+ if (hdq_data->init_trans) {
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0) {
+ dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+ return -EINTR;
+ }
+ hdq_data->init_trans = 0;
+ mutex_unlock(&hdq_data->hdq_mutex);
+ omap_hdq_put(hdq_data);
+ }
+
+ return val;
+}
+
+/* Write a byte of data to the device */
+static void omap_w1_write_byte(void *_hdq, u8 byte)
+{
+ struct hdq_data *hdq_data = _hdq;
+ int ret;
+ u8 status;
+
+ /* First write to initialize the transfer */
+ if (hdq_data->init_trans == 0)
+ omap_hdq_get(hdq_data);
+
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0) {
+ dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+ return;
+ }
+ hdq_data->init_trans++;
+ mutex_unlock(&hdq_data->hdq_mutex);
+
+ ret = hdq_write_byte(hdq_data, byte, &status);
+ if (ret < 0) {
+ dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
+ return;
+ }
+
+ /* Second write, data transferred. Release the module */
+ if (hdq_data->init_trans > 1) {
+ omap_hdq_put(hdq_data);
+ ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+ if (ret < 0) {
+ dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+ return;
+ }
+ hdq_data->init_trans = 0;
+ mutex_unlock(&hdq_data->hdq_mutex);
+ }
+}
+
+static int omap_hdq_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hdq_data *hdq_data;
+ struct resource *res;
+ int ret, irq;
+ u8 rev;
+
+ hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL);
+ if (!hdq_data) {
+ dev_dbg(&pdev->dev, "unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ hdq_data->dev = dev;
+ platform_set_drvdata(pdev, hdq_data);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdq_data->hdq_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdq_data->hdq_base))
+ return PTR_ERR(hdq_data->hdq_base);
+
+ hdq_data->hdq_usecount = 0;
+ mutex_init(&hdq_data->hdq_mutex);
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
+ dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
+ (rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt");
+
+ spin_lock_init(&hdq_data->hdq_spinlock);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENXIO;
+ goto err_irq;
+ }
+
+ ret = devm_request_irq(dev, irq, hdq_isr, 0, "omap_hdq", hdq_data);
+ if (ret < 0) {
+ dev_dbg(&pdev->dev, "could not request irq\n");
+ goto err_irq;
+ }
+
+ omap_hdq_break(hdq_data);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ omap_w1_master.data = hdq_data;
+
+ ret = w1_add_master_device(&omap_w1_master);
+ if (ret) {
+ dev_dbg(&pdev->dev, "Failure in registering w1 master\n");
+ goto err_w1;
+ }
+
+ return 0;
+
+err_irq:
+ pm_runtime_put_sync(&pdev->dev);
+err_w1:
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static int omap_hdq_remove(struct platform_device *pdev)
+{
+ struct hdq_data *hdq_data = platform_get_drvdata(pdev);
+
+ mutex_lock(&hdq_data->hdq_mutex);
+
+ if (hdq_data->hdq_usecount) {
+ dev_dbg(&pdev->dev, "removed when use count is not zero\n");
+ mutex_unlock(&hdq_data->hdq_mutex);
+ return -EBUSY;
+ }
+
+ mutex_unlock(&hdq_data->hdq_mutex);
+
+ /* remove module dependency */
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+module_platform_driver(omap_hdq_driver);
+
+module_param(w1_id, int, S_IRUSR);
+MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("HDQ driver Library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index 9e1138a75e8..1d111e56c8c 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -11,12 +11,37 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/w1-gpio.h>
+#include <linux/gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/delay.h>
#include "../w1.h"
#include "../w1_int.h"
-#include <asm/gpio.h>
+static u8 w1_gpio_set_pullup(void *data, int delay)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ if (delay) {
+ pdata->pullup_duration = delay;
+ } else {
+ if (pdata->pullup_duration) {
+ gpio_direction_output(pdata->pin, 1);
+
+ msleep(pdata->pullup_duration);
+
+ gpio_direction_input(pdata->pin);
+ }
+ pdata->pullup_duration = 0;
+ }
+
+ return 0;
+}
static void w1_gpio_write_bit_dir(void *data, u8 bit)
{
@@ -39,25 +64,94 @@ static u8 w1_gpio_read_bit(void *data)
{
struct w1_gpio_platform_data *pdata = data;
- return gpio_get_value(pdata->pin);
+ return gpio_get_value(pdata->pin) ? 1 : 0;
}
-static int __init w1_gpio_probe(struct platform_device *pdev)
+#if defined(CONFIG_OF)
+static struct of_device_id w1_gpio_dt_ids[] = {
+ { .compatible = "w1-gpio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
+#endif
+
+static int w1_gpio_probe_dt(struct platform_device *pdev)
+{
+ struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+ int gpio;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (of_get_property(np, "linux,open-drain", NULL))
+ pdata->is_open_drain = 1;
+
+ gpio = of_get_gpio(np, 0);
+ if (gpio < 0) {
+ if (gpio != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "Failed to parse gpio property for data pin (%d)\n",
+ gpio);
+
+ return gpio;
+ }
+ pdata->pin = gpio;
+
+ gpio = of_get_gpio(np, 1);
+ if (gpio == -EPROBE_DEFER)
+ return gpio;
+ /* ignore other errors as the pullup gpio is optional */
+ pdata->ext_pullup_enable_pin = gpio;
+
+ pdev->dev.platform_data = pdata;
+
+ return 0;
+}
+
+static int w1_gpio_probe(struct platform_device *pdev)
{
struct w1_bus_master *master;
- struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct w1_gpio_platform_data *pdata;
int err;
- if (!pdata)
+ if (of_have_populated_dt()) {
+ err = w1_gpio_probe_dt(pdev);
+ if (err < 0)
+ return err;
+ }
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No configuration data\n");
return -ENXIO;
+ }
- master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL);
- if (!master)
+ master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master),
+ GFP_KERNEL);
+ if (!master) {
+ dev_err(&pdev->dev, "Out of memory\n");
return -ENOMEM;
+ }
+
+ err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");
+ if (err) {
+ dev_err(&pdev->dev, "gpio_request (pin) failed\n");
+ return err;
+ }
- err = gpio_request(pdata->pin, "w1");
- if (err)
- goto free_master;
+ if (gpio_is_valid(pdata->ext_pullup_enable_pin)) {
+ err = devm_gpio_request_one(&pdev->dev,
+ pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW,
+ "w1 pullup");
+ if (err < 0) {
+ dev_err(&pdev->dev, "gpio_request_one "
+ "(ext_pullup_enable_pin) failed\n");
+ return err;
+ }
+ }
master->data = pdata;
master->read_bit = w1_gpio_read_bit;
@@ -68,56 +162,82 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
} else {
gpio_direction_input(pdata->pin);
master->write_bit = w1_gpio_write_bit_dir;
+ master->set_pullup = w1_gpio_set_pullup;
}
err = w1_add_master_device(master);
- if (err)
- goto free_gpio;
+ if (err) {
+ dev_err(&pdev->dev, "w1_add_master device failed\n");
+ return err;
+ }
- platform_set_drvdata(pdev, master);
+ if (pdata->enable_external_pullup)
+ pdata->enable_external_pullup(1);
- return 0;
+ if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+ gpio_set_value(pdata->ext_pullup_enable_pin, 1);
- free_gpio:
- gpio_free(pdata->pin);
- free_master:
- kfree(master);
+ platform_set_drvdata(pdev, master);
- return err;
+ return 0;
}
-static int __exit w1_gpio_remove(struct platform_device *pdev)
+static int w1_gpio_remove(struct platform_device *pdev)
{
struct w1_bus_master *master = platform_get_drvdata(pdev);
- struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+ if (pdata->enable_external_pullup)
+ pdata->enable_external_pullup(0);
+
+ if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+ gpio_set_value(pdata->ext_pullup_enable_pin, 0);
w1_remove_master_device(master);
- gpio_free(pdata->pin);
- kfree(master);
return 0;
}
-static struct platform_driver w1_gpio_driver = {
- .driver = {
- .name = "w1-gpio",
- .owner = THIS_MODULE,
- },
- .remove = __exit_p(w1_gpio_remove),
-};
+#ifdef CONFIG_PM
-static int __init w1_gpio_init(void)
+static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state)
{
- return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe);
+ struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+ if (pdata->enable_external_pullup)
+ pdata->enable_external_pullup(0);
+
+ return 0;
}
-static void __exit w1_gpio_exit(void)
+static int w1_gpio_resume(struct platform_device *pdev)
{
- platform_driver_unregister(&w1_gpio_driver);
+ struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+ if (pdata->enable_external_pullup)
+ pdata->enable_external_pullup(1);
+
+ return 0;
}
-module_init(w1_gpio_init);
-module_exit(w1_gpio_exit);
+#else
+#define w1_gpio_suspend NULL
+#define w1_gpio_resume NULL
+#endif
+
+static struct platform_driver w1_gpio_driver = {
+ .driver = {
+ .name = "w1-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(w1_gpio_dt_ids),
+ },
+ .probe = w1_gpio_probe,
+ .remove = w1_gpio_remove,
+ .suspend = w1_gpio_suspend,
+ .resume = w1_gpio_resume,
+};
+
+module_platform_driver(w1_gpio_driver);
MODULE_DESCRIPTION("GPIO w1 bus master driver");
MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");