diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/w1 | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/w1')
-rw-r--r-- | kernel/drivers/w1/masters/ds2482.c | 2 | ||||
-rw-r--r-- | kernel/drivers/w1/masters/matrox_w1.c | 16 | ||||
-rw-r--r-- | kernel/drivers/w1/masters/omap_hdq.c | 224 | ||||
-rw-r--r-- | kernel/drivers/w1/masters/w1-gpio.c | 20 | ||||
-rw-r--r-- | kernel/drivers/w1/slaves/w1_bq27000.c | 5 | ||||
-rw-r--r-- | kernel/drivers/w1/slaves/w1_therm.c | 102 | ||||
-rw-r--r-- | kernel/drivers/w1/w1.c | 17 | ||||
-rw-r--r-- | kernel/drivers/w1/w1_int.c | 3 |
8 files changed, 322 insertions, 67 deletions
diff --git a/kernel/drivers/w1/masters/ds2482.c b/kernel/drivers/w1/masters/ds2482.c index e76a9b39a..b05e8fefb 100644 --- a/kernel/drivers/w1/masters/ds2482.c +++ b/kernel/drivers/w1/masters/ds2482.c @@ -93,10 +93,10 @@ static const struct i2c_device_id ds2482_id[] = { { "ds2482", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, ds2482_id); static struct i2c_driver ds2482_driver = { .driver = { - .owner = THIS_MODULE, .name = "ds2482", }, .probe = ds2482_probe, diff --git a/kernel/drivers/w1/masters/matrox_w1.c b/kernel/drivers/w1/masters/matrox_w1.c index d8667b021..3749db8b4 100644 --- a/kernel/drivers/w1/masters/matrox_w1.c +++ b/kernel/drivers/w1/masters/matrox_w1.c @@ -40,7 +40,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); -MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio)."); +MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire protocol) over VGA DDC(matrox gpio)."); static struct pci_device_id matrox_w1_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) }, @@ -232,16 +232,4 @@ static void matrox_w1_remove(struct pci_dev *pdev) } kfree(dev); } - -static int __init matrox_w1_init(void) -{ - return pci_register_driver(&matrox_w1_pci_driver); -} - -static void __exit matrox_w1_fini(void) -{ - pci_unregister_driver(&matrox_w1_pci_driver); -} - -module_init(matrox_w1_init); -module_exit(matrox_w1_fini); +module_pci_driver(matrox_w1_pci_driver); diff --git a/kernel/drivers/w1/masters/omap_hdq.c b/kernel/drivers/w1/masters/omap_hdq.c index e7d448963..0e2f43bcc 100644 --- a/kernel/drivers/w1/masters/omap_hdq.c +++ b/kernel/drivers/w1/masters/omap_hdq.c @@ -17,6 +17,7 @@ #include <linux/io.h> #include <linux/sched.h> #include <linux/pm_runtime.h> +#include <linux/of.h> #include "../w1.h" #include "../w1_int.h" @@ -27,21 +28,23 @@ #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_CTRL_STATUS_SINGLE BIT(7) +#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK BIT(6) +#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE BIT(5) +#define OMAP_HDQ_CTRL_STATUS_GO BIT(4) +#define OMAP_HDQ_CTRL_STATUS_PRESENCE BIT(3) +#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION BIT(2) +#define OMAP_HDQ_CTRL_STATUS_DIR BIT(1) #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_INT_STATUS_TXCOMPLETE BIT(2) +#define OMAP_HDQ_INT_STATUS_RXCOMPLETE BIT(1) +#define OMAP_HDQ_INT_STATUS_TIMEOUT BIT(0) #define OMAP_HDQ_SYSCONFIG 0x14 -#define OMAP_HDQ_SYSCONFIG_SOFTRESET (1<<1) -#define OMAP_HDQ_SYSCONFIG_AUTOIDLE (1<<0) +#define OMAP_HDQ_SYSCONFIG_SOFTRESET BIT(1) +#define OMAP_HDQ_SYSCONFIG_AUTOIDLE BIT(0) +#define OMAP_HDQ_SYSCONFIG_NOIDLE 0x0 #define OMAP_HDQ_SYSSTATUS 0x18 -#define OMAP_HDQ_SYSSTATUS_RESETDONE (1<<0) +#define OMAP_HDQ_SYSSTATUS_RESETDONE BIT(0) #define OMAP_HDQ_FLAG_CLEAR 0 #define OMAP_HDQ_FLAG_SET 1 @@ -67,6 +70,10 @@ struct hdq_data { * the data wrire or read. */ int init_trans; + int rrw; + /* mode: 0-HDQ 1-W1 */ + int mode; + }; static int omap_hdq_probe(struct platform_device *pdev); @@ -74,6 +81,7 @@ static int omap_hdq_remove(struct platform_device *pdev); static const struct of_device_id omap_hdq_dt_ids[] = { { .compatible = "ti,omap3-1w" }, + { .compatible = "ti,am4372-hdq" }, {} }; MODULE_DEVICE_TABLE(of, omap_hdq_dt_ids); @@ -90,15 +98,12 @@ static struct platform_driver omap_hdq_driver = { 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 */ @@ -122,6 +127,15 @@ static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset, return new_val; } +static void hdq_disable_interrupt(struct hdq_data *hdq_data, u32 offset, + u32 mask) +{ + u32 ie; + + ie = readl(hdq_data->hdq_base + offset); + writel(ie & mask, hdq_data->hdq_base + offset); +} + /* * Wait for one or more bits in flag change. * HDQ_FLAG_SET: wait until any bit in the flag is set. @@ -229,13 +243,7 @@ static irqreturn_t hdq_isr(int irq, void *_hdq) return IRQ_HANDLED; } -/* HDQ Mode: always return success */ -static u8 omap_w1_reset_bus(void *_hdq) -{ - return 0; -} - -/* W1 search callback function */ +/* W1 search callback function in HDQ mode */ static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev, u8 search_type, w1_slave_found_callback slave_found) { @@ -262,9 +270,10 @@ 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); + hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, + OMAP_HDQ_SYSCONFIG_SOFTRESET); /* - * Select HDQ mode & enable clocks. + * Select HDQ/1W 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. @@ -282,7 +291,8 @@ static int _omap_hdq_reset(struct hdq_data *hdq_data) else { hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | - OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); + OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK | + hdq_data->mode); hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_AUTOIDLE); } @@ -334,6 +344,18 @@ static int omap_hdq_break(struct hdq_data *hdq_data) ret = -ETIMEDOUT; goto out; } + + /* + * check for the presence detect bit to get + * set to show that the slave is responding + */ + if (!(hdq_reg_in(hdq_data, OMAP_HDQ_CTRL_STATUS) & + OMAP_HDQ_CTRL_STATUS_PRESENCE)) { + dev_dbg(hdq_data->dev, "Presence bit not set\n"); + ret = -ETIMEDOUT; + goto out; + } + /* * wait for both INIT and GO bits rerurn to zero. * zero wait time expected for interrupt mode. @@ -368,6 +390,8 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val) goto out; } + hdq_data->hdq_irqstatus = 0; + 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, @@ -400,7 +424,7 @@ rtn: } -/* Enable clocks and set the controller to HDQ mode */ +/* Enable clocks and set the controller to HDQ/1W mode */ static int omap_hdq_get(struct hdq_data *hdq_data) { int ret = 0; @@ -422,7 +446,7 @@ static int omap_hdq_get(struct hdq_data *hdq_data) pm_runtime_get_sync(hdq_data->dev); - /* make sure HDQ is out of reset */ + /* make sure HDQ/1W is out of reset */ if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) & OMAP_HDQ_SYSSTATUS_RESETDONE)) { ret = _omap_hdq_reset(hdq_data); @@ -430,12 +454,13 @@ static int omap_hdq_get(struct hdq_data *hdq_data) /* back up the count */ hdq_data->hdq_usecount--; } else { - /* select HDQ mode & enable clocks */ + /* select HDQ/1W mode & enable clocks */ hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | - OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); + OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK | + hdq_data->mode); hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, - OMAP_HDQ_SYSCONFIG_AUTOIDLE); + OMAP_HDQ_SYSCONFIG_NOIDLE); hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); } } @@ -456,6 +481,8 @@ static int omap_hdq_put(struct hdq_data *hdq_data) if (ret < 0) return -EINTR; + hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, + OMAP_HDQ_SYSCONFIG_AUTOIDLE); if (0 == hdq_data->hdq_usecount) { dev_dbg(hdq_data->dev, "attempt to decrement use count" " when it is zero"); @@ -471,6 +498,100 @@ static int omap_hdq_put(struct hdq_data *hdq_data) return ret; } +/* + * W1 triplet callback function - used for searching ROM addresses. + * Registered only when controller is in 1-wire mode. + */ +static u8 omap_w1_triplet(void *_hdq, u8 bdir) +{ + u8 id_bit, comp_bit; + int err; + u8 ret = 0x3; /* no slaves responded */ + struct hdq_data *hdq_data = _hdq; + u8 ctrl = OMAP_HDQ_CTRL_STATUS_SINGLE | OMAP_HDQ_CTRL_STATUS_GO | + OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK; + u8 mask = ctrl | OMAP_HDQ_CTRL_STATUS_DIR; + + omap_hdq_get(_hdq); + + err = mutex_lock_interruptible(&hdq_data->hdq_mutex); + if (err < 0) { + dev_dbg(hdq_data->dev, "Could not acquire mutex\n"); + goto rtn; + } + + hdq_data->hdq_irqstatus = 0; + /* read id_bit */ + hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, + ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask); + err = wait_event_timeout(hdq_wait_queue, + (hdq_data->hdq_irqstatus + & OMAP_HDQ_INT_STATUS_RXCOMPLETE), + OMAP_HDQ_TIMEOUT); + if (err == 0) { + dev_dbg(hdq_data->dev, "RX wait elapsed\n"); + goto out; + } + id_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01); + + hdq_data->hdq_irqstatus = 0; + /* read comp_bit */ + hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, + ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask); + err = wait_event_timeout(hdq_wait_queue, + (hdq_data->hdq_irqstatus + & OMAP_HDQ_INT_STATUS_RXCOMPLETE), + OMAP_HDQ_TIMEOUT); + if (err == 0) { + dev_dbg(hdq_data->dev, "RX wait elapsed\n"); + goto out; + } + comp_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01); + + if (id_bit && comp_bit) { + ret = 0x03; /* no slaves responded */ + goto out; + } + if (!id_bit && !comp_bit) { + /* Both bits are valid, take the direction given */ + ret = bdir ? 0x04 : 0; + } else { + /* Only one bit is valid, take that direction */ + bdir = id_bit; + ret = id_bit ? 0x05 : 0x02; + } + + /* write bdir bit */ + hdq_reg_out(_hdq, OMAP_HDQ_TX_DATA, bdir); + hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, ctrl, mask); + err = wait_event_timeout(hdq_wait_queue, + (hdq_data->hdq_irqstatus + & OMAP_HDQ_INT_STATUS_TXCOMPLETE), + OMAP_HDQ_TIMEOUT); + if (err == 0) { + dev_dbg(hdq_data->dev, "TX wait elapsed\n"); + goto out; + } + + hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, 0, + OMAP_HDQ_CTRL_STATUS_SINGLE); + +out: + mutex_unlock(&hdq_data->hdq_mutex); +rtn: + omap_hdq_put(_hdq); + return ret; +} + +/* reset callback */ +static u8 omap_w1_reset_bus(void *_hdq) +{ + omap_hdq_get(_hdq); + omap_hdq_break(_hdq); + omap_hdq_put(_hdq); + return 0; +} + /* Read a byte of data from the device */ static u8 omap_w1_read_byte(void *_hdq) { @@ -478,6 +599,10 @@ static u8 omap_w1_read_byte(void *_hdq) u8 val = 0; int ret; + /* First write to initialize the transfer */ + if (hdq_data->init_trans == 0) + omap_hdq_get(hdq_data); + ret = hdq_read_byte(hdq_data, &val); if (ret) { ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); @@ -491,6 +616,10 @@ static u8 omap_w1_read_byte(void *_hdq) return -1; } + hdq_disable_interrupt(hdq_data, OMAP_HDQ_CTRL_STATUS, + ~OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); + hdq_data->hdq_usecount = 0; + /* Write followed by a read, release the module */ if (hdq_data->init_trans) { ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); @@ -517,6 +646,14 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) if (hdq_data->init_trans == 0) omap_hdq_get(hdq_data); + /* + * We need to reset the slave before + * issuing the SKIP ROM command, else + * the slave will not work. + */ + if (byte == W1_SKIP_ROM) + omap_hdq_break(hdq_data); + ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); if (ret < 0) { dev_dbg(hdq_data->dev, "Could not acquire mutex\n"); @@ -551,6 +688,7 @@ static int omap_hdq_probe(struct platform_device *pdev) struct resource *res; int ret, irq; u8 rev; + const char *mode; hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL); if (!hdq_data) { @@ -567,10 +705,21 @@ static int omap_hdq_probe(struct platform_device *pdev) return PTR_ERR(hdq_data->hdq_base); hdq_data->hdq_usecount = 0; + hdq_data->rrw = 0; mutex_init(&hdq_data->hdq_mutex); pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n"); + goto err_w1; + } + + ret = _omap_hdq_reset(hdq_data); + if (ret) { + dev_dbg(&pdev->dev, "reset failed\n"); + return -EINVAL; + } rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION); dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n", @@ -594,6 +743,15 @@ static int omap_hdq_probe(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); + ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode); + if (ret < 0 || !strcmp(mode, "hdq")) { + hdq_data->mode = 0; + omap_w1_master.search = omap_w1_search_bus; + } else { + hdq_data->mode = 1; + omap_w1_master.triplet = omap_w1_triplet; + } + omap_w1_master.data = hdq_data; ret = w1_add_master_device(&omap_w1_master); @@ -635,8 +793,8 @@ static int omap_hdq_remove(struct platform_device *pdev) 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_PARM_DESC(w1_id, "1-wire id for the slave detection in HDQ mode"); MODULE_AUTHOR("Texas Instruments"); -MODULE_DESCRIPTION("HDQ driver Library"); +MODULE_DESCRIPTION("HDQ-1W driver Library"); MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/w1/masters/w1-gpio.c b/kernel/drivers/w1/masters/w1-gpio.c index 8f7848c62..a373ae69d 100644 --- a/kernel/drivers/w1/masters/w1-gpio.c +++ b/kernel/drivers/w1/masters/w1-gpio.c @@ -198,11 +198,9 @@ static int w1_gpio_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - -static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) +static int __maybe_unused w1_gpio_suspend(struct device *dev) { - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); if (pdata->enable_external_pullup) pdata->enable_external_pullup(0); @@ -210,9 +208,9 @@ static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int w1_gpio_resume(struct platform_device *pdev) +static int __maybe_unused w1_gpio_resume(struct device *dev) { - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); @@ -220,20 +218,16 @@ static int w1_gpio_resume(struct platform_device *pdev) return 0; } -#else -#define w1_gpio_suspend NULL -#define w1_gpio_resume NULL -#endif +static SIMPLE_DEV_PM_OPS(w1_gpio_pm_ops, w1_gpio_suspend, w1_gpio_resume); static struct platform_driver w1_gpio_driver = { .driver = { .name = "w1-gpio", + .pm = &w1_gpio_pm_ops, .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, + .remove = w1_gpio_remove, }; module_platform_driver(w1_gpio_driver); diff --git a/kernel/drivers/w1/slaves/w1_bq27000.c b/kernel/drivers/w1/slaves/w1_bq27000.c index caafb1722..9f4a86b75 100644 --- a/kernel/drivers/w1/slaves/w1_bq27000.c +++ b/kernel/drivers/w1/slaves/w1_bq27000.c @@ -15,7 +15,7 @@ #include <linux/types.h> #include <linux/platform_device.h> #include <linux/mutex.h> -#include <linux/power/bq27x00_battery.h> +#include <linux/power/bq27xxx_battery.h> #include "../w1.h" #include "../w1_int.h" @@ -39,9 +39,10 @@ static int w1_bq27000_read(struct device *dev, unsigned int reg) return val; } -static struct bq27000_platform_data bq27000_battery_info = { +static struct bq27xxx_platform_data bq27000_battery_info = { .read = w1_bq27000_read, .name = "bq27000-battery", + .chip = BQ27000, }; static int w1_bq27000_add_slave(struct w1_slave *sl) diff --git a/kernel/drivers/w1/slaves/w1_therm.c b/kernel/drivers/w1/slaves/w1_therm.c index 55eb86c9e..2f029e8f4 100644 --- a/kernel/drivers/w1/slaves/w1_therm.c +++ b/kernel/drivers/w1/slaves/w1_therm.c @@ -92,13 +92,24 @@ static void w1_therm_remove_slave(struct w1_slave *sl) static ssize_t w1_slave_show(struct device *device, struct device_attribute *attr, char *buf); +static ssize_t w1_seq_show(struct device *device, + struct device_attribute *attr, char *buf); + static DEVICE_ATTR_RO(w1_slave); +static DEVICE_ATTR_RO(w1_seq); static struct attribute *w1_therm_attrs[] = { &dev_attr_w1_slave.attr, NULL, }; + +static struct attribute *w1_ds28ea00_attrs[] = { + &dev_attr_w1_slave.attr, + &dev_attr_w1_seq.attr, + NULL, +}; ATTRIBUTE_GROUPS(w1_therm); +ATTRIBUTE_GROUPS(w1_ds28ea00); static struct w1_family_ops w1_therm_fops = { .add_slave = w1_therm_add_slave, @@ -106,6 +117,12 @@ static struct w1_family_ops w1_therm_fops = { .groups = w1_therm_groups, }; +static struct w1_family_ops w1_ds28ea00_fops = { + .add_slave = w1_therm_add_slave, + .remove_slave = w1_therm_remove_slave, + .groups = w1_ds28ea00_groups, +}; + static struct w1_family w1_therm_family_DS18S20 = { .fid = W1_THERM_DS18S20, .fops = &w1_therm_fops, @@ -123,7 +140,7 @@ static struct w1_family w1_therm_family_DS1822 = { static struct w1_family w1_therm_family_DS28EA00 = { .fid = W1_THERM_DS28EA00, - .fops = &w1_therm_fops, + .fops = &w1_ds28ea00_fops, }; static struct w1_family w1_therm_family_DS1825 = { @@ -316,6 +333,89 @@ post_unlock: return ret; } +#define W1_42_CHAIN 0x99 +#define W1_42_CHAIN_OFF 0x3C +#define W1_42_CHAIN_OFF_INV 0xC3 +#define W1_42_CHAIN_ON 0x5A +#define W1_42_CHAIN_ON_INV 0xA5 +#define W1_42_CHAIN_DONE 0x96 +#define W1_42_CHAIN_DONE_INV 0x69 +#define W1_42_COND_READ 0x0F +#define W1_42_SUCCESS_CONFIRM_BYTE 0xAA +#define W1_42_FINISHED_BYTE 0xFF +static ssize_t w1_seq_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct w1_slave *sl = dev_to_w1_slave(device); + ssize_t c = PAGE_SIZE; + int rv; + int i; + u8 ack; + u64 rn; + struct w1_reg_num *reg_num; + int seq = 0; + + mutex_lock(&sl->master->bus_mutex); + /* Place all devices in CHAIN state */ + if (w1_reset_bus(sl->master)) + goto error; + w1_write_8(sl->master, W1_SKIP_ROM); + w1_write_8(sl->master, W1_42_CHAIN); + w1_write_8(sl->master, W1_42_CHAIN_ON); + w1_write_8(sl->master, W1_42_CHAIN_ON_INV); + msleep(sl->master->pullup_duration); + + /* check for acknowledgment */ + ack = w1_read_8(sl->master); + if (ack != W1_42_SUCCESS_CONFIRM_BYTE) + goto error; + + /* In case the bus fails to send 0xFF, limit*/ + for (i = 0; i <= 64; i++) { + if (w1_reset_bus(sl->master)) + goto error; + + w1_write_8(sl->master, W1_42_COND_READ); + rv = w1_read_block(sl->master, (u8 *)&rn, 8); + reg_num = (struct w1_reg_num *) &rn; + if (reg_num->family == W1_42_FINISHED_BYTE) + break; + if (sl->reg_num.id == reg_num->id) + seq = i; + + w1_write_8(sl->master, W1_42_CHAIN); + w1_write_8(sl->master, W1_42_CHAIN_DONE); + w1_write_8(sl->master, W1_42_CHAIN_DONE_INV); + w1_read_block(sl->master, &ack, sizeof(ack)); + + /* check for acknowledgment */ + ack = w1_read_8(sl->master); + if (ack != W1_42_SUCCESS_CONFIRM_BYTE) + goto error; + + } + + /* Exit from CHAIN state */ + if (w1_reset_bus(sl->master)) + goto error; + w1_write_8(sl->master, W1_SKIP_ROM); + w1_write_8(sl->master, W1_42_CHAIN); + w1_write_8(sl->master, W1_42_CHAIN_OFF); + w1_write_8(sl->master, W1_42_CHAIN_OFF_INV); + + /* check for acknowledgment */ + ack = w1_read_8(sl->master); + if (ack != W1_42_SUCCESS_CONFIRM_BYTE) + goto error; + mutex_unlock(&sl->master->bus_mutex); + + c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq); + return PAGE_SIZE - c; +error: + mutex_unlock(&sl->master->bus_mutex); + return -EIO; +} + static int __init w1_therm_init(void) { int err, i; diff --git a/kernel/drivers/w1/w1.c b/kernel/drivers/w1/w1.c index 181f41cb9..c9a7ff67d 100644 --- a/kernel/drivers/w1/w1.c +++ b/kernel/drivers/w1/w1.c @@ -46,11 +46,15 @@ MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol."); static int w1_timeout = 10; +static int w1_timeout_us = 0; int w1_max_slave_count = 64; int w1_max_slave_ttl = 10; module_param_named(timeout, w1_timeout, int, 0); MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches"); +module_param_named(timeout_us, w1_timeout_us, int, 0); +MODULE_PARM_DESC(timeout, "time in microseconds between automatic slave" + " searches"); /* A search stops when w1_max_slave_count devices have been found in that * search. The next search will start over and detect the same set of devices * on a static 1-wire bus. Memory is not allocated based on this number, just @@ -317,6 +321,14 @@ static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct devic return count; } +static ssize_t w1_master_attribute_show_timeout_us(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count; + count = sprintf(buf, "%d\n", w1_timeout_us); + return count; +} + static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -543,6 +555,7 @@ static W1_MASTER_ATTR_RO(slave_count, S_IRUGO); static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP); static W1_MASTER_ATTR_RO(attempts, S_IRUGO); static W1_MASTER_ATTR_RO(timeout, S_IRUGO); +static W1_MASTER_ATTR_RO(timeout_us, S_IRUGO); static W1_MASTER_ATTR_RO(pointer, S_IRUGO); static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUSR | S_IWGRP); static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUSR | S_IWGRP); @@ -556,6 +569,7 @@ static struct attribute *w1_master_default_attrs[] = { &w1_master_attribute_max_slave_count.attr, &w1_master_attribute_attempts.attr, &w1_master_attribute_timeout.attr, + &w1_master_attribute_timeout_us.attr, &w1_master_attribute_pointer.attr, &w1_master_attribute_search.attr, &w1_master_attribute_pullup.attr, @@ -1108,7 +1122,8 @@ int w1_process(void *data) /* As long as w1_timeout is only set by a module parameter the sleep * time can be calculated in jiffies once. */ - const unsigned long jtime = msecs_to_jiffies(w1_timeout * 1000); + const unsigned long jtime = + usecs_to_jiffies(w1_timeout * 1000000 + w1_timeout_us); /* remainder if it woke up early */ unsigned long jremain = 0; diff --git a/kernel/drivers/w1/w1_int.c b/kernel/drivers/w1/w1_int.c index 47249a30e..20f766afa 100644 --- a/kernel/drivers/w1/w1_int.c +++ b/kernel/drivers/w1/w1_int.c @@ -91,8 +91,7 @@ static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl, err = device_register(&dev->dev); if (err) { pr_err("Failed to register master device. err=%d\n", err); - memset(dev, 0, sizeof(struct w1_master)); - kfree(dev); + put_device(&dev->dev); dev = NULL; } |