diff options
Diffstat (limited to 'drivers/w1')
30 files changed, 1309 insertions, 1135 deletions
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 24b9a8e05f64..e6049a75b35b 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -5,6 +5,17 @@ menu "1-wire Bus Masters" +config W1_MASTER_AMD_AXI + tristate "AMD AXI 1-wire bus host" + help + Say Y here is you want to support the AMD AXI 1-wire IP core. + This driver makes use of the programmable logic IP to perform + correctly timed 1 wire transactions without relying on GPIO timing + through the kernel. + + This driver can also be built as a module. If so, the module will be + called amd_w1_axi. + config W1_MASTER_MATROX tristate "Matrox G400 transport layer for 1-wire" depends on PCI @@ -41,13 +52,6 @@ config W1_MASTER_MXC help Say Y here to enable MXC 1-wire host -config W1_MASTER_DS1WM - tristate "Maxim DS1WM 1-wire busmaster" - 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 - hx4700. - config W1_MASTER_GPIO tristate "GPIO 1-wire busmaster" depends on GPIOLIB || COMPILE_TEST @@ -60,7 +64,7 @@ config W1_MASTER_GPIO config HDQ_MASTER_OMAP tristate "OMAP HDQ driver" - depends on ARCH_OMAP + depends on ARCH_OMAP || COMPILE_TEST help Say Y here if you want support for the 1-wire or HDQ Interface on an OMAP processor. @@ -74,5 +78,15 @@ config W1_MASTER_SGI This support is also available as a module. If so, the module will be called sgi_w1. +config W1_MASTER_UART + tristate "UART 1-wire driver" + depends on SERIAL_DEV_BUS + help + Say Y here if you want to communicate with your 1-wire devices using + UART interface. + + This support is also available as a module. If so, the module + will be called w1-uart. + endmenu diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index dae629b7ab49..227f80987e69 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -3,12 +3,13 @@ # Makefile for 1-wire bus master drivers. # +obj-$(CONFIG_W1_MASTER_AMD_AXI) += amd_axi_w1.o obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o -obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o obj-$(CONFIG_W1_MASTER_SGI) += sgi_w1.o +obj-$(CONFIG_W1_MASTER_UART) += w1-uart.o diff --git a/drivers/w1/masters/amd_axi_w1.c b/drivers/w1/masters/amd_axi_w1.c new file mode 100644 index 000000000000..5da8b8d86811 --- /dev/null +++ b/drivers/w1/masters/amd_axi_w1.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * amd_axi_w1 - AMD 1Wire programmable logic bus host driver + * + * Copyright (C) 2022-2023 Advanced Micro Devices, Inc. All Rights Reserved. + */ + +#include <linux/atomic.h> +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/wait.h> + +#include <linux/w1.h> + +/* 1-wire AMD IP definition */ +#define AXIW1_IPID 0x10ee4453 +/* Registers offset */ +#define AXIW1_INST_REG 0x0 +#define AXIW1_CTRL_REG 0x4 +#define AXIW1_IRQE_REG 0x8 +#define AXIW1_STAT_REG 0xC +#define AXIW1_DATA_REG 0x10 +#define AXIW1_IPVER_REG 0x18 +#define AXIW1_IPID_REG 0x1C +/* Instructions */ +#define AXIW1_INITPRES 0x0800 +#define AXIW1_READBIT 0x0C00 +#define AXIW1_WRITEBIT 0x0E00 +#define AXIW1_READBYTE 0x0D00 +#define AXIW1_WRITEBYTE 0x0F00 +/* Status flag masks */ +#define AXIW1_DONE BIT(0) +#define AXIW1_READY BIT(4) +#define AXIW1_PRESENCE BIT(31) +#define AXIW1_MAJORVER_MASK GENMASK(23, 8) +#define AXIW1_MINORVER_MASK GENMASK(7, 0) +/* Control flag */ +#define AXIW1_GO BIT(0) +#define AXI_CLEAR 0 +#define AXI_RESET BIT(31) +#define AXIW1_READDATA BIT(0) +/* Interrupt Enable */ +#define AXIW1_READY_IRQ_EN BIT(4) +#define AXIW1_DONE_IRQ_EN BIT(0) + +#define AXIW1_TIMEOUT msecs_to_jiffies(100) + +#define DRIVER_NAME "amd_axi_w1" + +struct amd_axi_w1_local { + struct device *dev; + void __iomem *base_addr; + int irq; + atomic_t flag; /* Set on IRQ, cleared once serviced */ + wait_queue_head_t wait_queue; + struct w1_bus_master bus_host; +}; + +/** + * amd_axi_w1_wait_irq_interruptible_timeout() - Wait for IRQ with timeout. + * + * @amd_axi_w1_local: Pointer to device structure + * @IRQ: IRQ channel to wait on + * + * Return: %0 - OK, %-EINTR - Interrupted, %-EBUSY - Timed out + */ +static int amd_axi_w1_wait_irq_interruptible_timeout(struct amd_axi_w1_local *amd_axi_w1_local, + u32 IRQ) +{ + int ret; + + /* Enable the IRQ requested and wait for flag to indicate it's been triggered */ + iowrite32(IRQ, amd_axi_w1_local->base_addr + AXIW1_IRQE_REG); + ret = wait_event_interruptible_timeout(amd_axi_w1_local->wait_queue, + atomic_read(&amd_axi_w1_local->flag) != 0, + AXIW1_TIMEOUT); + if (ret < 0) { + dev_err(amd_axi_w1_local->dev, "Wait IRQ Interrupted\n"); + return -EINTR; + } + + if (!ret) { + dev_err(amd_axi_w1_local->dev, "Wait IRQ Timeout\n"); + return -EBUSY; + } + + atomic_set(&amd_axi_w1_local->flag, 0); + return 0; +} + +/** + * amd_axi_w1_touch_bit() - Performs the touch-bit function - write a 0 or 1 and reads the level. + * + * @data: Pointer to device structure + * @bit: The level to write + * + * Return: The level read + */ +static u8 amd_axi_w1_touch_bit(void *data, u8 bit) +{ + struct amd_axi_w1_local *amd_axi_w1_local = data; + u8 val = 0; + int rc; + + /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, + AXIW1_READY_IRQ_EN); + if (rc < 0) + return 1; /* Callee doesn't test for error. Return inactive bus state */ + } + + if (bit) + /* Read. Write read Bit command in register 0 */ + iowrite32(AXIW1_READBIT, amd_axi_w1_local->base_addr + AXIW1_INST_REG); + else + /* Write. Write tx Bit command in instruction register with bit to transmit */ + iowrite32(AXIW1_WRITEBIT + (bit & 0x01), + amd_axi_w1_local->base_addr + AXIW1_INST_REG); + + /* Write Go signal and clear control reset signal in control register */ + iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + /* Wait for done signal to be 1 */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, AXIW1_DONE_IRQ_EN); + if (rc < 0) + return 1; /* Callee doesn't test for error. Return inactive bus state */ + } + + /* If read, Retrieve data from register */ + if (bit) + val = (u8)(ioread32(amd_axi_w1_local->base_addr + AXIW1_DATA_REG) & AXIW1_READDATA); + + /* Clear Go signal in register 1 */ + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + return val; +} + +/** + * amd_axi_w1_read_byte - Performs the read byte function. + * + * @data: Pointer to device structure + * Return: The value read + */ +static u8 amd_axi_w1_read_byte(void *data) +{ + struct amd_axi_w1_local *amd_axi_w1_local = data; + u8 val = 0; + int rc; + + /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, + AXIW1_READY_IRQ_EN); + if (rc < 0) + return 0xFF; /* Return inactive bus state */ + } + + /* Write read Byte command in instruction register*/ + iowrite32(AXIW1_READBYTE, amd_axi_w1_local->base_addr + AXIW1_INST_REG); + + /* Write Go signal and clear control reset signal in control register */ + iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + /* Wait for done signal to be 1 */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, AXIW1_DONE_IRQ_EN); + if (rc < 0) + return 0xFF; /* Return inactive bus state */ + } + + /* Retrieve LSB bit in data register to get RX byte */ + val = (u8)(ioread32(amd_axi_w1_local->base_addr + AXIW1_DATA_REG) & 0x000000FF); + + /* Clear Go signal in control register */ + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + return val; +} + +/** + * amd_axi_w1_write_byte - Performs the write byte function. + * + * @data: The ds2482 channel pointer + * @val: The value to write + */ +static void amd_axi_w1_write_byte(void *data, u8 val) +{ + struct amd_axi_w1_local *amd_axi_w1_local = data; + int rc; + + /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, + AXIW1_READY_IRQ_EN); + if (rc < 0) + return; + } + + /* Write tx Byte command in instruction register with bit to transmit */ + iowrite32(AXIW1_WRITEBYTE + val, amd_axi_w1_local->base_addr + AXIW1_INST_REG); + + /* Write Go signal and clear control reset signal in register 1 */ + iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + /* Wait for done signal to be 1 */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, + AXIW1_DONE_IRQ_EN); + if (rc < 0) + return; + } + + /* Clear Go signal in control register */ + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); +} + +/** + * amd_axi_w1_reset_bus() - Issues a reset bus sequence. + * + * @data: the bus host data struct + * Return: 0=Device present, 1=No device present or error + */ +static u8 amd_axi_w1_reset_bus(void *data) +{ + struct amd_axi_w1_local *amd_axi_w1_local = data; + u8 val = 0; + int rc; + + /* Reset 1-wire Axi IP */ + iowrite32(AXI_RESET, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, + AXIW1_READY_IRQ_EN); + if (rc < 0) + return 1; /* Something went wrong with the hardware */ + } + /* Write Initialization command in instruction register */ + iowrite32(AXIW1_INITPRES, amd_axi_w1_local->base_addr + AXIW1_INST_REG); + + /* Write Go signal and clear control reset signal in register 1 */ + iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + /* Wait for done signal to be 1 */ + while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) { + rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, AXIW1_DONE_IRQ_EN); + if (rc < 0) + return 1; /* Something went wrong with the hardware */ + } + /* Retrieve MSB bit in status register to get failure bit */ + if ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_PRESENCE) != 0) + val = 1; + + /* Clear Go signal in control register */ + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + + return val; +} + +/* Reset the 1-wire AXI IP. Put the IP in reset state and clear registers */ +static void amd_axi_w1_reset(struct amd_axi_w1_local *amd_axi_w1_local) +{ + iowrite32(AXI_RESET, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG); + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_INST_REG); + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_IRQE_REG); + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_STAT_REG); + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_DATA_REG); +} + +static irqreturn_t amd_axi_w1_irq(int irq, void *lp) +{ + struct amd_axi_w1_local *amd_axi_w1_local = lp; + + /* Reset interrupt trigger */ + iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_IRQE_REG); + + atomic_set(&amd_axi_w1_local->flag, 1); + wake_up_interruptible(&amd_axi_w1_local->wait_queue); + + return IRQ_HANDLED; +} + +static int amd_axi_w1_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct amd_axi_w1_local *lp; + struct clk *clk; + u32 ver_major, ver_minor; + int val, rc = 0; + + lp = devm_kzalloc(dev, sizeof(*lp), GFP_KERNEL); + if (!lp) + return -ENOMEM; + + lp->dev = dev; + lp->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(lp->base_addr)) + return PTR_ERR(lp->base_addr); + + lp->irq = platform_get_irq(pdev, 0); + if (lp->irq < 0) + return lp->irq; + + rc = devm_request_irq(dev, lp->irq, &amd_axi_w1_irq, IRQF_TRIGGER_HIGH, DRIVER_NAME, lp); + if (rc) + return rc; + + /* Initialize wait queue and flag */ + init_waitqueue_head(&lp->wait_queue); + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + /* Verify IP presence in HW */ + if (ioread32(lp->base_addr + AXIW1_IPID_REG) != AXIW1_IPID) { + dev_err(dev, "AMD 1-wire IP not detected in hardware\n"); + return -ENODEV; + } + + /* + * Allow for future driver expansion supporting new hardware features + * This driver currently only supports hardware 1.x, but include logic + * to detect if a potentially incompatible future version is used + * by reading major version ID. It is highly undesirable for new IP versions + * to break the API, but this code will at least allow for graceful failure + * should that happen. Future new features can be enabled by hardware + * incrementing the minor version and augmenting the driver to detect capability + * using the minor version number + */ + val = ioread32(lp->base_addr + AXIW1_IPVER_REG); + ver_major = FIELD_GET(AXIW1_MAJORVER_MASK, val); + ver_minor = FIELD_GET(AXIW1_MINORVER_MASK, val); + + if (ver_major != 1) { + dev_err(dev, "AMD AXI W1 host version %u.%u is not supported by this driver", + ver_major, ver_minor); + return -ENODEV; + } + + lp->bus_host.data = lp; + lp->bus_host.touch_bit = amd_axi_w1_touch_bit; + lp->bus_host.read_byte = amd_axi_w1_read_byte; + lp->bus_host.write_byte = amd_axi_w1_write_byte; + lp->bus_host.reset_bus = amd_axi_w1_reset_bus; + + amd_axi_w1_reset(lp); + + platform_set_drvdata(pdev, lp); + rc = w1_add_master_device(&lp->bus_host); + if (rc) { + dev_err(dev, "Could not add host device\n"); + return rc; + } + + return 0; +} + +static void amd_axi_w1_remove(struct platform_device *pdev) +{ + struct amd_axi_w1_local *lp = platform_get_drvdata(pdev); + + w1_remove_master_device(&lp->bus_host); +} + +static const struct of_device_id amd_axi_w1_of_match[] = { + { .compatible = "amd,axi-1wire-host" }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, amd_axi_w1_of_match); + +static struct platform_driver amd_axi_w1_driver = { + .probe = amd_axi_w1_probe, + .remove = amd_axi_w1_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = amd_axi_w1_of_match, + }, +}; +module_platform_driver(amd_axi_w1_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kris Chaplin <kris.chaplin@amd.com>"); +MODULE_DESCRIPTION("Driver for AMD AXI 1 Wire IP core"); diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c deleted file mode 100644 index f661695fb589..000000000000 --- a/drivers/w1/masters/ds1wm.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * 1-wire busmaster driver for DS1WM and ASICs with embedded DS1WMs - * such as HP iPAQs (including h5xxx, h2200, and devices with ASIC3 - * like hx4700). - * - * Copyright (c) 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> - * Copyright (c) 2004-2007, Matt Reimer <mreimer@vpop.net> - * - * Use consistent with the GNU GPL is permitted, - * provided that this copyright notice is - * preserved in its entirety in all copies and derived works. - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/pm.h> -#include <linux/platform_device.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/mfd/core.h> -#include <linux/mfd/ds1wm.h> -#include <linux/slab.h> - -#include <asm/io.h> - -#include <linux/w1.h> - - -#define DS1WM_CMD 0x00 /* R/W 4 bits command */ -#define DS1WM_DATA 0x01 /* R/W 8 bits, transmit/receive buffer */ -#define DS1WM_INT 0x02 /* R/W interrupt status */ -#define DS1WM_INT_EN 0x03 /* R/W interrupt enable */ -#define DS1WM_CLKDIV 0x04 /* R/W 5 bits of divisor and pre-scale */ -#define DS1WM_CNTRL 0x05 /* R/W master control register (not used yet) */ - -#define DS1WM_CMD_1W_RESET (1 << 0) /* force reset on 1-wire bus */ -#define DS1WM_CMD_SRA (1 << 1) /* enable Search ROM accelerator mode */ -#define DS1WM_CMD_DQ_OUTPUT (1 << 2) /* write only - forces bus low */ -#define DS1WM_CMD_DQ_INPUT (1 << 3) /* read only - reflects state of bus */ -#define DS1WM_CMD_RST (1 << 5) /* software reset */ -#define DS1WM_CMD_OD (1 << 7) /* overdrive */ - -#define DS1WM_INT_PD (1 << 0) /* presence detect */ -#define DS1WM_INT_PDR (1 << 1) /* presence detect result */ -#define DS1WM_INT_TBE (1 << 2) /* tx buffer empty */ -#define DS1WM_INT_TSRE (1 << 3) /* tx shift register empty */ -#define DS1WM_INT_RBF (1 << 4) /* rx buffer full */ -#define DS1WM_INT_RSRF (1 << 5) /* rx shift register full */ - -#define DS1WM_INTEN_EPD (1 << 0) /* enable presence detect int */ -#define DS1WM_INTEN_IAS (1 << 1) /* INTR active state */ -#define DS1WM_INTEN_ETBE (1 << 2) /* enable tx buffer empty int */ -#define DS1WM_INTEN_ETMT (1 << 3) /* enable tx shift register empty int */ -#define DS1WM_INTEN_ERBF (1 << 4) /* enable rx buffer full int */ -#define DS1WM_INTEN_ERSRF (1 << 5) /* enable rx shift register full int */ -#define DS1WM_INTEN_DQO (1 << 6) /* enable direct bus driving ops */ - -#define DS1WM_INTEN_NOT_IAS (~DS1WM_INTEN_IAS) /* all but INTR active state */ - -#define DS1WM_TIMEOUT (HZ * 5) - -static struct { - unsigned long freq; - unsigned long divisor; -} freq[] = { - { 1000000, 0x80 }, - { 2000000, 0x84 }, - { 3000000, 0x81 }, - { 4000000, 0x88 }, - { 5000000, 0x82 }, - { 6000000, 0x85 }, - { 7000000, 0x83 }, - { 8000000, 0x8c }, - { 10000000, 0x86 }, - { 12000000, 0x89 }, - { 14000000, 0x87 }, - { 16000000, 0x90 }, - { 20000000, 0x8a }, - { 24000000, 0x8d }, - { 28000000, 0x8b }, - { 32000000, 0x94 }, - { 40000000, 0x8e }, - { 48000000, 0x91 }, - { 56000000, 0x8f }, - { 64000000, 0x98 }, - { 80000000, 0x92 }, - { 96000000, 0x95 }, - { 112000000, 0x93 }, - { 128000000, 0x9c }, -/* you can continue this table, consult the OPERATION - CLOCK DIVISOR - section of the ds1wm spec sheet. */ -}; - -struct ds1wm_data { - void __iomem *map; - unsigned int bus_shift; /* # of shifts to calc register offsets */ - bool is_hw_big_endian; - struct platform_device *pdev; - const struct mfd_cell *cell; - int irq; - int slave_present; - void *reset_complete; - void *read_complete; - void *write_complete; - int read_error; - /* last byte received */ - u8 read_byte; - /* byte to write that makes all intr disabled, */ - /* considering active_state (IAS) (optimization) */ - u8 int_en_reg_none; - unsigned int reset_recover_delay; /* see ds1wm.h */ -}; - -static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg, - u8 val) -{ - if (ds1wm_data->is_hw_big_endian) { - switch (ds1wm_data->bus_shift) { - case 0: - iowrite8(val, ds1wm_data->map + (reg << 0)); - break; - case 1: - iowrite16be((u16)val, ds1wm_data->map + (reg << 1)); - break; - case 2: - iowrite32be((u32)val, ds1wm_data->map + (reg << 2)); - break; - } - } else { - switch (ds1wm_data->bus_shift) { - case 0: - iowrite8(val, ds1wm_data->map + (reg << 0)); - break; - case 1: - iowrite16((u16)val, ds1wm_data->map + (reg << 1)); - break; - case 2: - iowrite32((u32)val, ds1wm_data->map + (reg << 2)); - break; - } - } -} - -static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg) -{ - u32 val = 0; - - if (ds1wm_data->is_hw_big_endian) { - switch (ds1wm_data->bus_shift) { - case 0: - val = ioread8(ds1wm_data->map + (reg << 0)); - break; - case 1: - val = ioread16be(ds1wm_data->map + (reg << 1)); - break; - case 2: - val = ioread32be(ds1wm_data->map + (reg << 2)); - break; - } - } else { - switch (ds1wm_data->bus_shift) { - case 0: - val = ioread8(ds1wm_data->map + (reg << 0)); - break; - case 1: - val = ioread16(ds1wm_data->map + (reg << 1)); - break; - case 2: - val = ioread32(ds1wm_data->map + (reg << 2)); - break; - } - } - dev_dbg(&ds1wm_data->pdev->dev, - "ds1wm_read_register reg: %d, 32 bit val:%x\n", reg, val); - return (u8)val; -} - - -static irqreturn_t ds1wm_isr(int isr, void *data) -{ - struct ds1wm_data *ds1wm_data = data; - u8 intr; - u8 inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN); - /* if no bits are set in int enable register (except the IAS) - than go no further, reading the regs below has side effects */ - if (!(inten & DS1WM_INTEN_NOT_IAS)) - return IRQ_NONE; - - ds1wm_write_register(ds1wm_data, - DS1WM_INT_EN, ds1wm_data->int_en_reg_none); - - /* this read action clears the INTR and certain flags in ds1wm */ - intr = ds1wm_read_register(ds1wm_data, DS1WM_INT); - - ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1; - - if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete) { - inten &= ~DS1WM_INTEN_ETMT; - complete(ds1wm_data->write_complete); - } - if (intr & DS1WM_INT_RBF) { - /* this read clears the RBF flag */ - ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data, - DS1WM_DATA); - inten &= ~DS1WM_INTEN_ERBF; - if (ds1wm_data->read_complete) - complete(ds1wm_data->read_complete); - } - if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete) { - inten &= ~DS1WM_INTEN_EPD; - complete(ds1wm_data->reset_complete); - } - - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, inten); - return IRQ_HANDLED; -} - -static int ds1wm_reset(struct ds1wm_data *ds1wm_data) -{ - unsigned long timeleft; - DECLARE_COMPLETION_ONSTACK(reset_done); - - ds1wm_data->reset_complete = &reset_done; - - /* enable Presence detect only */ - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD | - ds1wm_data->int_en_reg_none); - - ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET); - - timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT); - ds1wm_data->reset_complete = NULL; - if (!timeleft) { - dev_err(&ds1wm_data->pdev->dev, "reset failed, timed out\n"); - return 1; - } - - if (!ds1wm_data->slave_present) { - dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n"); - return 1; - } - - if (ds1wm_data->reset_recover_delay) - msleep(ds1wm_data->reset_recover_delay); - - return 0; -} - -static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data) -{ - unsigned long timeleft; - DECLARE_COMPLETION_ONSTACK(write_done); - ds1wm_data->write_complete = &write_done; - - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, - ds1wm_data->int_en_reg_none | DS1WM_INTEN_ETMT); - - ds1wm_write_register(ds1wm_data, DS1WM_DATA, data); - - timeleft = wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT); - - ds1wm_data->write_complete = NULL; - if (!timeleft) { - dev_err(&ds1wm_data->pdev->dev, "write failed, timed out\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static u8 ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data) -{ - unsigned long timeleft; - u8 intEnable = DS1WM_INTEN_ERBF | ds1wm_data->int_en_reg_none; - DECLARE_COMPLETION_ONSTACK(read_done); - - ds1wm_read_register(ds1wm_data, DS1WM_DATA); - - ds1wm_data->read_complete = &read_done; - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, intEnable); - - ds1wm_write_register(ds1wm_data, DS1WM_DATA, write_data); - timeleft = wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT); - - ds1wm_data->read_complete = NULL; - if (!timeleft) { - dev_err(&ds1wm_data->pdev->dev, "read failed, timed out\n"); - ds1wm_data->read_error = -ETIMEDOUT; - return 0xFF; - } - ds1wm_data->read_error = 0; - return ds1wm_data->read_byte; -} - -static int ds1wm_find_divisor(int gclk) -{ - int i; - - for (i = ARRAY_SIZE(freq)-1; i >= 0; --i) - if (gclk >= freq[i].freq) - return freq[i].divisor; - - return 0; -} - -static void ds1wm_up(struct ds1wm_data *ds1wm_data) -{ - int divisor; - 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(dev, "found divisor 0x%x for clock %d\n", - divisor, plat->clock_rate); - if (divisor == 0) { - dev_err(dev, "no suitable divisor for %dHz clock\n", - plat->clock_rate); - return; - } - ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor); - - /* Let the w1 clock stabilize. */ - msleep(1); - - ds1wm_reset(ds1wm_data); -} - -static void ds1wm_down(struct ds1wm_data *ds1wm_data) -{ - ds1wm_reset(ds1wm_data); - - /* Disable interrupts. */ - ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, - ds1wm_data->int_en_reg_none); - - if (ds1wm_data->cell->disable) - ds1wm_data->cell->disable(ds1wm_data->pdev); -} - -/* --------------------------------------------------------------------- */ -/* w1 methods */ - -static u8 ds1wm_read_byte(void *data) -{ - struct ds1wm_data *ds1wm_data = data; - - return ds1wm_read(ds1wm_data, 0xff); -} - -static void ds1wm_write_byte(void *data, u8 byte) -{ - struct ds1wm_data *ds1wm_data = data; - - ds1wm_write(ds1wm_data, byte); -} - -static u8 ds1wm_reset_bus(void *data) -{ - struct ds1wm_data *ds1wm_data = data; - - ds1wm_reset(ds1wm_data); - - return 0; -} - -static void ds1wm_search(void *data, struct w1_master *master_dev, - u8 search_type, w1_slave_found_callback slave_found) -{ - struct ds1wm_data *ds1wm_data = data; - int i; - int ms_discrep_bit = -1; - u64 r = 0; /* holds the progress of the search */ - u64 r_prime, d; - unsigned slaves_found = 0; - unsigned int pass = 0; - - dev_dbg(&ds1wm_data->pdev->dev, "search begin\n"); - while (true) { - ++pass; - if (pass > 100) { - dev_dbg(&ds1wm_data->pdev->dev, - "too many attempts (100), search aborted\n"); - return; - } - - mutex_lock(&master_dev->bus_mutex); - if (ds1wm_reset(ds1wm_data)) { - mutex_unlock(&master_dev->bus_mutex); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d reset error (or no slaves)\n", pass); - break; - } - - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d r : %0#18llx writing SEARCH_ROM\n", pass, r); - ds1wm_write(ds1wm_data, search_type); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d entering ASM\n", pass); - ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d beginning nibble loop\n", pass); - - r_prime = 0; - d = 0; - /* we work one nibble at a time */ - /* each nibble is interleaved to form a byte */ - for (i = 0; i < 16; i++) { - - unsigned char resp, _r, _r_prime, _d; - - _r = (r >> (4*i)) & 0xf; - _r = ((_r & 0x1) << 1) | - ((_r & 0x2) << 2) | - ((_r & 0x4) << 3) | - ((_r & 0x8) << 4); - - /* writes _r, then reads back: */ - resp = ds1wm_read(ds1wm_data, _r); - - if (ds1wm_data->read_error) { - dev_err(&ds1wm_data->pdev->dev, - "pass: %d nibble: %d read error\n", pass, i); - break; - } - - _r_prime = ((resp & 0x02) >> 1) | - ((resp & 0x08) >> 2) | - ((resp & 0x20) >> 3) | - ((resp & 0x80) >> 4); - - _d = ((resp & 0x01) >> 0) | - ((resp & 0x04) >> 1) | - ((resp & 0x10) >> 2) | - ((resp & 0x40) >> 3); - - r_prime |= (unsigned long long) _r_prime << (i * 4); - d |= (unsigned long long) _d << (i * 4); - - } - if (ds1wm_data->read_error) { - mutex_unlock(&master_dev->bus_mutex); - dev_err(&ds1wm_data->pdev->dev, - "pass: %d read error, retrying\n", pass); - break; - } - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d r\': %0#18llx d:%0#18llx\n", - pass, r_prime, d); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d nibble loop complete, exiting ASM\n", pass); - ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA); - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d resetting bus\n", pass); - ds1wm_reset(ds1wm_data); - mutex_unlock(&master_dev->bus_mutex); - if ((r_prime & ((u64)1 << 63)) && (d & ((u64)1 << 63))) { - dev_err(&ds1wm_data->pdev->dev, - "pass: %d bus error, retrying\n", pass); - continue; /* start over */ - } - - - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d found %0#18llx\n", pass, r_prime); - slave_found(master_dev, r_prime); - ++slaves_found; - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d complete, preparing next pass\n", pass); - - /* any discrepency found which we already choose the - '1' branch is now is now irrelevant we reveal the - next branch with this: */ - d &= ~r; - /* find last bit set, i.e. the most signif. bit set */ - ms_discrep_bit = fls64(d) - 1; - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d new d:%0#18llx MS discrep bit:%d\n", - pass, d, ms_discrep_bit); - - /* prev_ms_discrep_bit = ms_discrep_bit; - prepare for next ROM search: */ - if (ms_discrep_bit == -1) - break; - - r = (r & ~(~0ull << (ms_discrep_bit))) | 1 << ms_discrep_bit; - } /* end while true */ - dev_dbg(&ds1wm_data->pdev->dev, - "pass: %d total: %d search done ms d bit pos: %d\n", pass, - slaves_found, ms_discrep_bit); -} - -/* --------------------------------------------------------------------- */ - -static struct w1_bus_master ds1wm_master = { - .read_byte = ds1wm_read_byte, - .write_byte = ds1wm_write_byte, - .reset_bus = ds1wm_reset_bus, - .search = ds1wm_search, -}; - -static int ds1wm_probe(struct platform_device *pdev) -{ - struct ds1wm_data *ds1wm_data; - struct ds1wm_driver_data *plat; - struct resource *res; - int ret; - u8 inten; - - if (!pdev) - return -ENODEV; - - 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) - return -ENXIO; - ds1wm_data->map = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!ds1wm_data->map) - return -ENOMEM; - - ds1wm_data->pdev = pdev; - ds1wm_data->cell = mfd_get_cell(pdev); - if (!ds1wm_data->cell) - return -ENODEV; - plat = dev_get_platdata(&pdev->dev); - if (!plat) - return -ENODEV; - - /* how many bits to shift register number to get register offset */ - if (plat->bus_shift > 2) { - dev_err(&ds1wm_data->pdev->dev, - "illegal bus shift %d, not written", - ds1wm_data->bus_shift); - return -EINVAL; - } - - ds1wm_data->bus_shift = plat->bus_shift; - /* make sure resource has space for 8 registers */ - if ((8 << ds1wm_data->bus_shift) > resource_size(res)) { - dev_err(&ds1wm_data->pdev->dev, - "memory resource size %d to small, should be %d\n", - (int)resource_size(res), - 8 << ds1wm_data->bus_shift); - return -EINVAL; - } - - ds1wm_data->is_hw_big_endian = plat->is_hw_big_endian; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - 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; - - /* Mask interrupts, set IAS before claiming interrupt */ - inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN); - ds1wm_write_register(ds1wm_data, - DS1WM_INT_EN, ds1wm_data->int_en_reg_none); - - if (res->flags & IORESOURCE_IRQ_HIGHEDGE) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); - if (res->flags & IORESOURCE_IRQ_LOWEDGE) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); - if (res->flags & IORESOURCE_IRQ_HIGHLEVEL) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_HIGH); - if (res->flags & IORESOURCE_IRQ_LOWLEVEL) - irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_LOW); - - ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, - IRQF_SHARED, "ds1wm", ds1wm_data); - if (ret) { - dev_err(&ds1wm_data->pdev->dev, - "devm_request_irq %d failed with errno %d\n", - ds1wm_data->irq, - ret); - - return ret; - } - - ds1wm_up(ds1wm_data); - - ds1wm_master.data = (void *)ds1wm_data; - - ret = w1_add_master_device(&ds1wm_master); - if (ret) - goto err; - - dev_dbg(&ds1wm_data->pdev->dev, - "ds1wm: probe successful, IAS: %d, rec.delay: %d, clockrate: %d, bus-shift: %d, is Hw Big Endian: %d\n", - plat->active_high, - plat->reset_recover_delay, - plat->clock_rate, - ds1wm_data->bus_shift, - ds1wm_data->is_hw_big_endian); - return 0; - -err: - ds1wm_down(ds1wm_data); - - return ret; -} - -#ifdef CONFIG_PM -static int ds1wm_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); - - ds1wm_down(ds1wm_data); - - return 0; -} - -static int ds1wm_resume(struct platform_device *pdev) -{ - struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); - - ds1wm_up(ds1wm_data); - - return 0; -} -#else -#define ds1wm_suspend NULL -#define ds1wm_resume NULL -#endif - -static int ds1wm_remove(struct platform_device *pdev) -{ - struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev); - - w1_remove_master_device(&ds1wm_master); - ds1wm_down(ds1wm_data); - - return 0; -} - -static struct platform_driver ds1wm_driver = { - .driver = { - .name = "ds1wm", - }, - .probe = ds1wm_probe, - .remove = ds1wm_remove, - .suspend = ds1wm_suspend, - .resume = ds1wm_resume -}; - -static int __init ds1wm_init(void) -{ - pr_info("DS1WM w1 busmaster driver - (c) 2004 Szabolcs Gyurko\n"); - return platform_driver_register(&ds1wm_driver); -} - -static void __exit ds1wm_exit(void) -{ - platform_driver_unregister(&ds1wm_driver); -} - -module_init(ds1wm_init); -module_exit(ds1wm_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " - "Matt Reimer <mreimer@vpop.net>," - "Jean-Francois Dagenais <dagenaisj@sonatest.com>"); -MODULE_DESCRIPTION("DS1WM w1 busmaster driver"); diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index 62c44616d8a9..e2a568c9a43a 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c @@ -7,7 +7,7 @@ * It is a I2C to 1-wire bridge. * There are two variations: -100 and -800, which have 1 or 8 1-wire ports. * The complete datasheet can be obtained from MAXIM's website at: - * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/4382 + * https://www.analog.com/en/products/ds2482-100.html */ #include <linux/module.h> @@ -15,7 +15,7 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/delay.h> -#include <asm/delay.h> +#include <linux/regulator/consumer.h> #include <linux/w1.h> @@ -36,7 +36,7 @@ MODULE_PARM_DESC(active_pullup, "Active pullup (apply to all buses): " \ /* extra configurations - e.g. 1WS */ static int extra_config; -module_param(extra_config, int, S_IRUGO | S_IWUSR); +module_param(extra_config, int, 0644); MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS"); /* @@ -78,10 +78,8 @@ MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8 * To set the channel, write the value at the index of the channel. * Read and compare against the corresponding value to verify the change. */ -static const u8 ds2482_chan_wr[8] = - { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 }; -static const u8 ds2482_chan_rd[8] = - { 0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87 }; +static const u8 ds2482_chan_wr[8] = { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 }; +static const u8 ds2482_chan_rd[8] = { 0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87 }; /* @@ -442,23 +440,26 @@ static u8 ds2482_w1_set_pullup(void *data, int delay) } -static int ds2482_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds2482_probe(struct i2c_client *client) { struct ds2482_data *data; int err = -ENODEV; int temp1; int idx; + int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_BYTE)) return -ENODEV; - if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } + data = devm_kzalloc(&client->dev, sizeof(struct ds2482_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = devm_regulator_get_enable(&client->dev, "vcc"); + if (ret) + return dev_err_probe(&client->dev, ret, "Failed to enable regulator\n"); data->client = client; i2c_set_clientdata(client, data); @@ -466,7 +467,7 @@ static int ds2482_probe(struct i2c_client *client, /* Reset the device (sets the read_ptr to status) */ if (ds2482_send_cmd(data, DS2482_CMD_RESET) < 0) { dev_warn(&client->dev, "DS2482 reset failed.\n"); - goto exit_free; + return err; } /* Sleep at least 525ns to allow the reset to complete */ @@ -477,7 +478,7 @@ static int ds2482_probe(struct i2c_client *client, if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) { dev_warn(&client->dev, "DS2482 reset status " "0x%02X - not a DS2482\n", temp1); - goto exit_free; + return err; } /* Detect the 8-port version */ @@ -519,9 +520,6 @@ exit_w1_remove: if (data->w1_ch[idx].pdev != NULL) w1_remove_master_device(&data->w1_ch[idx].w1_bm); } -exit_free: - kfree(data); -exit: return err; } @@ -535,16 +533,14 @@ static void ds2482_remove(struct i2c_client *client) if (data->w1_ch[idx].pdev != NULL) w1_remove_master_device(&data->w1_ch[idx].w1_bm); } - - /* Free the memory */ - kfree(data); } /* * Driver data (common to all clients) */ static const struct i2c_device_id ds2482_id[] = { - { "ds2482", 0 }, + { "ds2482" }, + { "ds2484" }, { } }; MODULE_DEVICE_TABLE(i2c, ds2482_id); diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c index 0eb560fc0153..e1cac0730cbb 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c @@ -98,6 +98,8 @@ #define ST_EPOF 0x80 /* Status transfer size, 16 bytes status, 16 byte result flags */ #define ST_SIZE 0x20 +/* 1-wire data i/o fifo size, 128 bytes */ +#define FIFO_SIZE 0x80 /* Result Register flags */ #define RR_DETECT 0xA5 /* New device detected */ @@ -304,6 +306,7 @@ static void ds_reset_device(struct ds_device *dev) if (dev->spu_sleep) { /* lower 4 bits are 0, see ds_set_pullup */ u8 del = dev->spu_sleep>>4; + if (ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del)) dev_err(&dev->udev->dev, "%s: Error setting duration\n", __func__); @@ -613,14 +616,11 @@ static int ds_read_byte(struct ds_device *dev, u8 *byte) return 0; } -static int ds_read_block(struct ds_device *dev, u8 *buf, int len) +static int read_block_chunk(struct ds_device *dev, u8 *buf, int len) { struct ds_status st; int err; - if (len > 64*1024) - return -E2BIG; - memset(buf, 0xFF, len); err = ds_send_data(dev, buf, len); @@ -639,6 +639,24 @@ static int ds_read_block(struct ds_device *dev, u8 *buf, int len) return err; } +static int ds_read_block(struct ds_device *dev, u8 *buf, int len) +{ + int err, to_read, rem = len; + + if (len > 64 * 1024) + return -E2BIG; + + do { + to_read = rem <= FIFO_SIZE ? rem : FIFO_SIZE; + err = read_block_chunk(dev, &buf[len - rem], to_read); + if (err < 0) + return err; + rem -= to_read; + } while (rem); + + return err; +} + static int ds_write_block(struct ds_device *dev, u8 *buf, int len) { int err; @@ -731,7 +749,8 @@ static void ds9490r_search(void *data, struct w1_master *master, break; if (st.data_in_buffer_status) { - /* Bulk in can receive partial ids, but when it does + /* + * 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 @@ -743,8 +762,10 @@ static void ds9490r_search(void *data, struct w1_master *master, break; for (i = 0; i < err/8; ++i) { found_ids[found++] = buf[i]; - /* can't know if there will be a discrepancy - * value after until the next id */ + /* + * can't know if there will be a discrepancy + * value after until the next id + */ if (found == search_limit) { master->search_id = buf[i]; break; @@ -760,7 +781,8 @@ static void ds9490r_search(void *data, struct w1_master *master, 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, + /* + * 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 diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index ee716c715710..146fa7c6e74e 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -7,7 +7,7 @@ #include <asm/types.h> #include <linux/atomic.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/delay.h> #include <linux/kernel.h> @@ -39,8 +39,7 @@ #define MATROX_GET_DATA 0x2B #define MATROX_CURSOR_CTL 0x06 -struct matrox_device -{ +struct matrox_device { void __iomem *base_addr; void __iomem *port_index; void __iomem *port_data; @@ -48,7 +47,6 @@ struct matrox_device unsigned long phys_addr; void __iomem *virt_addr; - unsigned long found; struct w1_bus_master *bus_master; }; @@ -64,7 +62,7 @@ struct matrox_device * * Port mapping. */ -static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg) +static inline u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg) { u8 ret; @@ -75,7 +73,7 @@ static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg) return ret; } -static __inline__ void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val) +static inline void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val) { writeb(reg, dev->port_index); writeb(val, dev->port_data); @@ -123,13 +121,8 @@ static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent dev = kzalloc(sizeof(struct matrox_device) + sizeof(struct w1_bus_master), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, - "%s: Failed to create new matrox_device object.\n", - __func__); + if (!dev) return -ENOMEM; - } - dev->bus_master = (struct w1_bus_master *)(dev + 1); @@ -164,8 +157,6 @@ static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent pci_set_drvdata(pdev, dev); - dev->found = 1; - dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n"); return 0; @@ -182,10 +173,9 @@ static void matrox_w1_remove(struct pci_dev *pdev) { struct matrox_device *dev = pci_get_drvdata(pdev); - if (dev->found) { - w1_remove_master_device(dev->bus_master); - iounmap(dev->virt_addr); - } + w1_remove_master_device(dev->bus_master); + iounmap(dev->virt_addr); + kfree(dev); } diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 090cbbf9e1e2..30a190ce4298 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -151,15 +151,13 @@ out_disable_clk: /* * disassociate the w1 device from the driver */ -static int mxc_w1_remove(struct platform_device *pdev) +static void mxc_w1_remove(struct platform_device *pdev) { struct mxc_w1_device *mdev = platform_get_drvdata(pdev); w1_remove_master_device(&mdev->bus_master); clk_disable_unprepare(mdev->clk); - - return 0; } static const struct of_device_id mxc_w1_dt_ids[] = { diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index bf2ec59c1f9d..d13db3396570 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -1,12 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * drivers/w1/masters/omap_hdq.c - * * Copyright (C) 2007,2012 Texas Instruments, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * */ #include <linux/kernel.h> #include <linux/module.h> @@ -48,7 +42,7 @@ static DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue); static int w1_id; -module_param(w1_id, int, S_IRUSR); +module_param(w1_id, int, 0400); MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection in HDQ mode"); struct hdq_data { @@ -451,7 +445,6 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir) out: mutex_unlock(&hdq_data->hdq_mutex); rtn: - pm_runtime_mark_last_busy(hdq_data->dev); pm_runtime_put_autosuspend(hdq_data->dev); return ret; @@ -472,7 +465,6 @@ static u8 omap_w1_reset_bus(void *_hdq) omap_hdq_break(hdq_data); - pm_runtime_mark_last_busy(hdq_data->dev); pm_runtime_put_autosuspend(hdq_data->dev); return 0; @@ -496,7 +488,6 @@ static u8 omap_w1_read_byte(void *_hdq) if (ret) val = -1; - pm_runtime_mark_last_busy(hdq_data->dev); pm_runtime_put_autosuspend(hdq_data->dev); return val; @@ -531,7 +522,6 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) } out_err: - pm_runtime_mark_last_busy(hdq_data->dev); pm_runtime_put_autosuspend(hdq_data->dev); } @@ -579,10 +569,8 @@ static int omap_hdq_probe(struct platform_device *pdev) const char *mode; hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL); - if (!hdq_data) { - dev_dbg(&pdev->dev, "unable to allocate memory\n"); + if (!hdq_data) return -ENOMEM; - } hdq_data->dev = dev; platform_set_drvdata(pdev, hdq_data); @@ -633,7 +621,6 @@ static int omap_hdq_probe(struct platform_device *pdev) omap_hdq_break(hdq_data); - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); omap_w1_master.data = hdq_data; @@ -655,7 +642,7 @@ err_w1: return ret; } -static int omap_hdq_remove(struct platform_device *pdev) +static void omap_hdq_remove(struct platform_device *pdev) { int active; @@ -669,8 +656,6 @@ static int omap_hdq_remove(struct platform_device *pdev) if (active >= 0) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id omap_hdq_dt_ids[] = { diff --git a/drivers/w1/masters/sgi_w1.c b/drivers/w1/masters/sgi_w1.c index e8c7fa68d3cc..af6b1186b763 100644 --- a/drivers/w1/masters/sgi_w1.c +++ b/drivers/w1/masters/sgi_w1.c @@ -93,7 +93,7 @@ static int sgi_w1_probe(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); if (pdata) { - strlcpy(sdev->dev_id, pdata->dev_id, sizeof(sdev->dev_id)); + strscpy(sdev->dev_id, pdata->dev_id, sizeof(sdev->dev_id)); sdev->bus_master.dev_id = sdev->dev_id; } @@ -105,13 +105,11 @@ static int sgi_w1_probe(struct platform_device *pdev) /* * disassociate the w1 device from the driver */ -static int sgi_w1_remove(struct platform_device *pdev) +static void sgi_w1_remove(struct platform_device *pdev) { struct sgi_w1_device *sdev = platform_get_drvdata(pdev); w1_remove_master_device(&sdev->bus_master); - - return 0; } static struct platform_driver sgi_w1_driver = { diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index d4632aace402..a579f95be8f1 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -5,40 +5,45 @@ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi> */ -#include <linux/init.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/w1-gpio.h> -#include <linux/gpio/consumer.h> -#include <linux/of_platform.h> -#include <linux/err.h> -#include <linux/of.h> -#include <linux/delay.h> +#include <linux/property.h> +#include <linux/types.h> #include <linux/w1.h> +struct w1_gpio_ddata { + struct gpio_desc *gpiod; + struct gpio_desc *pullup_gpiod; + unsigned int pullup_duration; +}; + static u8 w1_gpio_set_pullup(void *data, int delay) { - struct w1_gpio_platform_data *pdata = data; + struct w1_gpio_ddata *ddata = data; if (delay) { - pdata->pullup_duration = delay; + ddata->pullup_duration = delay; } else { - if (pdata->pullup_duration) { + if (ddata->pullup_duration) { /* * This will OVERRIDE open drain emulation and force-pull * the line high for some time. */ - gpiod_set_raw_value(pdata->gpiod, 1); - msleep(pdata->pullup_duration); + gpiod_set_raw_value(ddata->gpiod, 1); + msleep(ddata->pullup_duration); /* * This will simply set the line as input since we are doing * open drain emulation in the GPIO library. */ - gpiod_set_value(pdata->gpiod, 1); + gpiod_set_value(ddata->gpiod, 1); } - pdata->pullup_duration = 0; + ddata->pullup_duration = 0; } return 0; @@ -46,83 +51,57 @@ static u8 w1_gpio_set_pullup(void *data, int delay) static void w1_gpio_write_bit(void *data, u8 bit) { - struct w1_gpio_platform_data *pdata = data; + struct w1_gpio_ddata *ddata = data; - gpiod_set_value(pdata->gpiod, bit); + gpiod_set_value(ddata->gpiod, bit); } static u8 w1_gpio_read_bit(void *data) { - struct w1_gpio_platform_data *pdata = data; + struct w1_gpio_ddata *ddata = data; - return gpiod_get_value(pdata->gpiod) ? 1 : 0; + return gpiod_get_value(ddata->gpiod) ? 1 : 0; } -#if defined(CONFIG_OF) -static const 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(struct platform_device *pdev) { struct w1_bus_master *master; - struct w1_gpio_platform_data *pdata; + struct w1_gpio_ddata *ddata; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; /* Enforce open drain mode by default */ enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; int err; - if (of_have_populated_dt()) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - /* - * This parameter means that something else than the gpiolib has - * already set the line into open drain mode, so we should just - * driver it high/low like we are in full control of the line and - * open drain will happen transparently. - */ - if (of_get_property(np, "linux,open-drain", NULL)) - gflags = GPIOD_OUT_LOW; - - pdev->dev.platform_data = pdata; - } - pdata = dev_get_platdata(dev); + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; - if (!pdata) { - dev_err(dev, "No configuration data\n"); - return -ENXIO; - } + /* + * This parameter means that something else than the gpiolib has + * already set the line into open drain mode, so we should just + * driver it high/low like we are in full control of the line and + * open drain will happen transparently. + */ + if (device_property_present(dev, "linux,open-drain")) + gflags = GPIOD_OUT_LOW; - master = devm_kzalloc(dev, sizeof(struct w1_bus_master), - GFP_KERNEL); - if (!master) { - dev_err(dev, "Out of memory\n"); + master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL); + if (!master) return -ENOMEM; - } - pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); - if (IS_ERR(pdata->gpiod)) { - dev_err(dev, "gpio_request (pin) failed\n"); - return PTR_ERR(pdata->gpiod); - } + ddata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); + if (IS_ERR(ddata->gpiod)) + return dev_err_probe(dev, PTR_ERR(ddata->gpiod), "gpio_request (pin) failed\n"); - pdata->pullup_gpiod = + ddata->pullup_gpiod = devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW); - if (IS_ERR(pdata->pullup_gpiod)) { - dev_err(dev, "gpio_request_one " - "(ext_pullup_enable_pin) failed\n"); - return PTR_ERR(pdata->pullup_gpiod); - } + if (IS_ERR(ddata->pullup_gpiod)) + return dev_err_probe(dev, PTR_ERR(ddata->pullup_gpiod), + "gpio_request (ext_pullup_enable_pin) failed\n"); - master->data = pdata; + master->data = ddata; master->read_bit = w1_gpio_read_bit; - gpiod_direction_output(pdata->gpiod, 1); + gpiod_direction_output(ddata->gpiod, 1); master->write_bit = w1_gpio_write_bit; /* @@ -135,65 +114,36 @@ static int w1_gpio_probe(struct platform_device *pdev) master->set_pullup = w1_gpio_set_pullup; err = w1_add_master_device(master); - if (err) { - dev_err(dev, "w1_add_master device failed\n"); - return err; - } - - if (pdata->enable_external_pullup) - pdata->enable_external_pullup(1); + if (err) + return dev_err_probe(dev, err, "w1_add_master device failed\n"); - if (pdata->pullup_gpiod) - gpiod_set_value(pdata->pullup_gpiod, 1); + gpiod_set_value(ddata->pullup_gpiod, 1); platform_set_drvdata(pdev, master); return 0; } -static int w1_gpio_remove(struct platform_device *pdev) +static void w1_gpio_remove(struct platform_device *pdev) { struct w1_bus_master *master = platform_get_drvdata(pdev); - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); - - if (pdata->enable_external_pullup) - pdata->enable_external_pullup(0); + struct w1_gpio_ddata *ddata = master->data; - if (pdata->pullup_gpiod) - gpiod_set_value(pdata->pullup_gpiod, 0); + gpiod_set_value(ddata->pullup_gpiod, 0); w1_remove_master_device(master); - - return 0; -} - -static int __maybe_unused w1_gpio_suspend(struct device *dev) -{ - struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); - - if (pdata->enable_external_pullup) - pdata->enable_external_pullup(0); - - return 0; } -static int __maybe_unused w1_gpio_resume(struct device *dev) -{ - struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); - - if (pdata->enable_external_pullup) - pdata->enable_external_pullup(1); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(w1_gpio_pm_ops, w1_gpio_suspend, w1_gpio_resume); +static const struct of_device_id w1_gpio_dt_ids[] = { + { .compatible = "w1-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); 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), + .of_match_table = w1_gpio_dt_ids, }, .probe = w1_gpio_probe, .remove = w1_gpio_remove, diff --git a/drivers/w1/masters/w1-uart.c b/drivers/w1/masters/w1-uart.c new file mode 100644 index 000000000000..c87eea347806 --- /dev/null +++ b/drivers/w1/masters/w1-uart.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * w1-uart - UART 1-Wire bus driver + * + * Uses the UART interface (via Serial Device Bus) to create the 1-Wire + * timing patterns. Implements the following 1-Wire master interface: + * + * - reset_bus: requests baud-rate 9600 + * + * - touch_bit: requests baud-rate 115200 + * + * Author: Christoph Winklhofer <cj.winklhofer@gmail.com> + */ + +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/serdev.h> +#include <linux/w1.h> + +/* UART packet contains start and stop bit */ +#define W1_UART_BITS_PER_PACKET (BITS_PER_BYTE + 2) + +/* Timeout to wait for completion of serdev-receive */ +#define W1_UART_TIMEOUT msecs_to_jiffies(500) + +/** + * struct w1_uart_config - configuration for 1-Wire operation + * @baudrate: baud-rate returned from serdev + * @delay_us: delay to complete a 1-Wire cycle (in us) + * @tx_byte: byte to generate 1-Wire timing pattern + */ +struct w1_uart_config { + unsigned int baudrate; + unsigned int delay_us; + u8 tx_byte; +}; + +/** + * struct w1_uart_device - 1-Wire UART device structure + * @serdev: serial device + * @bus: w1-bus master + * @cfg_reset: config for 1-Wire reset + * @cfg_touch_0: config for 1-Wire write-0 cycle + * @cfg_touch_1: config for 1-Wire write-1 and read cycle + * @rx_byte_received: completion for serdev receive + * @rx_mutex: mutex to protect rx_err and rx_byte + * @rx_err: indicates an error in serdev-receive + * @rx_byte: result byte from serdev-receive + */ +struct w1_uart_device { + struct serdev_device *serdev; + struct w1_bus_master bus; + + struct w1_uart_config cfg_reset; + struct w1_uart_config cfg_touch_0; + struct w1_uart_config cfg_touch_1; + + struct completion rx_byte_received; + /* + * protect rx_err and rx_byte from concurrent access in + * w1-callbacks and serdev-receive. + */ + struct mutex rx_mutex; + int rx_err; + u8 rx_byte; +}; + +/** + * struct w1_uart_limits - limits for 1-Wire operations + * @baudrate: Requested baud-rate to create 1-Wire timing pattern + * @bit_min_us: minimum time for a bit (in us) + * @bit_max_us: maximum time for a bit (in us) + * @sample_us: timespan to sample 1-Wire response + * @cycle_us: duration of the 1-Wire cycle + */ +struct w1_uart_limits { + unsigned int baudrate; + unsigned int bit_min_us; + unsigned int bit_max_us; + unsigned int sample_us; + unsigned int cycle_us; +}; + +static inline unsigned int baud_to_bit_ns(unsigned int baud) +{ + return NSEC_PER_SEC / baud; +} + +static inline unsigned int to_ns(unsigned int us) +{ + return us * NSEC_PER_USEC; +} + +/* + * Set baud-rate, delay and tx-byte to create a 1-Wire pulse and adapt + * the tx-byte according to the actual baud-rate. + * + * Reject when: + * - time for a bit outside min/max range + * - a 1-Wire response is not detectable for sent byte + */ +static int w1_uart_set_config(struct serdev_device *serdev, + const struct w1_uart_limits *limits, + struct w1_uart_config *w1cfg) +{ + unsigned int packet_ns; + unsigned int bits_low; + unsigned int bit_ns; + unsigned int low_ns; + + w1cfg->baudrate = serdev_device_set_baudrate(serdev, limits->baudrate); + if (w1cfg->baudrate == 0) + return -EINVAL; + + /* Compute in nanoseconds for accuracy */ + bit_ns = baud_to_bit_ns(w1cfg->baudrate); + bits_low = to_ns(limits->bit_min_us) / bit_ns; + /* start bit is always low */ + low_ns = bit_ns * (bits_low + 1); + + if (low_ns < to_ns(limits->bit_min_us)) + return -EINVAL; + + if (low_ns > to_ns(limits->bit_max_us)) + return -EINVAL; + + /* 1-Wire response detectable for sent byte */ + if (limits->sample_us > 0 && + bit_ns * BITS_PER_BYTE < low_ns + to_ns(limits->sample_us)) + return -EINVAL; + + /* delay: 1-Wire cycle takes longer than the UART packet */ + packet_ns = bit_ns * W1_UART_BITS_PER_PACKET; + w1cfg->delay_us = 0; + if (to_ns(limits->cycle_us) > packet_ns) + w1cfg->delay_us = + (to_ns(limits->cycle_us) - packet_ns) / NSEC_PER_USEC; + + /* byte to create 1-Wire pulse */ + w1cfg->tx_byte = 0xff << bits_low; + + return 0; +} + +/* + * Configuration for reset and presence detect + * - bit_min_us is 480us, add margin and use 485us + * - limits for sample time 60us-75us, use 65us + */ +static int w1_uart_set_config_reset(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device_node *np = serdev->dev.of_node; + + struct w1_uart_limits limits = { .baudrate = 9600, + .bit_min_us = 485, + .bit_max_us = 640, + .sample_us = 65, + .cycle_us = 960 }; + + of_property_read_u32(np, "reset-bps", &limits.baudrate); + + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_reset); +} + +/* + * Configuration for write-0 cycle (touch bit 0) + * - bit_min_us is 60us, add margin and use 65us + * - no sampling required, sample_us = 0 + */ +static int w1_uart_set_config_touch_0(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device_node *np = serdev->dev.of_node; + + struct w1_uart_limits limits = { .baudrate = 115200, + .bit_min_us = 65, + .bit_max_us = 120, + .sample_us = 0, + .cycle_us = 70 }; + + of_property_read_u32(np, "write-0-bps", &limits.baudrate); + + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_0); +} + +/* + * Configuration for write-1 and read cycle (touch bit 1) + * - bit_min_us is 5us, add margin and use 6us + * - limits for sample time 5us-15us, use 15us + */ +static int w1_uart_set_config_touch_1(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device_node *np = serdev->dev.of_node; + + struct w1_uart_limits limits = { .baudrate = 115200, + .bit_min_us = 6, + .bit_max_us = 15, + .sample_us = 15, + .cycle_us = 70 }; + + of_property_read_u32(np, "write-1-bps", &limits.baudrate); + + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_1); +} + +/* + * Configure and open the serial device + */ +static int w1_uart_serdev_open(struct w1_uart_device *w1dev) +{ + struct serdev_device *serdev = w1dev->serdev; + struct device *dev = &serdev->dev; + int ret; + + ret = devm_serdev_device_open(dev, serdev); + if (ret < 0) + return ret; + + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); + if (ret < 0) { + dev_err(dev, "set parity failed\n"); + return ret; + } + + ret = w1_uart_set_config_reset(w1dev); + if (ret < 0) { + dev_err(dev, "config for reset failed\n"); + return ret; + } + + ret = w1_uart_set_config_touch_0(w1dev); + if (ret < 0) { + dev_err(dev, "config for touch-0 failed\n"); + return ret; + } + + ret = w1_uart_set_config_touch_1(w1dev); + if (ret < 0) { + dev_err(dev, "config for touch-1 failed\n"); + return ret; + } + + serdev_device_set_flow_control(serdev, false); + + return 0; +} + +/* + * Send one byte (tx_byte) and read one byte (rx_byte) via serdev. + */ +static int w1_uart_serdev_tx_rx(struct w1_uart_device *w1dev, + const struct w1_uart_config *w1cfg, u8 *rx_byte) +{ + struct serdev_device *serdev = w1dev->serdev; + int ret; + + serdev_device_write_flush(serdev); + serdev_device_set_baudrate(serdev, w1cfg->baudrate); + + /* write and immediately read one byte */ + reinit_completion(&w1dev->rx_byte_received); + ret = serdev_device_write_buf(serdev, &w1cfg->tx_byte, 1); + if (ret != 1) + return -EIO; + ret = wait_for_completion_interruptible_timeout( + &w1dev->rx_byte_received, W1_UART_TIMEOUT); + if (ret <= 0) + return -EIO; + + /* locking could fail when serdev is unexpectedly receiving. */ + if (!mutex_trylock(&w1dev->rx_mutex)) + return -EIO; + + ret = w1dev->rx_err; + if (ret == 0) + *rx_byte = w1dev->rx_byte; + + mutex_unlock(&w1dev->rx_mutex); + + if (w1cfg->delay_us > 0) + fsleep(w1cfg->delay_us); + + return ret; +} + +static size_t w1_uart_serdev_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) +{ + struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev); + + mutex_lock(&w1dev->rx_mutex); + + /* sent a single byte and receive one single byte */ + if (count == 1) { + w1dev->rx_byte = buf[0]; + w1dev->rx_err = 0; + } else { + w1dev->rx_err = -EIO; + } + + mutex_unlock(&w1dev->rx_mutex); + complete(&w1dev->rx_byte_received); + + return count; +} + +static const struct serdev_device_ops w1_uart_serdev_ops = { + .receive_buf = w1_uart_serdev_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +/* + * 1-wire reset and presence detect: A present slave will manipulate + * the received byte by pulling the 1-Wire low. + */ +static u8 w1_uart_reset_bus(void *data) +{ + struct w1_uart_device *w1dev = data; + const struct w1_uart_config *w1cfg = &w1dev->cfg_reset; + int ret; + u8 val; + + ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val); + if (ret < 0) + return -1; + + /* Device present (0) or no device (1) */ + return val != w1cfg->tx_byte ? 0 : 1; +} + +/* + * 1-Wire read and write cycle: Only the read-0 manipulates the + * received byte, all others left the line untouched. + */ +static u8 w1_uart_touch_bit(void *data, u8 bit) +{ + struct w1_uart_device *w1dev = data; + const struct w1_uart_config *w1cfg = bit ? &w1dev->cfg_touch_1 : + &w1dev->cfg_touch_0; + int ret; + u8 val; + + ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val); + + /* return inactive bus state on error */ + if (ret < 0) + return 1; + + return val == w1cfg->tx_byte ? 1 : 0; +} + +static int w1_uart_probe(struct serdev_device *serdev) +{ + struct device *dev = &serdev->dev; + struct w1_uart_device *w1dev; + int ret; + + w1dev = devm_kzalloc(dev, sizeof(*w1dev), GFP_KERNEL); + if (!w1dev) + return -ENOMEM; + w1dev->bus.data = w1dev; + w1dev->bus.reset_bus = w1_uart_reset_bus; + w1dev->bus.touch_bit = w1_uart_touch_bit; + w1dev->serdev = serdev; + + init_completion(&w1dev->rx_byte_received); + mutex_init(&w1dev->rx_mutex); + + serdev_device_set_drvdata(serdev, w1dev); + serdev_device_set_client_ops(serdev, &w1_uart_serdev_ops); + ret = w1_uart_serdev_open(w1dev); + if (ret < 0) + return ret; + + return w1_add_master_device(&w1dev->bus); +} + +static void w1_uart_remove(struct serdev_device *serdev) +{ + struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev); + + /* + * Waits until w1-uart callbacks are finished, serdev is closed + * and its device data released automatically by devres (waits + * until serdev-receive is finished). + */ + w1_remove_master_device(&w1dev->bus); +} + +static const struct of_device_id w1_uart_of_match[] = { + { .compatible = "w1-uart" }, + {}, +}; +MODULE_DEVICE_TABLE(of, w1_uart_of_match); + +static struct serdev_device_driver w1_uart_driver = { + .driver = { + .name = "w1-uart", + .of_match_table = w1_uart_of_match, + }, + .probe = w1_uart_probe, + .remove = w1_uart_remove, +}; + +module_serdev_device_driver(w1_uart_driver); + +MODULE_DESCRIPTION("UART w1 bus driver"); +MODULE_AUTHOR("Christoph Winklhofer <cj.winklhofer@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 687753889c34..32b8a757744e 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -71,8 +71,8 @@ config W1_SLAVE_DS2805 help Say Y here if you want to use a 1-wire is a 112-byte user-programmable EEPROM is - organized as 7 pages of 16 bytes each with 64bit - unique number. Requires OverDrive Speed to talk to. + organized as 7 pages of 16 bytes each with 64bit + unique number. Requires OverDrive Speed to talk to. config W1_SLAVE_DS2430 tristate "256b EEPROM family support (DS2430)" diff --git a/drivers/w1/slaves/w1_ds2406.c b/drivers/w1/slaves/w1_ds2406.c index 6c269af73c80..efb2e784f8d7 100644 --- a/drivers/w1/slaves/w1_ds2406.c +++ b/drivers/w1/slaves/w1_ds2406.c @@ -24,14 +24,12 @@ static ssize_t w1_f12_read_state( struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - u8 w1_buf[6]={W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0}; + u8 w1_buf[6] = {W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0}; struct w1_slave *sl = kobj_to_w1_slave(kobj); - u16 crc=0; - int i; - ssize_t rtnval=1; + ssize_t rtnval = 1; if (off != 0) return 0; @@ -47,12 +45,10 @@ static ssize_t w1_f12_read_state( w1_write_block(sl->master, w1_buf, 3); w1_read_block(sl->master, w1_buf+3, 3); - for (i=0; i<6; i++) - crc=crc16_byte(crc, w1_buf[i]); - if (crc==0xb001) /* good read? */ - *buf=((w1_buf[3]>>5)&3)|0x30; + if (crc16(0, w1_buf, sizeof(w1_buf)) == 0xb001) /* good read? */ + *buf = ((w1_buf[3]>>5)&3)|0x30; else - rtnval=-EIO; + rtnval = -EIO; mutex_unlock(&sl->master->bus_mutex); @@ -61,14 +57,12 @@ static ssize_t w1_f12_read_state( static ssize_t w1_f12_write_output( struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); - u8 w1_buf[6]={W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0}; - u16 crc=0; - int i; - ssize_t rtnval=1; + u8 w1_buf[6] = {W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0}; + ssize_t rtnval = 1; if (count != 1 || off != 0) return -EFAULT; @@ -83,23 +77,21 @@ static ssize_t w1_f12_write_output( w1_buf[3] = (((*buf)&3)<<5)|0x1F; w1_write_block(sl->master, w1_buf, 4); w1_read_block(sl->master, w1_buf+4, 2); - for (i=0; i<6; i++) - crc=crc16_byte(crc, w1_buf[i]); - if (crc==0xb001) /* good read? */ + if (crc16(0, w1_buf, sizeof(w1_buf)) == 0xb001) /* good read? */ w1_write_8(sl->master, 0xFF); else - rtnval=-EIO; + rtnval = -EIO; mutex_unlock(&sl->master->bus_mutex); return rtnval; } #define NB_SYSFS_BIN_FILES 2 -static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { +static const struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { { .attr = { .name = "state", - .mode = S_IRUGO, + .mode = 0444, }, .size = 1, .read = w1_f12_read_state, @@ -107,7 +99,7 @@ static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { { .attr = { .name = "output", - .mode = S_IRUGO | S_IWUSR | S_IWGRP, + .mode = 0664, }, .size = 1, .write = w1_f12_write_output, @@ -133,6 +125,7 @@ static int w1_f12_add_slave(struct w1_slave *sl) static void w1_f12_remove_slave(struct w1_slave *sl) { int i; + for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i) sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f12_sysfs_bin_files[i])); diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c index ad102c577122..30d1d574d2e5 100644 --- a/drivers/w1/slaves/w1_ds2408.c +++ b/drivers/w1/slaves/w1_ds2408.c @@ -35,12 +35,12 @@ #define W1_F29_SUCCESS_CONFIRM_BYTE 0xAA -static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf) +static int _read_reg(struct w1_slave *sl, u8 address, unsigned char *buf) { u8 wrbuf[3]; - dev_dbg(&sl->dev, - "Reading with slave: %p, reg addr: %0#4x, buff addr: %p", - sl, (unsigned int)address, buf); + + dev_dbg(&sl->dev, "Reading with slave: %p, reg addr: %0#4x, buff addr: %p", + sl, (unsigned int)address, buf); if (!buf) return -EINVAL; @@ -65,8 +65,8 @@ static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf) } static ssize_t state_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, - size_t count) + const struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { dev_dbg(&kobj_to_w1_slave(kobj)->dev, "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", @@ -77,7 +77,7 @@ static ssize_t state_read(struct file *filp, struct kobject *kobj, } static ssize_t output_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { dev_dbg(&kobj_to_w1_slave(kobj)->dev, @@ -90,7 +90,7 @@ static ssize_t output_read(struct file *filp, struct kobject *kobj, } static ssize_t activity_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { dev_dbg(&kobj_to_w1_slave(kobj)->dev, @@ -103,8 +103,8 @@ static ssize_t activity_read(struct file *filp, struct kobject *kobj, } static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t off, size_t count) + const struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { dev_dbg(&kobj_to_w1_slave(kobj)->dev, "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", @@ -117,7 +117,7 @@ static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj, static ssize_t cond_search_polarity_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { if (count != 1 || off != 0) @@ -127,8 +127,8 @@ static ssize_t cond_search_polarity_read(struct file *filp, } static ssize_t status_control_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t off, size_t count) + const struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { if (count != 1 || off != 0) return -EFAULT; @@ -160,7 +160,7 @@ static bool optional_read_back_valid(struct w1_slave *sl, u8 expected) #endif static ssize_t output_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -206,11 +206,11 @@ out: } -/** +/* * Writing to the activity file resets the activity latches. */ static ssize_t activity_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -240,8 +240,8 @@ error: } static ssize_t status_control_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t off, size_t count) + const struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); u8 w1_buf[4]; @@ -292,7 +292,7 @@ static int w1_f29_disable_test_mode(struct w1_slave *sl) { int res; u8 magic[10] = {0x96, }; - u64 rn = le64_to_cpu(*((u64*)&sl->reg_num)); + u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num)); memcpy(&magic[1], &rn, 8); magic[9] = 0x3C; @@ -310,14 +310,14 @@ out: return res; } -static BIN_ATTR_RO(state, 1); -static BIN_ATTR_RW(output, 1); -static BIN_ATTR_RW(activity, 1); -static BIN_ATTR_RO(cond_search_mask, 1); -static BIN_ATTR_RO(cond_search_polarity, 1); -static BIN_ATTR_RW(status_control, 1); +static const BIN_ATTR_RO(state, 1); +static const BIN_ATTR_RW(output, 1); +static const BIN_ATTR_RW(activity, 1); +static const BIN_ATTR_RO(cond_search_mask, 1); +static const BIN_ATTR_RO(cond_search_polarity, 1); +static const BIN_ATTR_RW(status_control, 1); -static struct bin_attribute *w1_f29_bin_attrs[] = { +static const struct bin_attribute *const w1_f29_bin_attrs[] = { &bin_attr_state, &bin_attr_output, &bin_attr_activity, diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c index c8cfac555b48..94d3cd2a0ec9 100644 --- a/drivers/w1/slaves/w1_ds2413.c +++ b/drivers/w1/slaves/w1_ds2413.c @@ -25,8 +25,8 @@ #define W1_F3A_INVALID_PIO_STATE 0xFF static ssize_t state_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, - size_t count) + const struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); unsigned int retries = W1_F3A_RETRIES; @@ -78,10 +78,10 @@ out: return bytes_read; } -static BIN_ATTR_RO(state, 1); +static const BIN_ATTR_RO(state, 1); static ssize_t output_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -99,8 +99,10 @@ static ssize_t output_write(struct file *filp, struct kobject *kobj, if (w1_reset_select_slave(sl)) goto out; - /* according to the DS2413 datasheet the most significant 6 bits - should be set to "1"s, so do it now */ + /* + * according to the DS2413 datasheet the most significant 6 bits + * should be set to "1"s, so do it now + */ *buf = *buf | 0xFC; while (retries--) { @@ -126,9 +128,9 @@ out: return bytes_written; } -static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1); +static const BIN_ATTR(output, 0664, NULL, output_write, 1); -static struct bin_attribute *w1_f3a_bin_attrs[] = { +static const struct bin_attribute *const w1_f3a_bin_attrs[] = { &bin_attr_state, &bin_attr_output, NULL, diff --git a/drivers/w1/slaves/w1_ds2430.c b/drivers/w1/slaves/w1_ds2430.c index 0ea7d779d17a..3d8c2b238aed 100644 --- a/drivers/w1/slaves/w1_ds2430.c +++ b/drivers/w1/slaves/w1_ds2430.c @@ -95,7 +95,7 @@ static int w1_f14_readblock(struct w1_slave *sl, int off, int count, char *buf) } static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -202,7 +202,7 @@ retry: } static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -263,9 +263,9 @@ out_up: return count; } -static BIN_ATTR_RW(eeprom, W1_F14_EEPROM_SIZE); +static const BIN_ATTR_RW(eeprom, W1_F14_EEPROM_SIZE); -static struct bin_attribute *w1_f14_bin_attrs[] = { +static const struct bin_attribute *const w1_f14_bin_attrs[] = { &bin_attr_eeprom, NULL, }; diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c index 6856b1c29e17..5749880b67c5 100644 --- a/drivers/w1/slaves/w1_ds2431.c +++ b/drivers/w1/slaves/w1_ds2431.c @@ -95,7 +95,7 @@ static int w1_f2d_readblock(struct w1_slave *sl, int off, int count, char *buf) } static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -201,7 +201,7 @@ retry: } static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -262,9 +262,9 @@ out_up: return count; } -static BIN_ATTR_RW(eeprom, W1_F2D_EEPROM_SIZE); +static const BIN_ATTR_RW(eeprom, W1_F2D_EEPROM_SIZE); -static struct bin_attribute *w1_f2d_bin_attrs[] = { +static const struct bin_attribute *const w1_f2d_bin_attrs[] = { &bin_attr_eeprom, NULL, }; diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index 0f72df15a024..3371d804dc6c 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * w1_ds2433.c - w1 family 23 (DS2433) driver + * w1_ds2433.c - w1 family 23 (DS2433) & 43 (DS28EC20) eeprom driver * * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> + * Copyright (c) 2023 Marc Ferland <marc.ferland@sonatest.com> */ #include <linux/kernel.h> @@ -23,26 +24,48 @@ #include <linux/w1.h> #define W1_EEPROM_DS2433 0x23 +#define W1_EEPROM_DS28EC20 0x43 + +#define W1_EEPROM_DS2433_SIZE 512 +#define W1_EEPROM_DS28EC20_SIZE 2560 -#define W1_EEPROM_SIZE 512 -#define W1_PAGE_COUNT 16 #define W1_PAGE_SIZE 32 #define W1_PAGE_BITS 5 #define W1_PAGE_MASK 0x1F - -#define W1_F23_TIME 300 +#define W1_VALIDCRC_MAX 96 #define W1_F23_READ_EEPROM 0xF0 #define W1_F23_WRITE_SCRATCH 0x0F #define W1_F23_READ_SCRATCH 0xAA #define W1_F23_COPY_SCRATCH 0x55 +struct ds2433_config { + size_t eeprom_size; /* eeprom size in bytes */ + unsigned int page_count; /* number of 256 bits pages */ + unsigned int tprog; /* time in ms for page programming */ +}; + +static const struct ds2433_config config_f23 = { + .eeprom_size = W1_EEPROM_DS2433_SIZE, + .page_count = 16, + .tprog = 5, +}; + +static const struct ds2433_config config_f43 = { + .eeprom_size = W1_EEPROM_DS28EC20_SIZE, + .page_count = 80, + .tprog = 10, +}; + struct w1_f23_data { - u8 memory[W1_EEPROM_SIZE]; - u32 validcrc; +#ifdef CONFIG_W1_SLAVE_DS2433_CRC + u8 *memory; + DECLARE_BITMAP(validcrc, W1_VALIDCRC_MAX); +#endif + const struct ds2433_config *cfg; }; -/** +/* * Check the file size bounds and adjusts count as needed. * This would not be needed if the file size didn't reset to 0 after a write. */ @@ -64,11 +87,11 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data, u8 wrbuf[3]; int off = block * W1_PAGE_SIZE; - if (data->validcrc & (1 << block)) + if (test_bit(block, data->validcrc)) return 0; if (w1_reset_select_slave(sl)) { - data->validcrc = 0; + bitmap_zero(data->validcrc, data->cfg->page_count); return -EIO; } @@ -80,14 +103,14 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data, /* cache the block if the CRC is valid */ if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID) - data->validcrc |= (1 << block); + set_bit(block, data->validcrc); return 0; } #endif /* CONFIG_W1_SLAVE_DS2433_CRC */ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -98,7 +121,8 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, u8 wrbuf[3]; #endif - if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) + count = w1_f23_fix_count(off, count, bin_attr->size); + if (!count) return 0; mutex_lock(&sl->master->bus_mutex); @@ -115,7 +139,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, } memcpy(buf, &data->memory[off], count); -#else /* CONFIG_W1_SLAVE_DS2433_CRC */ +#else /* CONFIG_W1_SLAVE_DS2433_CRC */ /* read directly from the EEPROM */ if (w1_reset_select_slave(sl)) { @@ -138,22 +162,21 @@ out_up: } /** - * Writes to the scratchpad and reads it back for verification. + * w1_f23_write() - Writes to the scratchpad and reads it back for verification. + * @sl: The slave structure + * @addr: Address for the write + * @len: length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) + * @data: The data to write + * * Then copies the scratchpad to EEPROM. * The data must be on one page. * The master must be locked. * - * @param sl The slave structure - * @param addr Address for the write - * @param len length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) - * @param data The data to write - * @return 0=Success -1=failure + * Return: 0=Success, -1=failure */ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data) { -#ifdef CONFIG_W1_SLAVE_DS2433_CRC struct w1_f23_data *f23 = sl->family_data; -#endif u8 wrbuf[4]; u8 rdbuf[W1_PAGE_SIZE + 3]; u8 es = (addr + len - 1) & 0x1f; @@ -189,25 +212,26 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data) wrbuf[3] = es; w1_write_block(sl->master, wrbuf, 4); - /* Sleep for 5 ms to wait for the write to complete */ - msleep(5); + /* Sleep for tprog ms to wait for the write to complete */ + msleep(f23->cfg->tprog); /* Reset the bus to wake up the EEPROM (this may not be needed) */ w1_reset_bus(sl->master); #ifdef CONFIG_W1_SLAVE_DS2433_CRC - f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS)); + clear_bit(addr >> W1_PAGE_BITS, f23->validcrc); #endif return 0; } static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); int addr, len, idx; - if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) + count = w1_f23_fix_count(off, count, bin_attr->size); + if (!count) return 0; #ifdef CONFIG_W1_SLAVE_DS2433_CRC @@ -250,10 +274,22 @@ out_up: return count; } -static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE); +static const struct bin_attribute bin_attr_f23_eeprom = { + .attr = { .name = "eeprom", .mode = 0644 }, + .read = eeprom_read, + .write = eeprom_write, + .size = W1_EEPROM_DS2433_SIZE, +}; + +static const struct bin_attribute bin_attr_f43_eeprom = { + .attr = { .name = "eeprom", .mode = 0644 }, + .read = eeprom_read, + .write = eeprom_write, + .size = W1_EEPROM_DS28EC20_SIZE, +}; -static struct bin_attribute *w1_f23_bin_attributes[] = { - &bin_attr_eeprom, +static const struct bin_attribute *const w1_f23_bin_attributes[] = { + &bin_attr_f23_eeprom, NULL, }; @@ -266,26 +302,63 @@ static const struct attribute_group *w1_f23_groups[] = { NULL, }; +static const struct bin_attribute *const w1_f43_bin_attributes[] = { + &bin_attr_f43_eeprom, + NULL, +}; + +static const struct attribute_group w1_f43_group = { + .bin_attrs = w1_f43_bin_attributes, +}; + +static const struct attribute_group *w1_f43_groups[] = { + &w1_f43_group, + NULL, +}; + static int w1_f23_add_slave(struct w1_slave *sl) { -#ifdef CONFIG_W1_SLAVE_DS2433_CRC struct w1_f23_data *data; data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL); if (!data) return -ENOMEM; + + switch (sl->family->fid) { + case W1_EEPROM_DS2433: + data->cfg = &config_f23; + break; + case W1_EEPROM_DS28EC20: + data->cfg = &config_f43; + break; + } + +#ifdef CONFIG_W1_SLAVE_DS2433_CRC + if (data->cfg->page_count > W1_VALIDCRC_MAX) { + dev_err(&sl->dev, "page count too big for crc bitmap\n"); + kfree(data); + return -EINVAL; + } + data->memory = kzalloc(data->cfg->eeprom_size, GFP_KERNEL); + if (!data->memory) { + kfree(data); + return -ENOMEM; + } + bitmap_zero(data->validcrc, data->cfg->page_count); +#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ sl->family_data = data; -#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ return 0; } static void w1_f23_remove_slave(struct w1_slave *sl) { -#ifdef CONFIG_W1_SLAVE_DS2433_CRC - kfree(sl->family_data); + struct w1_f23_data *data = sl->family_data; sl->family_data = NULL; -#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ +#ifdef CONFIG_W1_SLAVE_DS2433_CRC + kfree(data->memory); +#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ + kfree(data); } static const struct w1_family_ops w1_f23_fops = { @@ -294,13 +367,53 @@ static const struct w1_family_ops w1_f23_fops = { .groups = w1_f23_groups, }; +static const struct w1_family_ops w1_f43_fops = { + .add_slave = w1_f23_add_slave, + .remove_slave = w1_f23_remove_slave, + .groups = w1_f43_groups, +}; + static struct w1_family w1_family_23 = { .fid = W1_EEPROM_DS2433, .fops = &w1_f23_fops, }; -module_w1_family(w1_family_23); + +static struct w1_family w1_family_43 = { + .fid = W1_EEPROM_DS28EC20, + .fops = &w1_f43_fops, +}; + +static int __init w1_ds2433_init(void) +{ + int err; + + err = w1_register_family(&w1_family_23); + if (err) + return err; + + err = w1_register_family(&w1_family_43); + if (err) + goto err_43; + + return 0; + +err_43: + w1_unregister_family(&w1_family_23); + return err; +} + +static void __exit w1_ds2433_exit(void) +{ + w1_unregister_family(&w1_family_23); + w1_unregister_family(&w1_family_43); +} + +module_init(w1_ds2433_init); +module_exit(w1_ds2433_exit); MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); -MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM"); +MODULE_AUTHOR("Marc Ferland <marc.ferland@sonatest.com>"); +MODULE_DESCRIPTION("w1 family 23/43 driver for DS2433 (4kb) and DS28EC20 (20kb)"); MODULE_LICENSE("GPL"); MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433)); +MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS28EC20)); diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c index ca64f99c8f3d..86860f727e96 100644 --- a/drivers/w1/slaves/w1_ds2438.c +++ b/drivers/w1/slaves/w1_ds2438.c @@ -66,8 +66,6 @@ static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) size_t count; while (retries--) { - crc = 0; - if (w1_reset_select_slave(sl)) continue; w1_buf[0] = W1_DS2438_RECALL_MEMORY; @@ -290,7 +288,7 @@ static int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage) } static ssize_t iad_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -312,7 +310,7 @@ static ssize_t iad_write(struct file *filp, struct kobject *kobj, } static ssize_t iad_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -333,7 +331,7 @@ static ssize_t iad_read(struct file *filp, struct kobject *kobj, } static ssize_t page0_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -363,7 +361,7 @@ static ssize_t page0_read(struct file *filp, struct kobject *kobj, } static ssize_t page1_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -393,7 +391,7 @@ static ssize_t page1_read(struct file *filp, struct kobject *kobj, } static ssize_t offset_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -412,7 +410,7 @@ static ssize_t offset_write(struct file *filp, struct kobject *kobj, } static ssize_t temperature_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -433,7 +431,7 @@ static ssize_t temperature_read(struct file *filp, struct kobject *kobj, } static ssize_t vad_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -454,7 +452,7 @@ static ssize_t vad_read(struct file *filp, struct kobject *kobj, } static ssize_t vdd_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -474,15 +472,15 @@ static ssize_t vdd_read(struct file *filp, struct kobject *kobj, return ret; } -static BIN_ATTR_RW(iad, 0); -static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); -static BIN_ATTR_RO(page1, DS2438_PAGE_SIZE); -static BIN_ATTR_WO(offset, 2); -static BIN_ATTR_RO(temperature, 0/* real length varies */); -static BIN_ATTR_RO(vad, 0/* real length varies */); -static BIN_ATTR_RO(vdd, 0/* real length varies */); +static const BIN_ATTR_RW(iad, 0); +static const BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); +static const BIN_ATTR_RO(page1, DS2438_PAGE_SIZE); +static const BIN_ATTR_WO(offset, 2); +static const BIN_ATTR_RO(temperature, 0/* real length varies */); +static const BIN_ATTR_RO(vad, 0/* real length varies */); +static const BIN_ATTR_RO(vdd, 0/* real length varies */); -static struct bin_attribute *w1_ds2438_bin_attrs[] = { +static const struct bin_attribute *const w1_ds2438_bin_attrs[] = { &bin_attr_iad, &bin_attr_page0, &bin_attr_page1, diff --git a/drivers/w1/slaves/w1_ds250x.c b/drivers/w1/slaves/w1_ds250x.c index 7592c7050d1d..cb426f7dd23d 100644 --- a/drivers/w1/slaves/w1_ds250x.c +++ b/drivers/w1/slaves/w1_ds250x.c @@ -168,6 +168,7 @@ static int w1_eprom_add_slave(struct w1_slave *sl) struct nvmem_device *nvmem; struct nvmem_config nvmem_cfg = { .dev = &sl->dev, + .add_legacy_fixed_of_cells = true, .reg_read = w1_nvmem_read, .type = NVMEM_TYPE_OTP, .read_only = true, diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c index 9dcb5a54f7fc..889a6099c314 100644 --- a/drivers/w1/slaves/w1_ds2780.c +++ b/drivers/w1/slaves/w1_ds2780.c @@ -87,16 +87,17 @@ int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd) EXPORT_SYMBOL(w1_ds2780_eeprom_cmd); static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); + return w1_ds2780_io(dev, buf, off, count, 0); } -static BIN_ATTR_RO(w1_slave, DS2780_DATA_SIZE); +static const BIN_ATTR_RO(w1_slave, DS2780_DATA_SIZE); -static struct bin_attribute *w1_ds2780_bin_attrs[] = { +static const struct bin_attribute *const w1_ds2780_bin_attrs[] = { &bin_attr_w1_slave, NULL, }; diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c index 2cb7c020b607..88f3abd5cd4b 100644 --- a/drivers/w1/slaves/w1_ds2781.c +++ b/drivers/w1/slaves/w1_ds2781.c @@ -84,16 +84,17 @@ int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd) EXPORT_SYMBOL(w1_ds2781_eeprom_cmd); static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); + return w1_ds2781_io(dev, buf, off, count, 0); } -static BIN_ATTR_RO(w1_slave, DS2781_DATA_SIZE); +static const BIN_ATTR_RO(w1_slave, DS2781_DATA_SIZE); -static struct bin_attribute *w1_ds2781_bin_attrs[] = { +static const struct bin_attribute *const w1_ds2781_bin_attrs[] = { &bin_attr_w1_slave, NULL, }; diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c index 6b5d12ba1b65..9c86b7985d0b 100644 --- a/drivers/w1/slaves/w1_ds2805.c +++ b/drivers/w1/slaves/w1_ds2805.c @@ -92,7 +92,7 @@ static int w1_f0d_readblock(struct w1_slave *sl, int off, int count, char *buf) } static ssize_t w1_f0d_read_bin(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -200,7 +200,7 @@ retry: } static ssize_t w1_f0d_write_bin(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -261,10 +261,10 @@ out_up: return count; } -static struct bin_attribute w1_f0d_bin_attr = { +static const struct bin_attribute w1_f0d_bin_attr = { .attr = { .name = "eeprom", - .mode = S_IRUGO | S_IWUSR, + .mode = 0644, }, .size = W1_F0D_EEPROM_SIZE, .read = w1_f0d_read_bin, diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c index 6cef6e2edb89..c577b5973032 100644 --- a/drivers/w1/slaves/w1_ds28e04.c +++ b/drivers/w1/slaves/w1_ds28e04.c @@ -53,7 +53,7 @@ struct w1_f1C_data { u32 validcrc; }; -/** +/* * Check the file size bounds and adjusts count as needed. * This would not be needed if the file size didn't reset to 0 after a write. */ @@ -112,7 +112,7 @@ static int w1_f1C_read(struct w1_slave *sl, int addr, int len, char *data) } static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -146,16 +146,17 @@ out_up: } /** - * Writes to the scratchpad and reads it back for verification. + * w1_f1C_write() - Writes to the scratchpad and reads it back for verification. + * @sl: The slave structure + * @addr: Address for the write + * @len: length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) + * @data: The data to write + * * Then copies the scratchpad to EEPROM. * The data must be on one page. * The master must be locked. * - * @param sl The slave structure - * @param addr Address for the write - * @param len length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) - * @param data The data to write - * @return 0=Success -1=failure + * Return: 0=Success, -1=failure */ static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data) { @@ -197,8 +198,10 @@ static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data) wrbuf[3] = es; for (i = 0; i < sizeof(wrbuf); ++i) { - /* issue 10ms strong pullup (or delay) on the last byte - for writing the data from the scratchpad to EEPROM */ + /* + * issue 10ms strong pullup (or delay) on the last byte + * for writing the data from the scratchpad to EEPROM + */ if (w1_strong_pullup && i == sizeof(wrbuf)-1) w1_next_pullup(sl->master, tm); @@ -220,7 +223,7 @@ static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data) } static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { @@ -273,10 +276,10 @@ out_up: return count; } -static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE); +static const BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE); static ssize_t pio_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { @@ -295,8 +298,8 @@ static ssize_t pio_read(struct file *filp, struct kobject *kobj, } static ssize_t pio_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, - size_t count) + const struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -334,7 +337,7 @@ static ssize_t pio_write(struct file *filp, struct kobject *kobj, return count; } -static BIN_ATTR_RW(pio, 1); +static const BIN_ATTR_RW(pio, 1); static ssize_t crccheck_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -360,7 +363,7 @@ static struct attribute *w1_f1C_attrs[] = { NULL, }; -static struct bin_attribute *w1_f1C_bin_attrs[] = { +static const struct bin_attribute *const w1_f1C_bin_attrs[] = { &bin_attr_eeprom, &bin_attr_pio, NULL, diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c index aed10b72fc99..e53bc41bde3c 100644 --- a/drivers/w1/slaves/w1_ds28e17.c +++ b/drivers/w1/slaves/w1_ds28e17.c @@ -31,12 +31,12 @@ MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E17)); /* Default I2C speed to be set when a DS28E17 is detected. */ static int i2c_speed = 100; -module_param_named(speed, i2c_speed, int, (S_IRUSR | S_IWUSR)); +module_param_named(speed, i2c_speed, int, 0600); MODULE_PARM_DESC(speed, "Default I2C speed to be set when a DS28E17 is detected"); /* Default I2C stretch value to be set when a DS28E17 is detected. */ static char i2c_stretch = 1; -module_param_named(stretch, i2c_stretch, byte, (S_IRUSR | S_IWUSR)); +module_param_named(stretch, i2c_stretch, byte, 0600); MODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected"); /* DS28E17 device command codes. */ @@ -59,7 +59,7 @@ MODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is /* * Maximum number of I2C bytes to transfer within one CRC16 protected onewire * command. - * */ + */ #define W1_F19_WRITE_DATA_LIMIT 255 /* Maximum number of I2C bytes to read with one onewire command. */ @@ -583,7 +583,7 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, return result; /* Return current speed value. */ - return sprintf(buf, "%d\n", result); + return sysfs_emit(buf, "%d\n", result); } static ssize_t speed_store(struct device *dev, struct device_attribute *attr, @@ -633,7 +633,7 @@ static ssize_t stretch_show(struct device *dev, struct device_attribute *attr, struct w1_f19_data *data = sl->family_data; /* Return current stretch value. */ - return sprintf(buf, "%d\n", data->stretch); + return sysfs_emit(buf, "%d\n", data->stretch); } static ssize_t stretch_store(struct device *dev, struct device_attribute *attr, @@ -719,8 +719,8 @@ static int w1_f19_add_slave(struct w1_slave *sl) data->adapter.owner = THIS_MODULE; data->adapter.algo = &w1_f19_i2c_algorithm; data->adapter.algo_data = sl; - strcpy(data->adapter.name, "w1-"); - strcat(data->adapter.name, sl->name); + scnprintf(data->adapter.name, sizeof(data->adapter.name), "w1-%s", + sl->name); data->adapter.dev.parent = &sl->dev; data->adapter.quirks = &w1_f19_i2c_adapter_quirks; diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 067692626cf0..9ccedb3264fb 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -284,7 +284,7 @@ static int read_powermode(struct w1_slave *sl); * trigger_bulk_read() - function to trigger a bulk read on the bus * @dev_master: the device master of the bus * - * Send a SKIP ROM follow by a CONVERT T commmand on the bus. + * Send a SKIP ROM follow by a CONVERT T command on the bus. * It also set the status flag in each slave &struct w1_therm_family_data * to signal that a conversion is in progress. * @@ -444,18 +444,8 @@ static int w1_read(struct device *dev, enum hwmon_sensor_types type, } } -static const u32 w1_temp_config[] = { - HWMON_T_INPUT, - 0 -}; - -static const struct hwmon_channel_info w1_temp = { - .type = hwmon_temp, - .config = w1_temp_config, -}; - -static const struct hwmon_channel_info *w1_info[] = { - &w1_temp, +static const struct hwmon_channel_info * const w1_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), NULL }; @@ -1159,29 +1149,26 @@ static int convert_t(struct w1_slave *sl, struct therm_info *info) w1_write_8(dev_master, W1_CONVERT_TEMP); - if (strong_pullup) { /*some device need pullup */ + if (SLAVE_FEATURES(sl) & W1_THERM_POLL_COMPLETION) { + ret = w1_poll_completion(dev_master, W1_POLL_CONVERT_TEMP); + if (ret) { + dev_dbg(&sl->dev, "%s: Timeout\n", __func__); + goto mt_unlock; + } + mutex_unlock(&dev_master->bus_mutex); + } else if (!strong_pullup) { /*no device need pullup */ sleep_rem = msleep_interruptible(t_conv); if (sleep_rem != 0) { ret = -EINTR; goto mt_unlock; } mutex_unlock(&dev_master->bus_mutex); - } else { /*no device need pullup */ - if (SLAVE_FEATURES(sl) & W1_THERM_POLL_COMPLETION) { - ret = w1_poll_completion(dev_master, W1_POLL_CONVERT_TEMP); - if (ret) { - dev_dbg(&sl->dev, "%s: Timeout\n", __func__); - goto mt_unlock; - } - mutex_unlock(&dev_master->bus_mutex); - } else { - /* Fixed delay */ - mutex_unlock(&dev_master->bus_mutex); - sleep_rem = msleep_interruptible(t_conv); - if (sleep_rem != 0) { - ret = -EINTR; - goto dec_refcnt; - } + } else { /*some device need pullup */ + mutex_unlock(&dev_master->bus_mutex); + sleep_rem = msleep_interruptible(t_conv); + if (sleep_rem != 0) { + ret = -EINTR; + goto dec_refcnt; } } ret = read_scratchpad(sl, info); @@ -1515,7 +1502,7 @@ static int trigger_bulk_read(struct w1_master *dev_master) if (bulk_read_support(sl)) { int t_cur = conversion_time(sl); - t_conv = t_cur > t_conv ? t_cur : t_conv; + t_conv = max(t_cur, t_conv); strong_pullup = strong_pullup || (w1_strong_pullup == 2 || (!SLAVE_POWERMODE(sl) && diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 4a2ddf730a3a..002d2639aa12 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -32,7 +32,7 @@ static int w1_timeout = 10; module_param_named(timeout, w1_timeout, int, 0); MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches"); -static int w1_timeout_us = 0; +static int w1_timeout_us; module_param_named(timeout_us, w1_timeout_us, int, 0); MODULE_PARM_DESC(timeout_us, "time in microseconds between automatic slave searches"); @@ -58,11 +58,6 @@ MODULE_PARM_DESC(slave_ttl, DEFINE_MUTEX(w1_mlock); LIST_HEAD(w1_masters); -static int w1_master_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - static int w1_master_probe(struct device *dev) { return -ENODEV; @@ -91,7 +86,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, char { struct w1_slave *sl = dev_to_w1_slave(dev); - return sprintf(buf, "%s\n", sl->name); + return sysfs_emit(buf, "%s\n", sl->name); } static DEVICE_ATTR_RO(name); @@ -116,7 +111,7 @@ ATTRIBUTE_GROUPS(w1_slave); /* Default family */ static ssize_t rw_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -135,8 +130,8 @@ out_up: } static ssize_t rw_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, - size_t count) + const struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); @@ -146,9 +141,9 @@ static ssize_t rw_read(struct file *filp, struct kobject *kobj, return count; } -static BIN_ATTR_RW(rw, PAGE_SIZE); +static const BIN_ATTR_RW(rw, PAGE_SIZE); -static struct bin_attribute *w1_slave_bin_attrs[] = { +static const struct bin_attribute *const w1_slave_bin_attrs[] = { &bin_attr_rw, NULL, }; @@ -170,11 +165,10 @@ static struct w1_family w1_default_family = { .fops = &w1_default_fops, }; -static int w1_uevent(struct device *dev, struct kobj_uevent_env *env); +static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env); -static struct bus_type w1_bus_type = { +static const struct bus_type w1_bus_type = { .name = "w1", - .match = w1_master_match, .uevent = w1_uevent, }; @@ -213,7 +207,7 @@ static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_a ssize_t count; mutex_lock(&md->mutex); - count = sprintf(buf, "%s\n", md->name); + count = sysfs_emit(buf, "%s\n", md->name); mutex_unlock(&md->mutex); return count; @@ -249,7 +243,7 @@ static ssize_t w1_master_attribute_show_search(struct device *dev, ssize_t count; mutex_lock(&md->mutex); - count = sprintf(buf, "%d\n", md->search_count); + count = sysfs_emit(buf, "%d\n", md->search_count); mutex_unlock(&md->mutex); return count; @@ -282,7 +276,7 @@ static ssize_t w1_master_attribute_show_pullup(struct device *dev, ssize_t count; mutex_lock(&md->mutex); - count = sprintf(buf, "%d\n", md->enable_pullup); + count = sysfs_emit(buf, "%d\n", md->enable_pullup); mutex_unlock(&md->mutex); return count; @@ -294,24 +288,20 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic ssize_t count; mutex_lock(&md->mutex); - count = sprintf(buf, "0x%p\n", md->bus_master); + count = sysfs_emit(buf, "0x%p\n", md->bus_master); mutex_unlock(&md->mutex); return count; } static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - ssize_t count; - count = sprintf(buf, "%d\n", w1_timeout); - return count; + return sysfs_emit(buf, "%d\n", w1_timeout); } 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; + return sysfs_emit(buf, "%d\n", w1_timeout_us); } static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev, @@ -338,7 +328,7 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru ssize_t count; mutex_lock(&md->mutex); - count = sprintf(buf, "%d\n", md->max_slave_count); + count = sysfs_emit(buf, "%d\n", md->max_slave_count); mutex_unlock(&md->mutex); return count; } @@ -349,7 +339,7 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi ssize_t count; mutex_lock(&md->mutex); - count = sprintf(buf, "%lu\n", md->attempts); + count = sysfs_emit(buf, "%lu\n", md->attempts); mutex_unlock(&md->mutex); return count; } @@ -360,7 +350,7 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d ssize_t count; mutex_lock(&md->mutex); - count = sprintf(buf, "%d\n", md->slave_count); + count = sysfs_emit(buf, "%d\n", md->slave_count); mutex_unlock(&md->mutex); return count; } @@ -501,7 +491,7 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev, struct w1_master *md = dev_to_w1_master(dev); struct w1_reg_num rn; struct w1_slave *sl; - ssize_t result = count; + ssize_t result; if (w1_atoreg_num(dev, buf, count, &rn)) return -EINVAL; @@ -514,7 +504,7 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev, if (result == 0) result = count; } else { - dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family, + dev_info(dev, "Device %02x-%012llx doesn't exist\n", rn.family, (unsigned long long)rn.id); result = -EINVAL; } @@ -577,11 +567,11 @@ void w1_destroy_master_attributes(struct w1_master *master) sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); } -static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) +static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env) { - struct w1_master *md = NULL; - struct w1_slave *sl = NULL; - char *event_owner, *name; + const struct w1_master *md = NULL; + const struct w1_slave *sl = NULL; + const char *event_owner, *name; int err = 0; if (dev->driver == &w1_master_driver) { @@ -702,6 +692,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) dev_err(&sl->dev, "Device registration [%s] failed. err=%d\n", dev_name(&sl->dev), err); + of_node_put(sl->dev.of_node); put_device(&sl->dev); return err; } @@ -830,49 +821,47 @@ int w1_slave_detach(struct w1_slave *sl) struct w1_master *w1_search_master_id(u32 id) { - struct w1_master *dev; - int found = 0; + struct w1_master *dev = NULL, *iter; mutex_lock(&w1_mlock); - list_for_each_entry(dev, &w1_masters, w1_master_entry) { - if (dev->id == id) { - found = 1; - atomic_inc(&dev->refcnt); + list_for_each_entry(iter, &w1_masters, w1_master_entry) { + if (iter->id == id) { + dev = iter; + atomic_inc(&iter->refcnt); break; } } mutex_unlock(&w1_mlock); - return (found)?dev:NULL; + return dev; } struct w1_slave *w1_search_slave(struct w1_reg_num *id) { struct w1_master *dev; - struct w1_slave *sl = NULL; - int found = 0; + struct w1_slave *sl = NULL, *iter; mutex_lock(&w1_mlock); list_for_each_entry(dev, &w1_masters, w1_master_entry) { mutex_lock(&dev->list_mutex); - list_for_each_entry(sl, &dev->slist, w1_slave_entry) { - if (sl->reg_num.family == id->family && - sl->reg_num.id == id->id && - sl->reg_num.crc == id->crc) { - found = 1; + list_for_each_entry(iter, &dev->slist, w1_slave_entry) { + if (iter->reg_num.family == id->family && + iter->reg_num.id == id->id && + iter->reg_num.crc == id->crc) { + sl = iter; atomic_inc(&dev->refcnt); - atomic_inc(&sl->refcnt); + atomic_inc(&iter->refcnt); break; } } mutex_unlock(&dev->list_mutex); - if (found) + if (sl) break; } mutex_unlock(&w1_mlock); - return (found)?sl:NULL; + return sl; } void w1_reconnect_slaves(struct w1_family *f, int attach) @@ -1263,10 +1252,10 @@ err_out_exit_init: static void __exit w1_fini(void) { - struct w1_master *dev; + struct w1_master *dev, *n; /* Set netlink removal messages and some cleanup */ - list_for_each_entry(dev, &w1_masters, w1_master_entry) + list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) __w1_remove_master_device(dev); w1_fini_netlink(); diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 3a71c5eb2f83..19a0ea28e9f3 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c @@ -32,12 +32,8 @@ static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl, * We are in process context(kernel thread), so can sleep. */ dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL); - if (!dev) { - pr_err("Failed to allocate %zd bytes for new w1 device.\n", - sizeof(struct w1_master)); + if (!dev) return NULL; - } - dev->bus_master = (struct w1_bus_master *)(dev + 1); diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index db110cc442b1..e6b59d921076 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -65,7 +65,8 @@ static void w1_unref_block(struct w1_cb_block *block) u16 len = w1_reply_len(block); if (len) { cn_netlink_send_mult(block->first_cn, len, - block->portid, 0, GFP_KERNEL); + block->portid, 0, + GFP_KERNEL, NULL, NULL); } kfree(block); } @@ -83,7 +84,8 @@ static void w1_reply_make_space(struct w1_cb_block *block, u16 space) { u16 len = w1_reply_len(block); if (len + space >= block->maxlen) { - cn_netlink_send_mult(block->first_cn, len, block->portid, 0, GFP_KERNEL); + cn_netlink_send_mult(block->first_cn, len, block->portid, + 0, GFP_KERNEL, NULL, NULL); block->first_cn->len = 0; block->cn = NULL; block->msg = NULL; @@ -192,16 +194,16 @@ static void w1_netlink_queue_status(struct w1_cb_block *block, static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg, int portid, int error) { - struct { - struct cn_msg cn; - struct w1_netlink_msg msg; - } packet; - memcpy(&packet.cn, cn, sizeof(packet.cn)); - memcpy(&packet.msg, msg, sizeof(packet.msg)); - packet.cn.len = sizeof(packet.msg); - packet.msg.len = 0; - packet.msg.status = (u8)-error; - cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL); + DEFINE_RAW_FLEX(struct cn_msg, packet, data, + sizeof(struct w1_netlink_msg)); + struct w1_netlink_msg *pkt_msg = (struct w1_netlink_msg *)packet->data; + + *packet = *cn; + *pkt_msg = *msg; + packet->len = sizeof(*pkt_msg); + pkt_msg->len = 0; + pkt_msg->status = (u8)-error; + cn_netlink_send(packet, portid, 0, GFP_KERNEL); } /** @@ -213,22 +215,20 @@ static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg, */ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) { - struct { - struct cn_msg cn; - struct w1_netlink_msg msg; - } packet; - memset(&packet, 0, sizeof(packet)); + DEFINE_RAW_FLEX(struct cn_msg, packet, data, + sizeof(struct w1_netlink_msg)); + struct w1_netlink_msg *pkt_msg = (struct w1_netlink_msg *)packet->data; - packet.cn.id.idx = CN_W1_IDX; - packet.cn.id.val = CN_W1_VAL; + packet->id.idx = CN_W1_IDX; + packet->id.val = CN_W1_VAL; - packet.cn.seq = dev->seq++; - packet.cn.len = sizeof(*msg); + packet->seq = dev->seq++; + packet->len = sizeof(*msg); - memcpy(&packet.msg, msg, sizeof(*msg)); - packet.msg.len = 0; + *pkt_msg = *msg; + pkt_msg->len = 0; - cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL); + cn_netlink_send(packet, 0, 0, GFP_KERNEL); } static void w1_send_slave(struct w1_master *dev, u64 rn) |
