18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * 1-wire busmaster driver for DS1WM and ASICs with embedded DS1WMs 38c2ecf20Sopenharmony_ci * such as HP iPAQs (including h5xxx, h2200, and devices with ASIC3 48c2ecf20Sopenharmony_ci * like hx4700). 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> 78c2ecf20Sopenharmony_ci * Copyright (c) 2004-2007, Matt Reimer <mreimer@vpop.net> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Use consistent with the GNU GPL is permitted, 108c2ecf20Sopenharmony_ci * provided that this copyright notice is 118c2ecf20Sopenharmony_ci * preserved in its entirety in all copies and derived works. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/irq.h> 188c2ecf20Sopenharmony_ci#include <linux/pm.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/err.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 238c2ecf20Sopenharmony_ci#include <linux/mfd/ds1wm.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm/io.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/w1.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define DS1WM_CMD 0x00 /* R/W 4 bits command */ 328c2ecf20Sopenharmony_ci#define DS1WM_DATA 0x01 /* R/W 8 bits, transmit/receive buffer */ 338c2ecf20Sopenharmony_ci#define DS1WM_INT 0x02 /* R/W interrupt status */ 348c2ecf20Sopenharmony_ci#define DS1WM_INT_EN 0x03 /* R/W interrupt enable */ 358c2ecf20Sopenharmony_ci#define DS1WM_CLKDIV 0x04 /* R/W 5 bits of divisor and pre-scale */ 368c2ecf20Sopenharmony_ci#define DS1WM_CNTRL 0x05 /* R/W master control register (not used yet) */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define DS1WM_CMD_1W_RESET (1 << 0) /* force reset on 1-wire bus */ 398c2ecf20Sopenharmony_ci#define DS1WM_CMD_SRA (1 << 1) /* enable Search ROM accelerator mode */ 408c2ecf20Sopenharmony_ci#define DS1WM_CMD_DQ_OUTPUT (1 << 2) /* write only - forces bus low */ 418c2ecf20Sopenharmony_ci#define DS1WM_CMD_DQ_INPUT (1 << 3) /* read only - reflects state of bus */ 428c2ecf20Sopenharmony_ci#define DS1WM_CMD_RST (1 << 5) /* software reset */ 438c2ecf20Sopenharmony_ci#define DS1WM_CMD_OD (1 << 7) /* overdrive */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define DS1WM_INT_PD (1 << 0) /* presence detect */ 468c2ecf20Sopenharmony_ci#define DS1WM_INT_PDR (1 << 1) /* presence detect result */ 478c2ecf20Sopenharmony_ci#define DS1WM_INT_TBE (1 << 2) /* tx buffer empty */ 488c2ecf20Sopenharmony_ci#define DS1WM_INT_TSRE (1 << 3) /* tx shift register empty */ 498c2ecf20Sopenharmony_ci#define DS1WM_INT_RBF (1 << 4) /* rx buffer full */ 508c2ecf20Sopenharmony_ci#define DS1WM_INT_RSRF (1 << 5) /* rx shift register full */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define DS1WM_INTEN_EPD (1 << 0) /* enable presence detect int */ 538c2ecf20Sopenharmony_ci#define DS1WM_INTEN_IAS (1 << 1) /* INTR active state */ 548c2ecf20Sopenharmony_ci#define DS1WM_INTEN_ETBE (1 << 2) /* enable tx buffer empty int */ 558c2ecf20Sopenharmony_ci#define DS1WM_INTEN_ETMT (1 << 3) /* enable tx shift register empty int */ 568c2ecf20Sopenharmony_ci#define DS1WM_INTEN_ERBF (1 << 4) /* enable rx buffer full int */ 578c2ecf20Sopenharmony_ci#define DS1WM_INTEN_ERSRF (1 << 5) /* enable rx shift register full int */ 588c2ecf20Sopenharmony_ci#define DS1WM_INTEN_DQO (1 << 6) /* enable direct bus driving ops */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define DS1WM_INTEN_NOT_IAS (~DS1WM_INTEN_IAS) /* all but INTR active state */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define DS1WM_TIMEOUT (HZ * 5) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic struct { 658c2ecf20Sopenharmony_ci unsigned long freq; 668c2ecf20Sopenharmony_ci unsigned long divisor; 678c2ecf20Sopenharmony_ci} freq[] = { 688c2ecf20Sopenharmony_ci { 1000000, 0x80 }, 698c2ecf20Sopenharmony_ci { 2000000, 0x84 }, 708c2ecf20Sopenharmony_ci { 3000000, 0x81 }, 718c2ecf20Sopenharmony_ci { 4000000, 0x88 }, 728c2ecf20Sopenharmony_ci { 5000000, 0x82 }, 738c2ecf20Sopenharmony_ci { 6000000, 0x85 }, 748c2ecf20Sopenharmony_ci { 7000000, 0x83 }, 758c2ecf20Sopenharmony_ci { 8000000, 0x8c }, 768c2ecf20Sopenharmony_ci { 10000000, 0x86 }, 778c2ecf20Sopenharmony_ci { 12000000, 0x89 }, 788c2ecf20Sopenharmony_ci { 14000000, 0x87 }, 798c2ecf20Sopenharmony_ci { 16000000, 0x90 }, 808c2ecf20Sopenharmony_ci { 20000000, 0x8a }, 818c2ecf20Sopenharmony_ci { 24000000, 0x8d }, 828c2ecf20Sopenharmony_ci { 28000000, 0x8b }, 838c2ecf20Sopenharmony_ci { 32000000, 0x94 }, 848c2ecf20Sopenharmony_ci { 40000000, 0x8e }, 858c2ecf20Sopenharmony_ci { 48000000, 0x91 }, 868c2ecf20Sopenharmony_ci { 56000000, 0x8f }, 878c2ecf20Sopenharmony_ci { 64000000, 0x98 }, 888c2ecf20Sopenharmony_ci { 80000000, 0x92 }, 898c2ecf20Sopenharmony_ci { 96000000, 0x95 }, 908c2ecf20Sopenharmony_ci { 112000000, 0x93 }, 918c2ecf20Sopenharmony_ci { 128000000, 0x9c }, 928c2ecf20Sopenharmony_ci/* you can continue this table, consult the OPERATION - CLOCK DIVISOR 938c2ecf20Sopenharmony_ci section of the ds1wm spec sheet. */ 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistruct ds1wm_data { 978c2ecf20Sopenharmony_ci void __iomem *map; 988c2ecf20Sopenharmony_ci unsigned int bus_shift; /* # of shifts to calc register offsets */ 998c2ecf20Sopenharmony_ci bool is_hw_big_endian; 1008c2ecf20Sopenharmony_ci struct platform_device *pdev; 1018c2ecf20Sopenharmony_ci const struct mfd_cell *cell; 1028c2ecf20Sopenharmony_ci int irq; 1038c2ecf20Sopenharmony_ci int slave_present; 1048c2ecf20Sopenharmony_ci void *reset_complete; 1058c2ecf20Sopenharmony_ci void *read_complete; 1068c2ecf20Sopenharmony_ci void *write_complete; 1078c2ecf20Sopenharmony_ci int read_error; 1088c2ecf20Sopenharmony_ci /* last byte received */ 1098c2ecf20Sopenharmony_ci u8 read_byte; 1108c2ecf20Sopenharmony_ci /* byte to write that makes all intr disabled, */ 1118c2ecf20Sopenharmony_ci /* considering active_state (IAS) (optimization) */ 1128c2ecf20Sopenharmony_ci u8 int_en_reg_none; 1138c2ecf20Sopenharmony_ci unsigned int reset_recover_delay; /* see ds1wm.h */ 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg, 1178c2ecf20Sopenharmony_ci u8 val) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci if (ds1wm_data->is_hw_big_endian) { 1208c2ecf20Sopenharmony_ci switch (ds1wm_data->bus_shift) { 1218c2ecf20Sopenharmony_ci case 0: 1228c2ecf20Sopenharmony_ci iowrite8(val, ds1wm_data->map + (reg << 0)); 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci case 1: 1258c2ecf20Sopenharmony_ci iowrite16be((u16)val, ds1wm_data->map + (reg << 1)); 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case 2: 1288c2ecf20Sopenharmony_ci iowrite32be((u32)val, ds1wm_data->map + (reg << 2)); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci switch (ds1wm_data->bus_shift) { 1338c2ecf20Sopenharmony_ci case 0: 1348c2ecf20Sopenharmony_ci iowrite8(val, ds1wm_data->map + (reg << 0)); 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci case 1: 1378c2ecf20Sopenharmony_ci iowrite16((u16)val, ds1wm_data->map + (reg << 1)); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci case 2: 1408c2ecf20Sopenharmony_ci iowrite32((u32)val, ds1wm_data->map + (reg << 2)); 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci u32 val = 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (ds1wm_data->is_hw_big_endian) { 1518c2ecf20Sopenharmony_ci switch (ds1wm_data->bus_shift) { 1528c2ecf20Sopenharmony_ci case 0: 1538c2ecf20Sopenharmony_ci val = ioread8(ds1wm_data->map + (reg << 0)); 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case 1: 1568c2ecf20Sopenharmony_ci val = ioread16be(ds1wm_data->map + (reg << 1)); 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case 2: 1598c2ecf20Sopenharmony_ci val = ioread32be(ds1wm_data->map + (reg << 2)); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci switch (ds1wm_data->bus_shift) { 1648c2ecf20Sopenharmony_ci case 0: 1658c2ecf20Sopenharmony_ci val = ioread8(ds1wm_data->map + (reg << 0)); 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case 1: 1688c2ecf20Sopenharmony_ci val = ioread16(ds1wm_data->map + (reg << 1)); 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case 2: 1718c2ecf20Sopenharmony_ci val = ioread32(ds1wm_data->map + (reg << 2)); 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 1768c2ecf20Sopenharmony_ci "ds1wm_read_register reg: %d, 32 bit val:%x\n", reg, val); 1778c2ecf20Sopenharmony_ci return (u8)val; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic irqreturn_t ds1wm_isr(int isr, void *data) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = data; 1848c2ecf20Sopenharmony_ci u8 intr; 1858c2ecf20Sopenharmony_ci u8 inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN); 1868c2ecf20Sopenharmony_ci /* if no bits are set in int enable register (except the IAS) 1878c2ecf20Sopenharmony_ci than go no further, reading the regs below has side effects */ 1888c2ecf20Sopenharmony_ci if (!(inten & DS1WM_INTEN_NOT_IAS)) 1898c2ecf20Sopenharmony_ci return IRQ_NONE; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, 1928c2ecf20Sopenharmony_ci DS1WM_INT_EN, ds1wm_data->int_en_reg_none); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* this read action clears the INTR and certain flags in ds1wm */ 1958c2ecf20Sopenharmony_ci intr = ds1wm_read_register(ds1wm_data, DS1WM_INT); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete) { 2008c2ecf20Sopenharmony_ci inten &= ~DS1WM_INTEN_ETMT; 2018c2ecf20Sopenharmony_ci complete(ds1wm_data->write_complete); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci if (intr & DS1WM_INT_RBF) { 2048c2ecf20Sopenharmony_ci /* this read clears the RBF flag */ 2058c2ecf20Sopenharmony_ci ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data, 2068c2ecf20Sopenharmony_ci DS1WM_DATA); 2078c2ecf20Sopenharmony_ci inten &= ~DS1WM_INTEN_ERBF; 2088c2ecf20Sopenharmony_ci if (ds1wm_data->read_complete) 2098c2ecf20Sopenharmony_ci complete(ds1wm_data->read_complete); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete) { 2128c2ecf20Sopenharmony_ci inten &= ~DS1WM_INTEN_EPD; 2138c2ecf20Sopenharmony_ci complete(ds1wm_data->reset_complete); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, inten); 2178c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int ds1wm_reset(struct ds1wm_data *ds1wm_data) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci unsigned long timeleft; 2238c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(reset_done); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ds1wm_data->reset_complete = &reset_done; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* enable Presence detect only */ 2288c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD | 2298c2ecf20Sopenharmony_ci ds1wm_data->int_en_reg_none); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT); 2348c2ecf20Sopenharmony_ci ds1wm_data->reset_complete = NULL; 2358c2ecf20Sopenharmony_ci if (!timeleft) { 2368c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, "reset failed, timed out\n"); 2378c2ecf20Sopenharmony_ci return 1; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!ds1wm_data->slave_present) { 2418c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n"); 2428c2ecf20Sopenharmony_ci return 1; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (ds1wm_data->reset_recover_delay) 2468c2ecf20Sopenharmony_ci msleep(ds1wm_data->reset_recover_delay); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci unsigned long timeleft; 2548c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(write_done); 2558c2ecf20Sopenharmony_ci ds1wm_data->write_complete = &write_done; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, 2588c2ecf20Sopenharmony_ci ds1wm_data->int_en_reg_none | DS1WM_INTEN_ETMT); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_DATA, data); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci ds1wm_data->write_complete = NULL; 2658c2ecf20Sopenharmony_ci if (!timeleft) { 2668c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, "write failed, timed out\n"); 2678c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic u8 ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci unsigned long timeleft; 2768c2ecf20Sopenharmony_ci u8 intEnable = DS1WM_INTEN_ERBF | ds1wm_data->int_en_reg_none; 2778c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(read_done); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ds1wm_read_register(ds1wm_data, DS1WM_DATA); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ds1wm_data->read_complete = &read_done; 2828c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, intEnable); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_DATA, write_data); 2858c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci ds1wm_data->read_complete = NULL; 2888c2ecf20Sopenharmony_ci if (!timeleft) { 2898c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, "read failed, timed out\n"); 2908c2ecf20Sopenharmony_ci ds1wm_data->read_error = -ETIMEDOUT; 2918c2ecf20Sopenharmony_ci return 0xFF; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci ds1wm_data->read_error = 0; 2948c2ecf20Sopenharmony_ci return ds1wm_data->read_byte; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int ds1wm_find_divisor(int gclk) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci int i; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(freq)-1; i >= 0; --i) 3028c2ecf20Sopenharmony_ci if (gclk >= freq[i].freq) 3038c2ecf20Sopenharmony_ci return freq[i].divisor; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic void ds1wm_up(struct ds1wm_data *ds1wm_data) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci int divisor; 3118c2ecf20Sopenharmony_ci struct device *dev = &ds1wm_data->pdev->dev; 3128c2ecf20Sopenharmony_ci struct ds1wm_driver_data *plat = dev_get_platdata(dev); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (ds1wm_data->cell->enable) 3158c2ecf20Sopenharmony_ci ds1wm_data->cell->enable(ds1wm_data->pdev); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci divisor = ds1wm_find_divisor(plat->clock_rate); 3188c2ecf20Sopenharmony_ci dev_dbg(dev, "found divisor 0x%x for clock %d\n", 3198c2ecf20Sopenharmony_ci divisor, plat->clock_rate); 3208c2ecf20Sopenharmony_ci if (divisor == 0) { 3218c2ecf20Sopenharmony_ci dev_err(dev, "no suitable divisor for %dHz clock\n", 3228c2ecf20Sopenharmony_ci plat->clock_rate); 3238c2ecf20Sopenharmony_ci return; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Let the w1 clock stabilize. */ 3288c2ecf20Sopenharmony_ci msleep(1); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ds1wm_reset(ds1wm_data); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void ds1wm_down(struct ds1wm_data *ds1wm_data) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci ds1wm_reset(ds1wm_data); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Disable interrupts. */ 3388c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, 3398c2ecf20Sopenharmony_ci ds1wm_data->int_en_reg_none); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (ds1wm_data->cell->disable) 3428c2ecf20Sopenharmony_ci ds1wm_data->cell->disable(ds1wm_data->pdev); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */ 3468c2ecf20Sopenharmony_ci/* w1 methods */ 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic u8 ds1wm_read_byte(void *data) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = data; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return ds1wm_read(ds1wm_data, 0xff); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void ds1wm_write_byte(void *data, u8 byte) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = data; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ds1wm_write(ds1wm_data, byte); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic u8 ds1wm_reset_bus(void *data) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = data; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci ds1wm_reset(ds1wm_data); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void ds1wm_search(void *data, struct w1_master *master_dev, 3728c2ecf20Sopenharmony_ci u8 search_type, w1_slave_found_callback slave_found) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = data; 3758c2ecf20Sopenharmony_ci int i; 3768c2ecf20Sopenharmony_ci int ms_discrep_bit = -1; 3778c2ecf20Sopenharmony_ci u64 r = 0; /* holds the progress of the search */ 3788c2ecf20Sopenharmony_ci u64 r_prime, d; 3798c2ecf20Sopenharmony_ci unsigned slaves_found = 0; 3808c2ecf20Sopenharmony_ci unsigned int pass = 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, "search begin\n"); 3838c2ecf20Sopenharmony_ci while (true) { 3848c2ecf20Sopenharmony_ci ++pass; 3858c2ecf20Sopenharmony_ci if (pass > 100) { 3868c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 3878c2ecf20Sopenharmony_ci "too many attempts (100), search aborted\n"); 3888c2ecf20Sopenharmony_ci return; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci mutex_lock(&master_dev->bus_mutex); 3928c2ecf20Sopenharmony_ci if (ds1wm_reset(ds1wm_data)) { 3938c2ecf20Sopenharmony_ci mutex_unlock(&master_dev->bus_mutex); 3948c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 3958c2ecf20Sopenharmony_ci "pass: %d reset error (or no slaves)\n", pass); 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4008c2ecf20Sopenharmony_ci "pass: %d r : %0#18llx writing SEARCH_ROM\n", pass, r); 4018c2ecf20Sopenharmony_ci ds1wm_write(ds1wm_data, search_type); 4028c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4038c2ecf20Sopenharmony_ci "pass: %d entering ASM\n", pass); 4048c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA); 4058c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4068c2ecf20Sopenharmony_ci "pass: %d beginning nibble loop\n", pass); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci r_prime = 0; 4098c2ecf20Sopenharmony_ci d = 0; 4108c2ecf20Sopenharmony_ci /* we work one nibble at a time */ 4118c2ecf20Sopenharmony_ci /* each nibble is interleaved to form a byte */ 4128c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci unsigned char resp, _r, _r_prime, _d; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci _r = (r >> (4*i)) & 0xf; 4178c2ecf20Sopenharmony_ci _r = ((_r & 0x1) << 1) | 4188c2ecf20Sopenharmony_ci ((_r & 0x2) << 2) | 4198c2ecf20Sopenharmony_ci ((_r & 0x4) << 3) | 4208c2ecf20Sopenharmony_ci ((_r & 0x8) << 4); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* writes _r, then reads back: */ 4238c2ecf20Sopenharmony_ci resp = ds1wm_read(ds1wm_data, _r); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (ds1wm_data->read_error) { 4268c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, 4278c2ecf20Sopenharmony_ci "pass: %d nibble: %d read error\n", pass, i); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci _r_prime = ((resp & 0x02) >> 1) | 4328c2ecf20Sopenharmony_ci ((resp & 0x08) >> 2) | 4338c2ecf20Sopenharmony_ci ((resp & 0x20) >> 3) | 4348c2ecf20Sopenharmony_ci ((resp & 0x80) >> 4); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci _d = ((resp & 0x01) >> 0) | 4378c2ecf20Sopenharmony_ci ((resp & 0x04) >> 1) | 4388c2ecf20Sopenharmony_ci ((resp & 0x10) >> 2) | 4398c2ecf20Sopenharmony_ci ((resp & 0x40) >> 3); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci r_prime |= (unsigned long long) _r_prime << (i * 4); 4428c2ecf20Sopenharmony_ci d |= (unsigned long long) _d << (i * 4); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci if (ds1wm_data->read_error) { 4468c2ecf20Sopenharmony_ci mutex_unlock(&master_dev->bus_mutex); 4478c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, 4488c2ecf20Sopenharmony_ci "pass: %d read error, retrying\n", pass); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4528c2ecf20Sopenharmony_ci "pass: %d r\': %0#18llx d:%0#18llx\n", 4538c2ecf20Sopenharmony_ci pass, r_prime, d); 4548c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4558c2ecf20Sopenharmony_ci "pass: %d nibble loop complete, exiting ASM\n", pass); 4568c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA); 4578c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4588c2ecf20Sopenharmony_ci "pass: %d resetting bus\n", pass); 4598c2ecf20Sopenharmony_ci ds1wm_reset(ds1wm_data); 4608c2ecf20Sopenharmony_ci mutex_unlock(&master_dev->bus_mutex); 4618c2ecf20Sopenharmony_ci if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) { 4628c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, 4638c2ecf20Sopenharmony_ci "pass: %d bus error, retrying\n", pass); 4648c2ecf20Sopenharmony_ci continue; /* start over */ 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4698c2ecf20Sopenharmony_ci "pass: %d found %0#18llx\n", pass, r_prime); 4708c2ecf20Sopenharmony_ci slave_found(master_dev, r_prime); 4718c2ecf20Sopenharmony_ci ++slaves_found; 4728c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4738c2ecf20Sopenharmony_ci "pass: %d complete, preparing next pass\n", pass); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* any discrepency found which we already choose the 4768c2ecf20Sopenharmony_ci '1' branch is now is now irrelevant we reveal the 4778c2ecf20Sopenharmony_ci next branch with this: */ 4788c2ecf20Sopenharmony_ci d &= ~r; 4798c2ecf20Sopenharmony_ci /* find last bit set, i.e. the most signif. bit set */ 4808c2ecf20Sopenharmony_ci ms_discrep_bit = fls64(d) - 1; 4818c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4828c2ecf20Sopenharmony_ci "pass: %d new d:%0#18llx MS discrep bit:%d\n", 4838c2ecf20Sopenharmony_ci pass, d, ms_discrep_bit); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* prev_ms_discrep_bit = ms_discrep_bit; 4868c2ecf20Sopenharmony_ci prepare for next ROM search: */ 4878c2ecf20Sopenharmony_ci if (ms_discrep_bit == -1) 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci r = (r & ~(~0ull << (ms_discrep_bit))) | 1 << ms_discrep_bit; 4918c2ecf20Sopenharmony_ci } /* end while true */ 4928c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 4938c2ecf20Sopenharmony_ci "pass: %d total: %d search done ms d bit pos: %d\n", pass, 4948c2ecf20Sopenharmony_ci slaves_found, ms_discrep_bit); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */ 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic struct w1_bus_master ds1wm_master = { 5008c2ecf20Sopenharmony_ci .read_byte = ds1wm_read_byte, 5018c2ecf20Sopenharmony_ci .write_byte = ds1wm_write_byte, 5028c2ecf20Sopenharmony_ci .reset_bus = ds1wm_reset_bus, 5038c2ecf20Sopenharmony_ci .search = ds1wm_search, 5048c2ecf20Sopenharmony_ci}; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int ds1wm_probe(struct platform_device *pdev) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data; 5098c2ecf20Sopenharmony_ci struct ds1wm_driver_data *plat; 5108c2ecf20Sopenharmony_ci struct resource *res; 5118c2ecf20Sopenharmony_ci int ret; 5128c2ecf20Sopenharmony_ci u8 inten; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (!pdev) 5158c2ecf20Sopenharmony_ci return -ENODEV; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci ds1wm_data = devm_kzalloc(&pdev->dev, sizeof(*ds1wm_data), GFP_KERNEL); 5188c2ecf20Sopenharmony_ci if (!ds1wm_data) 5198c2ecf20Sopenharmony_ci return -ENOMEM; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ds1wm_data); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5248c2ecf20Sopenharmony_ci if (!res) 5258c2ecf20Sopenharmony_ci return -ENXIO; 5268c2ecf20Sopenharmony_ci ds1wm_data->map = devm_ioremap(&pdev->dev, res->start, 5278c2ecf20Sopenharmony_ci resource_size(res)); 5288c2ecf20Sopenharmony_ci if (!ds1wm_data->map) 5298c2ecf20Sopenharmony_ci return -ENOMEM; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci ds1wm_data->pdev = pdev; 5328c2ecf20Sopenharmony_ci ds1wm_data->cell = mfd_get_cell(pdev); 5338c2ecf20Sopenharmony_ci if (!ds1wm_data->cell) 5348c2ecf20Sopenharmony_ci return -ENODEV; 5358c2ecf20Sopenharmony_ci plat = dev_get_platdata(&pdev->dev); 5368c2ecf20Sopenharmony_ci if (!plat) 5378c2ecf20Sopenharmony_ci return -ENODEV; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* how many bits to shift register number to get register offset */ 5408c2ecf20Sopenharmony_ci if (plat->bus_shift > 2) { 5418c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, 5428c2ecf20Sopenharmony_ci "illegal bus shift %d, not written", 5438c2ecf20Sopenharmony_ci ds1wm_data->bus_shift); 5448c2ecf20Sopenharmony_ci return -EINVAL; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ds1wm_data->bus_shift = plat->bus_shift; 5488c2ecf20Sopenharmony_ci /* make sure resource has space for 8 registers */ 5498c2ecf20Sopenharmony_ci if ((8 << ds1wm_data->bus_shift) > resource_size(res)) { 5508c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, 5518c2ecf20Sopenharmony_ci "memory resource size %d to small, should be %d\n", 5528c2ecf20Sopenharmony_ci (int)resource_size(res), 5538c2ecf20Sopenharmony_ci 8 << ds1wm_data->bus_shift); 5548c2ecf20Sopenharmony_ci return -EINVAL; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ds1wm_data->is_hw_big_endian = plat->is_hw_big_endian; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 5608c2ecf20Sopenharmony_ci if (!res) 5618c2ecf20Sopenharmony_ci return -ENXIO; 5628c2ecf20Sopenharmony_ci ds1wm_data->irq = res->start; 5638c2ecf20Sopenharmony_ci ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0); 5648c2ecf20Sopenharmony_ci ds1wm_data->reset_recover_delay = plat->reset_recover_delay; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* Mask interrupts, set IAS before claiming interrupt */ 5678c2ecf20Sopenharmony_ci inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN); 5688c2ecf20Sopenharmony_ci ds1wm_write_register(ds1wm_data, 5698c2ecf20Sopenharmony_ci DS1WM_INT_EN, ds1wm_data->int_en_reg_none); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_IRQ_HIGHEDGE) 5728c2ecf20Sopenharmony_ci irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); 5738c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_IRQ_LOWEDGE) 5748c2ecf20Sopenharmony_ci irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); 5758c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_IRQ_HIGHLEVEL) 5768c2ecf20Sopenharmony_ci irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_HIGH); 5778c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_IRQ_LOWLEVEL) 5788c2ecf20Sopenharmony_ci irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_LOW); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, 5818c2ecf20Sopenharmony_ci IRQF_SHARED, "ds1wm", ds1wm_data); 5828c2ecf20Sopenharmony_ci if (ret) { 5838c2ecf20Sopenharmony_ci dev_err(&ds1wm_data->pdev->dev, 5848c2ecf20Sopenharmony_ci "devm_request_irq %d failed with errno %d\n", 5858c2ecf20Sopenharmony_ci ds1wm_data->irq, 5868c2ecf20Sopenharmony_ci ret); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return ret; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci ds1wm_up(ds1wm_data); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci ds1wm_master.data = (void *)ds1wm_data; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci ret = w1_add_master_device(&ds1wm_master); 5968c2ecf20Sopenharmony_ci if (ret) 5978c2ecf20Sopenharmony_ci goto err; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci dev_dbg(&ds1wm_data->pdev->dev, 6008c2ecf20Sopenharmony_ci "ds1wm: probe successful, IAS: %d, rec.delay: %d, clockrate: %d, bus-shift: %d, is Hw Big Endian: %d\n", 6018c2ecf20Sopenharmony_ci plat->active_high, 6028c2ecf20Sopenharmony_ci plat->reset_recover_delay, 6038c2ecf20Sopenharmony_ci plat->clock_rate, 6048c2ecf20Sopenharmony_ci ds1wm_data->bus_shift, 6058c2ecf20Sopenharmony_ci ds1wm_data->is_hw_big_endian); 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cierr: 6098c2ecf20Sopenharmony_ci ds1wm_down(ds1wm_data); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return ret; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6158c2ecf20Sopenharmony_cistatic int ds1wm_suspend(struct platform_device *pdev, pm_message_t state) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci ds1wm_down(ds1wm_data); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic int ds1wm_resume(struct platform_device *pdev) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci ds1wm_up(ds1wm_data); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci#else 6338c2ecf20Sopenharmony_ci#define ds1wm_suspend NULL 6348c2ecf20Sopenharmony_ci#define ds1wm_resume NULL 6358c2ecf20Sopenharmony_ci#endif 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic int ds1wm_remove(struct platform_device *pdev) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci w1_remove_master_device(&ds1wm_master); 6428c2ecf20Sopenharmony_ci ds1wm_down(ds1wm_data); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic struct platform_driver ds1wm_driver = { 6488c2ecf20Sopenharmony_ci .driver = { 6498c2ecf20Sopenharmony_ci .name = "ds1wm", 6508c2ecf20Sopenharmony_ci }, 6518c2ecf20Sopenharmony_ci .probe = ds1wm_probe, 6528c2ecf20Sopenharmony_ci .remove = ds1wm_remove, 6538c2ecf20Sopenharmony_ci .suspend = ds1wm_suspend, 6548c2ecf20Sopenharmony_ci .resume = ds1wm_resume 6558c2ecf20Sopenharmony_ci}; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic int __init ds1wm_init(void) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci pr_info("DS1WM w1 busmaster driver - (c) 2004 Szabolcs Gyurko\n"); 6608c2ecf20Sopenharmony_ci return platform_driver_register(&ds1wm_driver); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void __exit ds1wm_exit(void) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci platform_driver_unregister(&ds1wm_driver); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cimodule_init(ds1wm_init); 6698c2ecf20Sopenharmony_cimodule_exit(ds1wm_exit); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " 6738c2ecf20Sopenharmony_ci "Matt Reimer <mreimer@vpop.net>," 6748c2ecf20Sopenharmony_ci "Jean-Francois Dagenais <dagenaisj@sonatest.com>"); 6758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DS1WM w1 busmaster driver"); 676