mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
Char/Misc patches for 4.15-rc1
Here is the big set of char/misc and other driver subsystem patches for 4.15-rc1. There are small changes all over here, hyperv driver updates, pcmcia driver updates, w1 driver updats, vme driver updates, nvmem driver updates, and lots of other little one-off driver updates as well. The shortlog has the full details. Note, there will be a merge conflict in drivers/misc/lkdtm_core.c when merging to your tree as one lkdtm patch came in through the perf tree as well as this one. The resolution is to take the const change that this tree provides. All of these have been in linux-next for quite a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWg2Lnw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymTUwCgwp46+I8yPlgDH8oe5TxyyJnpdHQAn1XW0i+a sBi6WS87In5v1QO1Rgfc =dH2a -----END PGP SIGNATURE----- Merge tag 'char-misc-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc updates from Greg KH: "Here is the big set of char/misc and other driver subsystem patches for 4.15-rc1. There are small changes all over here, hyperv driver updates, pcmcia driver updates, w1 driver updats, vme driver updates, nvmem driver updates, and lots of other little one-off driver updates as well. The shortlog has the full details. All of these have been in linux-next for quite a while with no reported issues" * tag 'char-misc-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (90 commits) VME: Return -EBUSY when DMA list in use w1: keep balance of mutex locks and refcnts MAINTAINERS: Update VME subsystem tree. nvmem: sunxi-sid: add support for A64/H5's SID controller nvmem: imx-ocotp: Update module description nvmem: imx-ocotp: Enable i.MX7D OTP write support nvmem: imx-ocotp: Add i.MX7D timing write clock setup support nvmem: imx-ocotp: Move i.MX6 write clock setup to dedicated function nvmem: imx-ocotp: Add support for banked OTP addressing nvmem: imx-ocotp: Pass parameters via a struct nvmem: imx-ocotp: Restrict OTP write to IMX6 processors nvmem: uniphier: add UniPhier eFuse driver dt-bindings: nvmem: add description for UniPhier eFuse nvmem: set nvmem->owner to nvmem->dev->driver->owner if unset nvmem: qfprom: fix different address space warnings of sparse nvmem: mtk-efuse: fix different address space warnings of sparse nvmem: mtk-efuse: use stack for nvmem_config instead of malloc'ing it nvmem: imx-iim: use stack for nvmem_config instead of malloc'ing it thunderbolt: tb: fix use after free in tb_activate_pcie_devices MAINTAINERS: Add git tree for Thunderbolt development ...
This commit is contained in:
commit
2bf16b7a73
5 changed files with 2770 additions and 517 deletions
|
|
@ -148,4 +148,19 @@ config W1_SLAVE_DS28E04
|
|||
|
||||
If you are unsure, say N.
|
||||
|
||||
config W1_SLAVE_DS28E17
|
||||
tristate "1-wire-to-I2C master bridge (DS28E17)"
|
||||
select CRC16
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to use the DS28E17 1-wire-to-I2C master bridge.
|
||||
For each DS28E17 detected, a new I2C adapter is created within the
|
||||
kernel. I2C devices on that bus can be configured to be used by the
|
||||
kernel and userspace tools as on any other "native" I2C bus.
|
||||
|
||||
This driver is also available as a module. If so, the module
|
||||
will be called w1_ds28e17.
|
||||
|
||||
If you are unsure, say N.
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
|
|||
obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS28E17) += w1_ds28e17.o
|
||||
|
|
|
|||
771
drivers/w1/slaves/w1_ds28e17.c
Normal file
771
drivers/w1/slaves/w1_ds28e17.c
Normal file
|
|
@ -0,0 +1,771 @@
|
|||
/*
|
||||
* w1_ds28e17.c - w1 family 19 (DS28E17) driver
|
||||
*
|
||||
* Copyright (c) 2016 Jan Kandziora <jjj@gmx.de>
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2. See the file COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <linux/crc16.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define CRC16_INIT 0
|
||||
|
||||
#include <linux/w1.h>
|
||||
|
||||
#define W1_FAMILY_DS28E17 0x19
|
||||
|
||||
/* Module setup. */
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Jan Kandziora <jjj@gmx.de>");
|
||||
MODULE_DESCRIPTION("w1 family 19 driver for DS28E17, 1-wire to I2C master bridge");
|
||||
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_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_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected");
|
||||
|
||||
/* DS28E17 device command codes. */
|
||||
#define W1_F19_WRITE_DATA_WITH_STOP 0x4B
|
||||
#define W1_F19_WRITE_DATA_NO_STOP 0x5A
|
||||
#define W1_F19_WRITE_DATA_ONLY 0x69
|
||||
#define W1_F19_WRITE_DATA_ONLY_WITH_STOP 0x78
|
||||
#define W1_F19_READ_DATA_WITH_STOP 0x87
|
||||
#define W1_F19_WRITE_READ_DATA_WITH_STOP 0x2D
|
||||
#define W1_F19_WRITE_CONFIGURATION 0xD2
|
||||
#define W1_F19_READ_CONFIGURATION 0xE1
|
||||
#define W1_F19_ENABLE_SLEEP_MODE 0x1E
|
||||
#define W1_F19_READ_DEVICE_REVISION 0xC4
|
||||
|
||||
/* DS28E17 status bits */
|
||||
#define W1_F19_STATUS_CRC 0x01
|
||||
#define W1_F19_STATUS_ADDRESS 0x02
|
||||
#define W1_F19_STATUS_START 0x08
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
#define W1_F19_READ_DATA_LIMIT 255
|
||||
|
||||
/* Constants for calculating the busy sleep. */
|
||||
#define W1_F19_BUSY_TIMEBASES { 90, 23, 10 }
|
||||
#define W1_F19_BUSY_GRATUITY 1000
|
||||
|
||||
/* Number of checks for the busy flag before timeout. */
|
||||
#define W1_F19_BUSY_CHECKS 1000
|
||||
|
||||
|
||||
/* Slave specific data. */
|
||||
struct w1_f19_data {
|
||||
u8 speed;
|
||||
u8 stretch;
|
||||
struct i2c_adapter adapter;
|
||||
};
|
||||
|
||||
|
||||
/* Wait a while until the busy flag clears. */
|
||||
static int w1_f19_i2c_busy_wait(struct w1_slave *sl, size_t count)
|
||||
{
|
||||
const unsigned long timebases[3] = W1_F19_BUSY_TIMEBASES;
|
||||
struct w1_f19_data *data = sl->family_data;
|
||||
unsigned int checks;
|
||||
|
||||
/* Check the busy flag first in any case.*/
|
||||
if (w1_touch_bit(sl->master, 1) == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Do a generously long sleep in the beginning,
|
||||
* as we have to wait at least this time for all
|
||||
* the I2C bytes at the given speed to be transferred.
|
||||
*/
|
||||
usleep_range(timebases[data->speed] * (data->stretch) * count,
|
||||
timebases[data->speed] * (data->stretch) * count
|
||||
+ W1_F19_BUSY_GRATUITY);
|
||||
|
||||
/* Now continusly check the busy flag sent by the DS28E17. */
|
||||
checks = W1_F19_BUSY_CHECKS;
|
||||
while ((checks--) > 0) {
|
||||
/* Return success if the busy flag is cleared. */
|
||||
if (w1_touch_bit(sl->master, 1) == 0)
|
||||
return 0;
|
||||
|
||||
/* Wait one non-streched byte timeslot. */
|
||||
udelay(timebases[data->speed]);
|
||||
}
|
||||
|
||||
/* Timeout. */
|
||||
dev_warn(&sl->dev, "busy timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
||||
/* Utility function: result. */
|
||||
static size_t w1_f19_error(struct w1_slave *sl, u8 w1_buf[])
|
||||
{
|
||||
/* Warnings. */
|
||||
if (w1_buf[0] & W1_F19_STATUS_CRC)
|
||||
dev_warn(&sl->dev, "crc16 mismatch\n");
|
||||
if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
|
||||
dev_warn(&sl->dev, "i2c device not responding\n");
|
||||
if ((w1_buf[0] & (W1_F19_STATUS_CRC | W1_F19_STATUS_ADDRESS)) == 0
|
||||
&& w1_buf[1] != 0) {
|
||||
dev_warn(&sl->dev, "i2c short write, %d bytes not acknowledged\n",
|
||||
w1_buf[1]);
|
||||
}
|
||||
|
||||
/* Check error conditions. */
|
||||
if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
|
||||
return -ENXIO;
|
||||
if (w1_buf[0] & W1_F19_STATUS_START)
|
||||
return -EAGAIN;
|
||||
if (w1_buf[0] != 0 || w1_buf[1] != 0)
|
||||
return -EIO;
|
||||
|
||||
/* All ok. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Utility function: write data to I2C slave, single chunk. */
|
||||
static int __w1_f19_i2c_write(struct w1_slave *sl,
|
||||
const u8 *command, size_t command_count,
|
||||
const u8 *buffer, size_t count)
|
||||
{
|
||||
u16 crc;
|
||||
int error;
|
||||
u8 w1_buf[2];
|
||||
|
||||
/* Send command and I2C data to DS28E17. */
|
||||
crc = crc16(CRC16_INIT, command, command_count);
|
||||
w1_write_block(sl->master, command, command_count);
|
||||
|
||||
w1_buf[0] = count;
|
||||
crc = crc16(crc, w1_buf, 1);
|
||||
w1_write_8(sl->master, w1_buf[0]);
|
||||
|
||||
crc = crc16(crc, buffer, count);
|
||||
w1_write_block(sl->master, buffer, count);
|
||||
|
||||
w1_buf[0] = ~(crc & 0xFF);
|
||||
w1_buf[1] = ~((crc >> 8) & 0xFF);
|
||||
w1_write_block(sl->master, w1_buf, 2);
|
||||
|
||||
/* Wait until busy flag clears (or timeout). */
|
||||
if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Read status from DS28E17. */
|
||||
w1_read_block(sl->master, w1_buf, 2);
|
||||
|
||||
/* Check error conditions. */
|
||||
error = w1_f19_error(sl, w1_buf);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
/* Return number of bytes written. */
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* Write data to I2C slave. */
|
||||
static int w1_f19_i2c_write(struct w1_slave *sl, u16 i2c_address,
|
||||
const u8 *buffer, size_t count, bool stop)
|
||||
{
|
||||
int result;
|
||||
int remaining = count;
|
||||
const u8 *p;
|
||||
u8 command[2];
|
||||
|
||||
/* Check input. */
|
||||
if (count == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Check whether we need multiple commands. */
|
||||
if (count <= W1_F19_WRITE_DATA_LIMIT) {
|
||||
/*
|
||||
* Small data amount. Data can be sent with
|
||||
* a single onewire command.
|
||||
*/
|
||||
|
||||
/* Send all data to DS28E17. */
|
||||
command[0] = (stop ? W1_F19_WRITE_DATA_WITH_STOP
|
||||
: W1_F19_WRITE_DATA_NO_STOP);
|
||||
command[1] = i2c_address << 1;
|
||||
result = __w1_f19_i2c_write(sl, command, 2, buffer, count);
|
||||
} else {
|
||||
/* Large data amount. Data has to be sent in multiple chunks. */
|
||||
|
||||
/* Send first chunk to DS28E17. */
|
||||
p = buffer;
|
||||
command[0] = W1_F19_WRITE_DATA_NO_STOP;
|
||||
command[1] = i2c_address << 1;
|
||||
result = __w1_f19_i2c_write(sl, command, 2, p,
|
||||
W1_F19_WRITE_DATA_LIMIT);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/* Resume to same DS28E17. */
|
||||
if (w1_reset_resume_command(sl->master))
|
||||
return -EIO;
|
||||
|
||||
/* Next data chunk. */
|
||||
p += W1_F19_WRITE_DATA_LIMIT;
|
||||
remaining -= W1_F19_WRITE_DATA_LIMIT;
|
||||
|
||||
while (remaining > W1_F19_WRITE_DATA_LIMIT) {
|
||||
/* Send intermediate chunk to DS28E17. */
|
||||
command[0] = W1_F19_WRITE_DATA_ONLY;
|
||||
result = __w1_f19_i2c_write(sl, command, 1, p,
|
||||
W1_F19_WRITE_DATA_LIMIT);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/* Resume to same DS28E17. */
|
||||
if (w1_reset_resume_command(sl->master))
|
||||
return -EIO;
|
||||
|
||||
/* Next data chunk. */
|
||||
p += W1_F19_WRITE_DATA_LIMIT;
|
||||
remaining -= W1_F19_WRITE_DATA_LIMIT;
|
||||
}
|
||||
|
||||
/* Send final chunk to DS28E17. */
|
||||
command[0] = (stop ? W1_F19_WRITE_DATA_ONLY_WITH_STOP
|
||||
: W1_F19_WRITE_DATA_ONLY);
|
||||
result = __w1_f19_i2c_write(sl, command, 1, p, remaining);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Read data from I2C slave. */
|
||||
static int w1_f19_i2c_read(struct w1_slave *sl, u16 i2c_address,
|
||||
u8 *buffer, size_t count)
|
||||
{
|
||||
u16 crc;
|
||||
int error;
|
||||
u8 w1_buf[5];
|
||||
|
||||
/* Check input. */
|
||||
if (count == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Send command to DS28E17. */
|
||||
w1_buf[0] = W1_F19_READ_DATA_WITH_STOP;
|
||||
w1_buf[1] = i2c_address << 1 | 0x01;
|
||||
w1_buf[2] = count;
|
||||
crc = crc16(CRC16_INIT, w1_buf, 3);
|
||||
w1_buf[3] = ~(crc & 0xFF);
|
||||
w1_buf[4] = ~((crc >> 8) & 0xFF);
|
||||
w1_write_block(sl->master, w1_buf, 5);
|
||||
|
||||
/* Wait until busy flag clears (or timeout). */
|
||||
if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Read status from DS28E17. */
|
||||
w1_buf[0] = w1_read_8(sl->master);
|
||||
w1_buf[1] = 0;
|
||||
|
||||
/* Check error conditions. */
|
||||
error = w1_f19_error(sl, w1_buf);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
/* Read received I2C data from DS28E17. */
|
||||
return w1_read_block(sl->master, buffer, count);
|
||||
}
|
||||
|
||||
|
||||
/* Write to, then read data from I2C slave. */
|
||||
static int w1_f19_i2c_write_read(struct w1_slave *sl, u16 i2c_address,
|
||||
const u8 *wbuffer, size_t wcount, u8 *rbuffer, size_t rcount)
|
||||
{
|
||||
u16 crc;
|
||||
int error;
|
||||
u8 w1_buf[3];
|
||||
|
||||
/* Check input. */
|
||||
if (wcount == 0 || rcount == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Send command and I2C data to DS28E17. */
|
||||
w1_buf[0] = W1_F19_WRITE_READ_DATA_WITH_STOP;
|
||||
w1_buf[1] = i2c_address << 1;
|
||||
w1_buf[2] = wcount;
|
||||
crc = crc16(CRC16_INIT, w1_buf, 3);
|
||||
w1_write_block(sl->master, w1_buf, 3);
|
||||
|
||||
crc = crc16(crc, wbuffer, wcount);
|
||||
w1_write_block(sl->master, wbuffer, wcount);
|
||||
|
||||
w1_buf[0] = rcount;
|
||||
crc = crc16(crc, w1_buf, 1);
|
||||
w1_buf[1] = ~(crc & 0xFF);
|
||||
w1_buf[2] = ~((crc >> 8) & 0xFF);
|
||||
w1_write_block(sl->master, w1_buf, 3);
|
||||
|
||||
/* Wait until busy flag clears (or timeout). */
|
||||
if (w1_f19_i2c_busy_wait(sl, wcount + rcount + 2) < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Read status from DS28E17. */
|
||||
w1_read_block(sl->master, w1_buf, 2);
|
||||
|
||||
/* Check error conditions. */
|
||||
error = w1_f19_error(sl, w1_buf);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
/* Read received I2C data from DS28E17. */
|
||||
return w1_read_block(sl->master, rbuffer, rcount);
|
||||
}
|
||||
|
||||
|
||||
/* Do an I2C master transfer. */
|
||||
static int w1_f19_i2c_master_transfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct w1_slave *sl = (struct w1_slave *) adapter->algo_data;
|
||||
int i = 0;
|
||||
int result = 0;
|
||||
|
||||
/* Start onewire transaction. */
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
/* Select DS28E17. */
|
||||
if (w1_reset_select_slave(sl)) {
|
||||
i = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Loop while there are still messages to transfer. */
|
||||
while (i < num) {
|
||||
/*
|
||||
* Check for special case: Small write followed
|
||||
* by read to same I2C device.
|
||||
*/
|
||||
if (i < (num-1)
|
||||
&& msgs[i].addr == msgs[i+1].addr
|
||||
&& !(msgs[i].flags & I2C_M_RD)
|
||||
&& (msgs[i+1].flags & I2C_M_RD)
|
||||
&& (msgs[i].len <= W1_F19_WRITE_DATA_LIMIT)) {
|
||||
/*
|
||||
* The DS28E17 has a combined transfer
|
||||
* for small write+read.
|
||||
*/
|
||||
result = w1_f19_i2c_write_read(sl, msgs[i].addr,
|
||||
msgs[i].buf, msgs[i].len,
|
||||
msgs[i+1].buf, msgs[i+1].len);
|
||||
if (result < 0) {
|
||||
i = result;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we should interpret the read data
|
||||
* as a length byte. The DS28E17 unfortunately
|
||||
* has no read without stop, so we can just do
|
||||
* another simple read in that case.
|
||||
*/
|
||||
if (msgs[i+1].flags & I2C_M_RECV_LEN) {
|
||||
result = w1_f19_i2c_read(sl, msgs[i+1].addr,
|
||||
&(msgs[i+1].buf[1]), msgs[i+1].buf[0]);
|
||||
if (result < 0) {
|
||||
i = result;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Eat up read message, too. */
|
||||
i++;
|
||||
} else if (msgs[i].flags & I2C_M_RD) {
|
||||
/* Read transfer. */
|
||||
result = w1_f19_i2c_read(sl, msgs[i].addr,
|
||||
msgs[i].buf, msgs[i].len);
|
||||
if (result < 0) {
|
||||
i = result;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we should interpret the read data
|
||||
* as a length byte. The DS28E17 unfortunately
|
||||
* has no read without stop, so we can just do
|
||||
* another simple read in that case.
|
||||
*/
|
||||
if (msgs[i].flags & I2C_M_RECV_LEN) {
|
||||
result = w1_f19_i2c_read(sl,
|
||||
msgs[i].addr,
|
||||
&(msgs[i].buf[1]),
|
||||
msgs[i].buf[0]);
|
||||
if (result < 0) {
|
||||
i = result;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Write transfer.
|
||||
* Stop condition only for last
|
||||
* transfer.
|
||||
*/
|
||||
result = w1_f19_i2c_write(sl,
|
||||
msgs[i].addr,
|
||||
msgs[i].buf,
|
||||
msgs[i].len,
|
||||
i == (num-1));
|
||||
if (result < 0) {
|
||||
i = result;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next message. */
|
||||
i++;
|
||||
|
||||
/* Are there still messages to send/receive? */
|
||||
if (i < num) {
|
||||
/* Yes. Resume to same DS28E17. */
|
||||
if (w1_reset_resume_command(sl->master)) {
|
||||
i = -EIO;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
/* End onewire transaction. */
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
/* Return number of messages processed or error. */
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* Get I2C adapter functionality. */
|
||||
static u32 w1_f19_i2c_functionality(struct i2c_adapter *adapter)
|
||||
{
|
||||
/*
|
||||
* Plain I2C functions only.
|
||||
* SMBus is emulated by the kernel's I2C layer.
|
||||
* No "I2C_FUNC_SMBUS_QUICK"
|
||||
* No "I2C_FUNC_SMBUS_READ_BLOCK_DATA"
|
||||
* No "I2C_FUNC_SMBUS_BLOCK_PROC_CALL"
|
||||
*/
|
||||
return I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK |
|
||||
I2C_FUNC_SMBUS_PEC;
|
||||
}
|
||||
|
||||
|
||||
/* I2C adapter quirks. */
|
||||
static const struct i2c_adapter_quirks w1_f19_i2c_adapter_quirks = {
|
||||
.max_read_len = W1_F19_READ_DATA_LIMIT,
|
||||
};
|
||||
|
||||
/* I2C algorithm. */
|
||||
static const struct i2c_algorithm w1_f19_i2c_algorithm = {
|
||||
.master_xfer = w1_f19_i2c_master_transfer,
|
||||
.functionality = w1_f19_i2c_functionality,
|
||||
};
|
||||
|
||||
|
||||
/* Read I2C speed from DS28E17. */
|
||||
static int w1_f19_get_i2c_speed(struct w1_slave *sl)
|
||||
{
|
||||
struct w1_f19_data *data = sl->family_data;
|
||||
int result = -EIO;
|
||||
|
||||
/* Start onewire transaction. */
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
/* Select slave. */
|
||||
if (w1_reset_select_slave(sl))
|
||||
goto error;
|
||||
|
||||
/* Read slave configuration byte. */
|
||||
w1_write_8(sl->master, W1_F19_READ_CONFIGURATION);
|
||||
result = w1_read_8(sl->master);
|
||||
if (result < 0 || result > 2) {
|
||||
result = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Update speed in slave specific data. */
|
||||
data->speed = result;
|
||||
|
||||
error:
|
||||
/* End onewire transaction. */
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Set I2C speed on DS28E17. */
|
||||
static int __w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
|
||||
{
|
||||
struct w1_f19_data *data = sl->family_data;
|
||||
const int i2c_speeds[3] = { 100, 400, 900 };
|
||||
u8 w1_buf[2];
|
||||
|
||||
/* Select slave. */
|
||||
if (w1_reset_select_slave(sl))
|
||||
return -EIO;
|
||||
|
||||
w1_buf[0] = W1_F19_WRITE_CONFIGURATION;
|
||||
w1_buf[1] = speed;
|
||||
w1_write_block(sl->master, w1_buf, 2);
|
||||
|
||||
/* Update speed in slave specific data. */
|
||||
data->speed = speed;
|
||||
|
||||
dev_info(&sl->dev, "i2c speed set to %d kBaud\n", i2c_speeds[speed]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Start onewire transaction. */
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
|
||||
/* Set I2C speed on DS28E17. */
|
||||
result = __w1_f19_set_i2c_speed(sl, speed);
|
||||
|
||||
/* End onewire transaction. */
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Sysfs attributes. */
|
||||
|
||||
/* I2C speed attribute for a single chip. */
|
||||
static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct w1_slave *sl = dev_to_w1_slave(dev);
|
||||
int result;
|
||||
|
||||
/* Read current speed from slave. Updates data->speed. */
|
||||
result = w1_f19_get_i2c_speed(sl);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
/* Return current speed value. */
|
||||
return sprintf(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = dev_to_w1_slave(dev);
|
||||
int error;
|
||||
|
||||
/* Valid values are: "100", "400", "900" */
|
||||
if (count < 3 || count > 4 || !buf)
|
||||
return -EINVAL;
|
||||
if (count == 4 && buf[3] != '\n')
|
||||
return -EINVAL;
|
||||
if (buf[1] != '0' || buf[2] != '0')
|
||||
return -EINVAL;
|
||||
|
||||
/* Set speed on slave. */
|
||||
switch (buf[0]) {
|
||||
case '1':
|
||||
error = w1_f19_set_i2c_speed(sl, 0);
|
||||
break;
|
||||
case '4':
|
||||
error = w1_f19_set_i2c_speed(sl, 1);
|
||||
break;
|
||||
case '9':
|
||||
error = w1_f19_set_i2c_speed(sl, 2);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
/* Return bytes written. */
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(speed);
|
||||
|
||||
|
||||
/* Busy stretch attribute for a single chip. */
|
||||
static ssize_t stretch_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct w1_slave *sl = dev_to_w1_slave(dev);
|
||||
struct w1_f19_data *data = sl->family_data;
|
||||
|
||||
/* Return current stretch value. */
|
||||
return sprintf(buf, "%d\n", data->stretch);
|
||||
}
|
||||
|
||||
static ssize_t stretch_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct w1_slave *sl = dev_to_w1_slave(dev);
|
||||
struct w1_f19_data *data = sl->family_data;
|
||||
|
||||
/* Valid values are '1' to '9' */
|
||||
if (count < 1 || count > 2 || !buf)
|
||||
return -EINVAL;
|
||||
if (count == 2 && buf[1] != '\n')
|
||||
return -EINVAL;
|
||||
if (buf[0] < '1' || buf[0] > '9')
|
||||
return -EINVAL;
|
||||
|
||||
/* Set busy stretch value. */
|
||||
data->stretch = buf[0] & 0x0F;
|
||||
|
||||
/* Return bytes written. */
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(stretch);
|
||||
|
||||
|
||||
/* All attributes. */
|
||||
static struct attribute *w1_f19_attrs[] = {
|
||||
&dev_attr_speed.attr,
|
||||
&dev_attr_stretch.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group w1_f19_group = {
|
||||
.attrs = w1_f19_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *w1_f19_groups[] = {
|
||||
&w1_f19_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
/* Slave add and remove functions. */
|
||||
static int w1_f19_add_slave(struct w1_slave *sl)
|
||||
{
|
||||
struct w1_f19_data *data = NULL;
|
||||
|
||||
/* Allocate memory for slave specific data. */
|
||||
data = devm_kzalloc(&sl->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
sl->family_data = data;
|
||||
|
||||
/* Setup default I2C speed on slave. */
|
||||
switch (i2c_speed) {
|
||||
case 100:
|
||||
__w1_f19_set_i2c_speed(sl, 0);
|
||||
break;
|
||||
case 400:
|
||||
__w1_f19_set_i2c_speed(sl, 1);
|
||||
break;
|
||||
case 900:
|
||||
__w1_f19_set_i2c_speed(sl, 2);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* A i2c_speed module parameter of anything else
|
||||
* than 100, 400, 900 means not to touch the
|
||||
* speed of the DS28E17.
|
||||
* We assume 400kBaud, the power-on value.
|
||||
*/
|
||||
data->speed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup default busy stretch
|
||||
* configuration for the DS28E17.
|
||||
*/
|
||||
data->stretch = i2c_stretch;
|
||||
|
||||
/* Setup I2C adapter. */
|
||||
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);
|
||||
data->adapter.dev.parent = &sl->dev;
|
||||
data->adapter.quirks = &w1_f19_i2c_adapter_quirks;
|
||||
|
||||
return i2c_add_adapter(&data->adapter);
|
||||
}
|
||||
|
||||
static void w1_f19_remove_slave(struct w1_slave *sl)
|
||||
{
|
||||
struct w1_f19_data *family_data = sl->family_data;
|
||||
|
||||
/* Delete I2C adapter. */
|
||||
i2c_del_adapter(&family_data->adapter);
|
||||
|
||||
/* Free slave specific data. */
|
||||
devm_kfree(&sl->dev, family_data);
|
||||
sl->family_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Declarations within the w1 subsystem. */
|
||||
static struct w1_family_ops w1_f19_fops = {
|
||||
.add_slave = w1_f19_add_slave,
|
||||
.remove_slave = w1_f19_remove_slave,
|
||||
.groups = w1_f19_groups,
|
||||
};
|
||||
|
||||
static struct w1_family w1_family_19 = {
|
||||
.fid = W1_FAMILY_DS28E17,
|
||||
.fops = &w1_f19_fops,
|
||||
};
|
||||
|
||||
|
||||
/* Module init and remove functions. */
|
||||
static int __init w1_f19_init(void)
|
||||
{
|
||||
return w1_register_family(&w1_family_19);
|
||||
}
|
||||
|
||||
static void __exit w1_f19_fini(void)
|
||||
{
|
||||
w1_unregister_family(&w1_family_19);
|
||||
}
|
||||
|
||||
module_init(w1_f19_init);
|
||||
module_exit(w1_f19_fini);
|
||||
|
||||
|
|
@ -268,17 +268,18 @@ static inline int w1_therm_eeprom(struct device *device)
|
|||
int ret, max_trying = 10;
|
||||
u8 *family_data = sl->family_data;
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (ret != 0)
|
||||
goto post_unlock;
|
||||
|
||||
if (!sl->family_data) {
|
||||
ret = -ENODEV;
|
||||
goto pre_unlock;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* prevent the slave from going away in sleep */
|
||||
atomic_inc(THERM_REFCNT(family_data));
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (ret != 0)
|
||||
goto dec_refcnt;
|
||||
|
||||
memset(rom, 0, sizeof(rom));
|
||||
|
||||
while (max_trying--) {
|
||||
|
|
@ -306,17 +307,17 @@ static inline int w1_therm_eeprom(struct device *device)
|
|||
sleep_rem = msleep_interruptible(tm);
|
||||
if (sleep_rem != 0) {
|
||||
ret = -EINTR;
|
||||
goto post_unlock;
|
||||
goto dec_refcnt;
|
||||
}
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (ret != 0)
|
||||
goto post_unlock;
|
||||
goto dec_refcnt;
|
||||
} else if (!w1_strong_pullup) {
|
||||
sleep_rem = msleep_interruptible(tm);
|
||||
if (sleep_rem != 0) {
|
||||
ret = -EINTR;
|
||||
goto pre_unlock;
|
||||
goto mt_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,11 +325,11 @@ static inline int w1_therm_eeprom(struct device *device)
|
|||
}
|
||||
}
|
||||
|
||||
pre_unlock:
|
||||
mt_unlock:
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
|
||||
post_unlock:
|
||||
dec_refcnt:
|
||||
atomic_dec(THERM_REFCNT(family_data));
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -350,20 +351,22 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
|
|||
|
||||
if (val > 12 || val < 9) {
|
||||
pr_warn("Unsupported precision\n");
|
||||
return -1;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (ret != 0)
|
||||
goto post_unlock;
|
||||
|
||||
if (!sl->family_data) {
|
||||
ret = -ENODEV;
|
||||
goto pre_unlock;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* prevent the slave from going away in sleep */
|
||||
atomic_inc(THERM_REFCNT(family_data));
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (ret != 0)
|
||||
goto dec_refcnt;
|
||||
|
||||
memset(rom, 0, sizeof(rom));
|
||||
|
||||
/* translate precision to bitmask (see datasheet page 9) */
|
||||
|
|
@ -411,11 +414,10 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
|
|||
}
|
||||
}
|
||||
|
||||
pre_unlock:
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
|
||||
post_unlock:
|
||||
dec_refcnt:
|
||||
atomic_dec(THERM_REFCNT(family_data));
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -490,17 +492,18 @@ static ssize_t read_therm(struct device *device,
|
|||
int ret, max_trying = 10;
|
||||
u8 *family_data = sl->family_data;
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
|
||||
if (!family_data) {
|
||||
ret = -ENODEV;
|
||||
goto mt_unlock;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* prevent the slave from going away in sleep */
|
||||
atomic_inc(THERM_REFCNT(family_data));
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->bus_mutex);
|
||||
if (ret != 0)
|
||||
goto dec_refcnt;
|
||||
|
||||
memset(info->rom, 0, sizeof(info->rom));
|
||||
|
||||
while (max_trying--) {
|
||||
|
|
@ -542,7 +545,7 @@ static ssize_t read_therm(struct device *device,
|
|||
sleep_rem = msleep_interruptible(tm);
|
||||
if (sleep_rem != 0) {
|
||||
ret = -EINTR;
|
||||
goto dec_refcnt;
|
||||
goto mt_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -567,10 +570,10 @@ static ssize_t read_therm(struct device *device,
|
|||
break;
|
||||
}
|
||||
|
||||
dec_refcnt:
|
||||
atomic_dec(THERM_REFCNT(family_data));
|
||||
mt_unlock:
|
||||
mutex_unlock(&dev->bus_mutex);
|
||||
dec_refcnt:
|
||||
atomic_dec(THERM_REFCNT(family_data));
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static u8 w1_read_bit(struct w1_master *dev);
|
|||
* @dev: the master device
|
||||
* @bit: 0 - write a 0, 1 - write a 0 read the level
|
||||
*/
|
||||
static u8 w1_touch_bit(struct w1_master *dev, int bit)
|
||||
u8 w1_touch_bit(struct w1_master *dev, int bit)
|
||||
{
|
||||
if (dev->bus_master->touch_bit)
|
||||
return dev->bus_master->touch_bit(dev->bus_master->data, bit);
|
||||
|
|
@ -69,6 +69,7 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(w1_touch_bit);
|
||||
|
||||
/**
|
||||
* w1_write_bit() - Generates a write-0 or write-1 cycle.
|
||||
|
|
|
|||
Loading…
Reference in a new issue