diff options
Diffstat (limited to 'drivers/w1/masters')
| -rw-r--r-- | drivers/w1/masters/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/w1/masters/ds1wm.c | 72 | ||||
| -rw-r--r-- | drivers/w1/masters/ds2482.c | 64 | ||||
| -rw-r--r-- | drivers/w1/masters/ds2490.c | 155 | ||||
| -rw-r--r-- | drivers/w1/masters/matrox_w1.c | 10 | ||||
| -rw-r--r-- | drivers/w1/masters/mxc_w1.c | 146 | ||||
| -rw-r--r-- | drivers/w1/masters/omap_hdq.c | 177 | ||||
| -rw-r--r-- | drivers/w1/masters/w1-gpio.c | 158 |
8 files changed, 424 insertions, 367 deletions
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 979d6eed9a0..1708b2300c7 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -26,7 +26,7 @@ config W1_MASTER_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. @@ -36,13 +36,12 @@ config W1_MASTER_DS2482 config W1_MASTER_MXC tristate "Freescale MXC 1-wire busmaster" - depends on W1 && ARCH_MXC + 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 && GENERIC_HARDIRQS 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 @@ -50,7 +49,7 @@ 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. @@ -60,7 +59,7 @@ config W1_MASTER_GPIO config HDQ_MASTER_OMAP tristate "OMAP HDQ driver" - depends on SOC_OMAP2430 || ARCH_OMAP3 + depends on ARCH_OMAP help Say Y here if you want support for the 1-wire or HDQ Interface on an OMAP processor. diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index a0c8965c1a7..02df3b1381d 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -13,6 +13,7 @@ #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> @@ -254,17 +255,17 @@ static int ds1wm_find_divisor(int gclk) static void ds1wm_up(struct ds1wm_data *ds1wm_data) { int divisor; - struct ds1wm_driver_data *plat = ds1wm_data->pdev->dev.platform_data; + struct device *dev = &ds1wm_data->pdev->dev; + struct ds1wm_driver_data *plat = dev_get_platdata(dev); if (ds1wm_data->cell->enable) ds1wm_data->cell->enable(ds1wm_data->pdev); divisor = ds1wm_find_divisor(plat->clock_rate); - dev_dbg(&ds1wm_data->pdev->dev, - "found divisor 0x%x for clock %d\n", 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", + dev_err(dev, "no suitable divisor for %dHz clock\n", plat->clock_rate); return; } @@ -334,7 +335,9 @@ static void ds1wm_search(void *data, struct w1_master *master_dev, return; } + mutex_lock(&master_dev->bus_mutex); if (ds1wm_reset(ds1wm_data)) { + mutex_unlock(&master_dev->bus_mutex); dev_dbg(&ds1wm_data->pdev->dev, "pass: %d reset error (or no slaves)\n", pass); break; @@ -347,7 +350,7 @@ static void ds1wm_search(void *data, struct w1_master *master_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 begining nibble loop\n", pass); + "pass: %d beginning nibble loop\n", pass); r_prime = 0; d = 0; @@ -387,6 +390,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev, } if (ds1wm_data->read_error) { + mutex_unlock(&master_dev->bus_mutex); dev_err(&ds1wm_data->pdev->dev, "pass: %d read error, retrying\n", pass); break; @@ -400,6 +404,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev, dev_dbg(&ds1wm_data->pdev->dev, "pass: %d resetting bus\n", pass); ds1wm_reset(ds1wm_data); + mutex_unlock(&master_dev->bus_mutex); if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) { dev_err(&ds1wm_data->pdev->dev, "pass: %d bus error, retrying\n", pass); @@ -455,43 +460,34 @@ static int ds1wm_probe(struct platform_device *pdev) 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, resource_size(res)); - if (!ds1wm_data->map) { - ret = -ENOMEM; - goto err0; - } + 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->cell = mfd_get_cell(pdev); - if (!ds1wm_data->cell) { - ret = -ENODEV; - goto err1; - } - plat = pdev->dev.platform_data; - if (!plat) { - ret = -ENODEV; - goto err1; - } + 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->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0); ds1wm_data->reset_recover_delay = plat->reset_recover_delay; @@ -501,10 +497,10 @@ static int ds1wm_probe(struct platform_device *pdev) if (res->flags & IORESOURCE_IRQ_LOWEDGE) irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); - ret = request_irq(ds1wm_data->irq, ds1wm_isr, - IRQF_DISABLED | IRQF_SHARED, "ds1wm", ds1wm_data); + ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, + IRQF_SHARED, "ds1wm", ds1wm_data); if (ret) - goto err1; + return ret; ds1wm_up(ds1wm_data); @@ -512,17 +508,12 @@ static int ds1wm_probe(struct platform_device *pdev) ret = w1_add_master_device(&ds1wm_master); if (ret) - goto err2; + goto err; return 0; -err2: +err: ds1wm_down(ds1wm_data); - free_irq(ds1wm_data->irq, ds1wm_data); -err1: - iounmap(ds1wm_data->map); -err0: - kfree(ds1wm_data); return ret; } @@ -556,9 +547,6 @@ static int ds1wm_remove(struct platform_device *pdev) w1_remove_master_device(&ds1wm_master); ds1wm_down(ds1wm_data); - free_irq(ds1wm_data->irq, ds1wm_data); - iounmap(ds1wm_data->map); - kfree(ds1wm_data); return 0; } diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index e5f74416d4b..e033491fe30 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c @@ -51,10 +51,10 @@ * 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 */ /** @@ -132,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 @@ -399,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); @@ -407,6 +418,32 @@ static u8 ds2482_w1_reset_bus(void *data) return retval; } +static u8 ds2482_w1_set_pullup(void *data, int delay) +{ + 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; +} + static int ds2482_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -452,7 +489,8 @@ static int ds2482_probe(struct i2c_client *client, data->w1_count = 8; /* Set all config items to 0 (off) */ - ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, 0xF0); + ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, + ds2482_calculate_config(0x00)); mutex_init(&data->access_lock); @@ -468,6 +506,7 @@ static int ds2482_probe(struct i2c_client *client, 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) { @@ -505,19 +544,8 @@ static int ds2482_remove(struct i2c_client *client) 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 4f7e1d770f8..7404ad3062b 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c @@ -1,5 +1,5 @@ /* - * dscore.c + * ds2490.c USB to one wire bridge * * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net> * @@ -28,6 +28,10 @@ #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 @@ -107,6 +111,8 @@ #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 */ @@ -198,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); @@ -213,7 +219,7 @@ 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); @@ -228,7 +234,7 @@ 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); @@ -246,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; @@ -353,7 +360,7 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size) err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]), buf, size, &count, 1000); if (err < 0) { - u8 buf[0x20]; + u8 buf[ST_SIZE]; int count; printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]); @@ -398,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); @@ -450,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) { @@ -464,7 +472,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st) printk("\n"); } #endif - } while (!(buf[0x08] & ST_IDLE) && !(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"); @@ -690,37 +698,106 @@ static int ds_write_block(struct ds_device *dev, u8 *buf, int len) 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; @@ -894,6 +971,7 @@ static int ds_w1_init(struct ds_device *dev) 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); } @@ -910,15 +988,13 @@ 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; } - dev->spu_sleep = 0; - dev->spu_bit = 0; dev->udev = usb_get_dev(udev); if (!dev->udev) { err = -ENOMEM; @@ -928,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; diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index f667c26b219..d8667b0212d 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -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 index a3b6a74c67a..a5df5e89d45 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -10,24 +10,16 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * */ -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> #include <linux/clk.h> -#include <linux/slab.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" -#include "../w1_log.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 */ @@ -36,17 +28,16 @@ /* * MXC W1 Register offsets */ -#define MXC_W1_CONTROL 0x00 -#define MXC_W1_TIME_DIVIDER 0x02 -#define MXC_W1_RESET 0x04 -#define MXC_W1_COMMAND 0x06 -#define MXC_W1_TXRX 0x08 -#define MXC_W1_INTERRUPT 0x0A -#define MXC_W1_INTERRUPT_EN 0x0C +#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; - unsigned int clkdiv; struct clk *clk; struct w1_bus_master bus_master; }; @@ -62,12 +53,12 @@ static u8 mxc_w1_ds2_reset_bus(void *data) unsigned int timeout_cnt = 0; struct mxc_w1_device *dev = data; - __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL)); + writeb(MXC_W1_CONTROL_RPP, (dev->regs + MXC_W1_CONTROL)); while (1) { - reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL); + reg_val = readb(dev->regs + MXC_W1_CONTROL); - if (((reg_val >> 7) & 0x1) == 0 || + if (!(reg_val & MXC_W1_CONTROL_RPP) || timeout_cnt > MXC_W1_RESET_TIMEOUT) break; else @@ -75,7 +66,7 @@ static u8 mxc_w1_ds2_reset_bus(void *data) udelay(100); } - return (reg_val >> 7) & 0x1; + return !(reg_val & MXC_W1_CONTROL_PST); } /* @@ -91,121 +82,100 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) * datasheet. */ - __raw_writeb((1 << (5 - bit)), ctrl_addr); + writeb(MXC_W1_CONTROL_WR(bit), ctrl_addr); while (timeout_cnt--) { - if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1)) + if (!(readb(ctrl_addr) & MXC_W1_CONTROL_WR(bit))) break; udelay(1); } - return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; + return !!(readb(ctrl_addr) & MXC_W1_CONTROL_RDST); } -static int __devinit mxc_w1_probe(struct platform_device *pdev) +static int mxc_w1_probe(struct platform_device *pdev) { struct mxc_w1_device *mdev; + unsigned long clkrate; struct resource *res; - int err = 0; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; + unsigned int clkdiv; + int err; - mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL); + mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device), + GFP_KERNEL); if (!mdev) return -ENOMEM; - mdev->clk = clk_get(&pdev->dev, "owire"); - if (!mdev->clk) { - err = -ENODEV; - goto failed_clk; - } + mdev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mdev->clk)) + return PTR_ERR(mdev->clk); - mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1; + clkrate = clk_get_rate(mdev->clk); + if (clkrate < 10000000) + dev_warn(&pdev->dev, + "Low clock frequency causes improper function\n"); - res = request_mem_region(res->start, resource_size(res), - "mxc_w1"); - if (!res) { - err = -EBUSY; - goto failed_req; - } + 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); - mdev->regs = ioremap(res->start, resource_size(res)); - if (!mdev->regs) { - printk(KERN_ERR "Cannot map frame buffer registers\n"); - goto failed_ioremap; - } + 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); - clk_enable(mdev->clk); - __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); + 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; - err = w1_add_master_device(&mdev->bus_master); + platform_set_drvdata(pdev, mdev); + err = w1_add_master_device(&mdev->bus_master); if (err) - goto failed_add; + clk_disable_unprepare(mdev->clk); - platform_set_drvdata(pdev, mdev); - return 0; - -failed_add: - iounmap(mdev->regs); -failed_ioremap: - release_mem_region(res->start, resource_size(res)); -failed_req: - clk_put(mdev->clk); -failed_clk: - kfree(mdev); return err; } /* * disassociate the w1 device from the driver */ -static int __devexit mxc_w1_remove(struct platform_device *pdev) +static int mxc_w1_remove(struct platform_device *pdev) { struct mxc_w1_device *mdev = platform_get_drvdata(pdev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); w1_remove_master_device(&mdev->bus_master); - iounmap(mdev->regs); - release_mem_region(res->start, resource_size(res)); - clk_disable(mdev->clk); - clk_put(mdev->clk); - - platform_set_drvdata(pdev, NULL); + 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", + .name = "mxc_w1", + .owner = THIS_MODULE, + .of_match_table = mxc_w1_dt_ids, }, .probe = mxc_w1_probe, .remove = mxc_w1_remove, }; - -static int __init mxc_w1_init(void) -{ - return platform_driver_register(&mxc_w1_driver); -} - -static void mxc_w1_exit(void) -{ - platform_driver_unregister(&mxc_w1_driver); -} - -module_init(mxc_w1_init); -module_exit(mxc_w1_exit); +module_platform_driver(mxc_w1_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale Semiconductors Inc"); diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 5ef385bfed1..9900e8ec739 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -1,7 +1,7 @@ /* * drivers/w1/masters/omap_hdq.c * - * Copyright (C) 2007 Texas Instruments, Inc. + * 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 @@ -14,12 +14,9 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/err.h> -#include <linux/clk.h> #include <linux/io.h> #include <linux/sched.h> - -#include <asm/irq.h> -#include <mach/hardware.h> +#include <linux/pm_runtime.h> #include "../w1.h" #include "../w1_int.h" @@ -61,8 +58,6 @@ struct hdq_data { /* lock status update */ struct mutex hdq_mutex; int hdq_usecount; - struct clk *hdq_ick; - struct clk *hdq_fck; u8 hdq_irqstatus; /* device lock */ spinlock_t hdq_spinlock; @@ -74,7 +69,7 @@ struct hdq_data { int init_trans; }; -static int __devinit omap_hdq_probe(struct platform_device *pdev); +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 = { @@ -102,20 +97,20 @@ static struct w1_bus_master omap_w1_master = { /* HDQ register I/O routines */ static inline u8 hdq_reg_in(struct hdq_data *hdq_data, u32 offset) { - return __raw_readb(hdq_data->hdq_base + 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_writeb(val, hdq_data->hdq_base + offset); + __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_readb(hdq_data->hdq_base + offset) & ~mask) + u8 new_val = (__raw_readl(hdq_data->hdq_base + offset) & ~mask) | (val & mask); - __raw_writeb(new_val, hdq_data->hdq_base + offset); + __raw_writel(new_val, hdq_data->hdq_base + offset); return new_val; } @@ -180,6 +175,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status) hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT); if (ret == 0) { dev_dbg(hdq_data->dev, "TX wait elapsed\n"); + ret = -ETIMEDOUT; goto out; } @@ -187,7 +183,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status) /* check irqstatus */ if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) { dev_dbg(hdq_data->dev, "timeout waiting for" - "TXCOMPLETE/RXCOMPLETE, %x", *status); + " TXCOMPLETE/RXCOMPLETE, %x", *status); ret = -ETIMEDOUT; goto out; } @@ -198,7 +194,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status) OMAP_HDQ_FLAG_CLEAR, &tmp_status); if (ret) { dev_dbg(hdq_data->dev, "timeout waiting GO bit" - "return to zero, %x", tmp_status); + " return to zero, %x", tmp_status); } out: @@ -341,7 +337,7 @@ static int omap_hdq_break(struct hdq_data *hdq_data) &tmp_status); if (ret) dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits" - "return to zero, %x", tmp_status); + " return to zero, %x", tmp_status); out: mutex_unlock(&hdq_data->hdq_mutex); @@ -353,7 +349,6 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val) { int ret = 0; u8 status; - unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT; ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); if (ret < 0) { @@ -371,22 +366,20 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val) OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO); /* - * The RX comes immediately after TX. It - * triggers another interrupt before we - * sleep. So we have to wait for RXCOMPLETE bit. + * The RX comes immediately after TX. */ - while (!(hdq_data->hdq_irqstatus - & OMAP_HDQ_INT_STATUS_RXCOMPLETE) - && time_before(jiffies, timeout)) { - schedule_timeout_uninterruptible(1); - } + wait_event_timeout(hdq_wait_queue, + (hdq_data->hdq_irqstatus + & OMAP_HDQ_INT_STATUS_RXCOMPLETE), + OMAP_HDQ_TIMEOUT); + hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0, OMAP_HDQ_CTRL_STATUS_DIR); status = hdq_data->hdq_irqstatus; /* check irqstatus */ if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) { dev_dbg(hdq_data->dev, "timeout waiting for" - "RXCOMPLETE, %x", status); + " RXCOMPLETE, %x", status); ret = -ETIMEDOUT; goto out; } @@ -396,7 +389,7 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val) out: mutex_unlock(&hdq_data->hdq_mutex); rtn: - return 0; + return ret; } @@ -419,17 +412,8 @@ static int omap_hdq_get(struct hdq_data *hdq_data) hdq_data->hdq_usecount++; try_module_get(THIS_MODULE); if (1 == hdq_data->hdq_usecount) { - if (clk_enable(hdq_data->hdq_ick)) { - dev_dbg(hdq_data->dev, "Can not enable ick\n"); - ret = -ENODEV; - goto clk_err; - } - if (clk_enable(hdq_data->hdq_fck)) { - dev_dbg(hdq_data->dev, "Can not enable fck\n"); - clk_disable(hdq_data->hdq_ick); - ret = -ENODEV; - goto clk_err; - } + + pm_runtime_get_sync(hdq_data->dev); /* make sure HDQ is out of reset */ if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) & @@ -450,9 +434,6 @@ static int omap_hdq_get(struct hdq_data *hdq_data) } } -clk_err: - clk_put(hdq_data->hdq_ick); - clk_put(hdq_data->hdq_fck); out: mutex_unlock(&hdq_data->hdq_mutex); rtn: @@ -470,15 +451,13 @@ static int omap_hdq_put(struct hdq_data *hdq_data) if (0 == hdq_data->hdq_usecount) { dev_dbg(hdq_data->dev, "attempt to decrement use count" - "when it is zero"); + " when it is zero"); ret = -EINVAL; } else { hdq_data->hdq_usecount--; module_put(THIS_MODULE); - if (0 == hdq_data->hdq_usecount) { - clk_disable(hdq_data->hdq_ick); - clk_disable(hdq_data->hdq_fck); - } + if (0 == hdq_data->hdq_usecount) + pm_runtime_put_sync(hdq_data->dev); } mutex_unlock(&hdq_data->hdq_mutex); @@ -540,7 +519,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) mutex_unlock(&hdq_data->hdq_mutex); ret = hdq_write_byte(hdq_data, byte, &status); - if (ret == 0) { + if (ret < 0) { dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status); return; } @@ -556,70 +535,35 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) hdq_data->init_trans = 0; mutex_unlock(&hdq_data->hdq_mutex); } - - return; } -static int __devinit omap_hdq_probe(struct platform_device *pdev) +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 = kmalloc(sizeof(*hdq_data), GFP_KERNEL); + hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL); if (!hdq_data) { dev_dbg(&pdev->dev, "unable to allocate memory\n"); - ret = -ENOMEM; - goto err_kmalloc; + return -ENOMEM; } - hdq_data->dev = &pdev->dev; + hdq_data->dev = dev; platform_set_drvdata(pdev, hdq_data); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_dbg(&pdev->dev, "unable to get resource\n"); - ret = -ENXIO; - goto err_resource; - } - - hdq_data->hdq_base = ioremap(res->start, SZ_4K); - if (!hdq_data->hdq_base) { - dev_dbg(&pdev->dev, "ioremap failed\n"); - ret = -EINVAL; - goto err_ioremap; - } - - /* get interface & functional clock objects */ - hdq_data->hdq_ick = clk_get(&pdev->dev, "ick"); - if (IS_ERR(hdq_data->hdq_ick)) { - dev_dbg(&pdev->dev, "Can't get HDQ ick clock object\n"); - ret = PTR_ERR(hdq_data->hdq_ick); - goto err_ick; - } - - hdq_data->hdq_fck = clk_get(&pdev->dev, "fck"); - if (IS_ERR(hdq_data->hdq_fck)) { - dev_dbg(&pdev->dev, "Can't get HDQ fck clock object\n"); - ret = PTR_ERR(hdq_data->hdq_fck); - goto err_fck; - } + 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); - if (clk_enable(hdq_data->hdq_ick)) { - dev_dbg(&pdev->dev, "Can not enable ick\n"); - ret = -ENODEV; - goto err_intfclk; - } - - if (clk_enable(hdq_data->hdq_fck)) { - dev_dbg(&pdev->dev, "Can not enable fck\n"); - ret = -ENODEV; - goto err_fnclk; - } + 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", @@ -633,7 +577,7 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev) goto err_irq; } - ret = request_irq(irq, hdq_isr, IRQF_DISABLED, "omap_hdq", hdq_data); + 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; @@ -641,9 +585,7 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev) omap_hdq_break(hdq_data); - /* don't clock the HDQ until it is needed */ - clk_disable(hdq_data->hdq_ick); - clk_disable(hdq_data->hdq_fck); + pm_runtime_put_sync(&pdev->dev); omap_w1_master.data = hdq_data; @@ -655,30 +597,12 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev) return 0; -err_w1: err_irq: - clk_disable(hdq_data->hdq_fck); - -err_fnclk: - clk_disable(hdq_data->hdq_ick); - -err_intfclk: - clk_put(hdq_data->hdq_fck); - -err_fck: - clk_put(hdq_data->hdq_ick); - -err_ick: - iounmap(hdq_data->hdq_base); - -err_ioremap: -err_resource: - platform_set_drvdata(pdev, NULL); - kfree(hdq_data); + pm_runtime_put_sync(&pdev->dev); +err_w1: + pm_runtime_disable(&pdev->dev); -err_kmalloc: return ret; - } static int omap_hdq_remove(struct platform_device *pdev) @@ -696,29 +620,12 @@ static int omap_hdq_remove(struct platform_device *pdev) mutex_unlock(&hdq_data->hdq_mutex); /* remove module dependency */ - clk_put(hdq_data->hdq_ick); - clk_put(hdq_data->hdq_fck); - free_irq(INT_24XX_HDQ_IRQ, hdq_data); - platform_set_drvdata(pdev, NULL); - iounmap(hdq_data->hdq_base); - kfree(hdq_data); + pm_runtime_disable(&pdev->dev); return 0; } -static int __init -omap_hdq_init(void) -{ - return platform_driver_register(&omap_hdq_driver); -} -module_init(omap_hdq_init); - -static void __exit -omap_hdq_exit(void) -{ - platform_driver_unregister(&omap_hdq_driver); -} -module_exit(omap_hdq_exit); +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"); diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index fcbe742188a..1d111e56c8c 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -13,11 +13,35 @@ #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) { @@ -43,22 +67,91 @@ static u8 w1_gpio_read_bit(void *data) 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 = gpio_request(pdata->pin, "w1"); - if (err) - goto free_master; + err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); + if (err) { + dev_err(&pdev->dev, "gpio_request (pin) failed\n"); + return err; + } + + 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; @@ -69,38 +162,38 @@ 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; + } if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); + if (gpio_is_valid(pdata->ext_pullup_enable_pin)) + gpio_set_value(pdata->ext_pullup_enable_pin, 1); + platform_set_drvdata(pdev, master); return 0; - - free_gpio: - gpio_free(pdata->pin); - free_master: - kfree(master); - - return err; } -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; } @@ -109,7 +202,7 @@ static int __exit w1_gpio_remove(struct platform_device *pdev) static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) { - 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); @@ -119,7 +212,7 @@ static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) static int w1_gpio_resume(struct platform_device *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(1); @@ -136,24 +229,15 @@ static struct platform_driver w1_gpio_driver = { .driver = { .name = "w1-gpio", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(w1_gpio_dt_ids), }, - .remove = __exit_p(w1_gpio_remove), + .probe = w1_gpio_probe, + .remove = w1_gpio_remove, .suspend = w1_gpio_suspend, .resume = w1_gpio_resume, }; -static int __init w1_gpio_init(void) -{ - return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe); -} - -static void __exit w1_gpio_exit(void) -{ - platform_driver_unregister(&w1_gpio_driver); -} - -module_init(w1_gpio_init); -module_exit(w1_gpio_exit); +module_platform_driver(w1_gpio_driver); MODULE_DESCRIPTION("GPIO w1 bus master driver"); MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); |
