162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	w1_ds28e17.c - w1 family 19 (DS28E17) driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2016 Jan Kandziora <jjj@gmx.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/crc16.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/i2c.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/moduleparam.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/types.h>
1762306a36Sopenharmony_ci#include <linux/uaccess.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define CRC16_INIT 0
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/w1.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define W1_FAMILY_DS28E17 0x19
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Module setup. */
2662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2762306a36Sopenharmony_ciMODULE_AUTHOR("Jan Kandziora <jjj@gmx.de>");
2862306a36Sopenharmony_ciMODULE_DESCRIPTION("w1 family 19 driver for DS28E17, 1-wire to I2C master bridge");
2962306a36Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E17));
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Default I2C speed to be set when a DS28E17 is detected. */
3362306a36Sopenharmony_cistatic int i2c_speed = 100;
3462306a36Sopenharmony_cimodule_param_named(speed, i2c_speed, int, 0600);
3562306a36Sopenharmony_ciMODULE_PARM_DESC(speed, "Default I2C speed to be set when a DS28E17 is detected");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* Default I2C stretch value to be set when a DS28E17 is detected. */
3862306a36Sopenharmony_cistatic char i2c_stretch = 1;
3962306a36Sopenharmony_cimodule_param_named(stretch, i2c_stretch, byte, 0600);
4062306a36Sopenharmony_ciMODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* DS28E17 device command codes. */
4362306a36Sopenharmony_ci#define W1_F19_WRITE_DATA_WITH_STOP      0x4B
4462306a36Sopenharmony_ci#define W1_F19_WRITE_DATA_NO_STOP        0x5A
4562306a36Sopenharmony_ci#define W1_F19_WRITE_DATA_ONLY           0x69
4662306a36Sopenharmony_ci#define W1_F19_WRITE_DATA_ONLY_WITH_STOP 0x78
4762306a36Sopenharmony_ci#define W1_F19_READ_DATA_WITH_STOP       0x87
4862306a36Sopenharmony_ci#define W1_F19_WRITE_READ_DATA_WITH_STOP 0x2D
4962306a36Sopenharmony_ci#define W1_F19_WRITE_CONFIGURATION       0xD2
5062306a36Sopenharmony_ci#define W1_F19_READ_CONFIGURATION        0xE1
5162306a36Sopenharmony_ci#define W1_F19_ENABLE_SLEEP_MODE         0x1E
5262306a36Sopenharmony_ci#define W1_F19_READ_DEVICE_REVISION      0xC4
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* DS28E17 status bits */
5562306a36Sopenharmony_ci#define W1_F19_STATUS_CRC     0x01
5662306a36Sopenharmony_ci#define W1_F19_STATUS_ADDRESS 0x02
5762306a36Sopenharmony_ci#define W1_F19_STATUS_START   0x08
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * Maximum number of I2C bytes to transfer within one CRC16 protected onewire
6162306a36Sopenharmony_ci * command.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_ci#define W1_F19_WRITE_DATA_LIMIT 255
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* Maximum number of I2C bytes to read with one onewire command. */
6662306a36Sopenharmony_ci#define W1_F19_READ_DATA_LIMIT 255
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* Constants for calculating the busy sleep. */
6962306a36Sopenharmony_ci#define W1_F19_BUSY_TIMEBASES { 90, 23, 10 }
7062306a36Sopenharmony_ci#define W1_F19_BUSY_GRATUITY  1000
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Number of checks for the busy flag before timeout. */
7362306a36Sopenharmony_ci#define W1_F19_BUSY_CHECKS 1000
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Slave specific data. */
7762306a36Sopenharmony_cistruct w1_f19_data {
7862306a36Sopenharmony_ci	u8 speed;
7962306a36Sopenharmony_ci	u8 stretch;
8062306a36Sopenharmony_ci	struct i2c_adapter adapter;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* Wait a while until the busy flag clears. */
8562306a36Sopenharmony_cistatic int w1_f19_i2c_busy_wait(struct w1_slave *sl, size_t count)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	const unsigned long timebases[3] = W1_F19_BUSY_TIMEBASES;
8862306a36Sopenharmony_ci	struct w1_f19_data *data = sl->family_data;
8962306a36Sopenharmony_ci	unsigned int checks;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* Check the busy flag first in any case.*/
9262306a36Sopenharmony_ci	if (w1_touch_bit(sl->master, 1) == 0)
9362306a36Sopenharmony_ci		return 0;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/*
9662306a36Sopenharmony_ci	 * Do a generously long sleep in the beginning,
9762306a36Sopenharmony_ci	 * as we have to wait at least this time for all
9862306a36Sopenharmony_ci	 * the I2C bytes at the given speed to be transferred.
9962306a36Sopenharmony_ci	 */
10062306a36Sopenharmony_ci	usleep_range(timebases[data->speed] * (data->stretch) * count,
10162306a36Sopenharmony_ci		timebases[data->speed] * (data->stretch) * count
10262306a36Sopenharmony_ci		+ W1_F19_BUSY_GRATUITY);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Now continusly check the busy flag sent by the DS28E17. */
10562306a36Sopenharmony_ci	checks = W1_F19_BUSY_CHECKS;
10662306a36Sopenharmony_ci	while ((checks--) > 0) {
10762306a36Sopenharmony_ci		/* Return success if the busy flag is cleared. */
10862306a36Sopenharmony_ci		if (w1_touch_bit(sl->master, 1) == 0)
10962306a36Sopenharmony_ci			return 0;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		/* Wait one non-streched byte timeslot. */
11262306a36Sopenharmony_ci		udelay(timebases[data->speed]);
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Timeout. */
11662306a36Sopenharmony_ci	dev_warn(&sl->dev, "busy timeout\n");
11762306a36Sopenharmony_ci	return -ETIMEDOUT;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/* Utility function: result. */
12262306a36Sopenharmony_cistatic size_t w1_f19_error(struct w1_slave *sl, u8 w1_buf[])
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	/* Warnings. */
12562306a36Sopenharmony_ci	if (w1_buf[0] & W1_F19_STATUS_CRC)
12662306a36Sopenharmony_ci		dev_warn(&sl->dev, "crc16 mismatch\n");
12762306a36Sopenharmony_ci	if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
12862306a36Sopenharmony_ci		dev_warn(&sl->dev, "i2c device not responding\n");
12962306a36Sopenharmony_ci	if ((w1_buf[0] & (W1_F19_STATUS_CRC | W1_F19_STATUS_ADDRESS)) == 0
13062306a36Sopenharmony_ci			&& w1_buf[1] != 0) {
13162306a36Sopenharmony_ci		dev_warn(&sl->dev, "i2c short write, %d bytes not acknowledged\n",
13262306a36Sopenharmony_ci			w1_buf[1]);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* Check error conditions. */
13662306a36Sopenharmony_ci	if (w1_buf[0] & W1_F19_STATUS_ADDRESS)
13762306a36Sopenharmony_ci		return -ENXIO;
13862306a36Sopenharmony_ci	if (w1_buf[0] & W1_F19_STATUS_START)
13962306a36Sopenharmony_ci		return -EAGAIN;
14062306a36Sopenharmony_ci	if (w1_buf[0] != 0 || w1_buf[1] != 0)
14162306a36Sopenharmony_ci		return -EIO;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* All ok. */
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/* Utility function: write data to I2C slave, single chunk. */
14962306a36Sopenharmony_cistatic int __w1_f19_i2c_write(struct w1_slave *sl,
15062306a36Sopenharmony_ci	const u8 *command, size_t command_count,
15162306a36Sopenharmony_ci	const u8 *buffer, size_t count)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	u16 crc;
15462306a36Sopenharmony_ci	int error;
15562306a36Sopenharmony_ci	u8 w1_buf[2];
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* Send command and I2C data to DS28E17. */
15862306a36Sopenharmony_ci	crc = crc16(CRC16_INIT, command, command_count);
15962306a36Sopenharmony_ci	w1_write_block(sl->master, command, command_count);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	w1_buf[0] = count;
16262306a36Sopenharmony_ci	crc = crc16(crc, w1_buf, 1);
16362306a36Sopenharmony_ci	w1_write_8(sl->master, w1_buf[0]);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	crc = crc16(crc, buffer, count);
16662306a36Sopenharmony_ci	w1_write_block(sl->master, buffer, count);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	w1_buf[0] = ~(crc & 0xFF);
16962306a36Sopenharmony_ci	w1_buf[1] = ~((crc >> 8) & 0xFF);
17062306a36Sopenharmony_ci	w1_write_block(sl->master, w1_buf, 2);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Wait until busy flag clears (or timeout). */
17362306a36Sopenharmony_ci	if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
17462306a36Sopenharmony_ci		return -ETIMEDOUT;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* Read status from DS28E17. */
17762306a36Sopenharmony_ci	w1_read_block(sl->master, w1_buf, 2);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Check error conditions. */
18062306a36Sopenharmony_ci	error = w1_f19_error(sl, w1_buf);
18162306a36Sopenharmony_ci	if (error < 0)
18262306a36Sopenharmony_ci		return error;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* Return number of bytes written. */
18562306a36Sopenharmony_ci	return count;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/* Write data to I2C slave. */
19062306a36Sopenharmony_cistatic int w1_f19_i2c_write(struct w1_slave *sl, u16 i2c_address,
19162306a36Sopenharmony_ci	const u8 *buffer, size_t count, bool stop)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	int result;
19462306a36Sopenharmony_ci	int remaining = count;
19562306a36Sopenharmony_ci	const u8 *p;
19662306a36Sopenharmony_ci	u8 command[2];
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* Check input. */
19962306a36Sopenharmony_ci	if (count == 0)
20062306a36Sopenharmony_ci		return -EOPNOTSUPP;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* Check whether we need multiple commands. */
20362306a36Sopenharmony_ci	if (count <= W1_F19_WRITE_DATA_LIMIT) {
20462306a36Sopenharmony_ci		/*
20562306a36Sopenharmony_ci		 * Small data amount. Data can be sent with
20662306a36Sopenharmony_ci		 * a single onewire command.
20762306a36Sopenharmony_ci		 */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		/* Send all data to DS28E17. */
21062306a36Sopenharmony_ci		command[0] = (stop ? W1_F19_WRITE_DATA_WITH_STOP
21162306a36Sopenharmony_ci			: W1_F19_WRITE_DATA_NO_STOP);
21262306a36Sopenharmony_ci		command[1] = i2c_address << 1;
21362306a36Sopenharmony_ci		result = __w1_f19_i2c_write(sl, command, 2, buffer, count);
21462306a36Sopenharmony_ci	} else {
21562306a36Sopenharmony_ci		/* Large data amount. Data has to be sent in multiple chunks. */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		/* Send first chunk to DS28E17. */
21862306a36Sopenharmony_ci		p = buffer;
21962306a36Sopenharmony_ci		command[0] = W1_F19_WRITE_DATA_NO_STOP;
22062306a36Sopenharmony_ci		command[1] = i2c_address << 1;
22162306a36Sopenharmony_ci		result = __w1_f19_i2c_write(sl, command, 2, p,
22262306a36Sopenharmony_ci			W1_F19_WRITE_DATA_LIMIT);
22362306a36Sopenharmony_ci		if (result < 0)
22462306a36Sopenharmony_ci			return result;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		/* Resume to same DS28E17. */
22762306a36Sopenharmony_ci		if (w1_reset_resume_command(sl->master))
22862306a36Sopenharmony_ci			return -EIO;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		/* Next data chunk. */
23162306a36Sopenharmony_ci		p += W1_F19_WRITE_DATA_LIMIT;
23262306a36Sopenharmony_ci		remaining -= W1_F19_WRITE_DATA_LIMIT;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		while (remaining > W1_F19_WRITE_DATA_LIMIT) {
23562306a36Sopenharmony_ci			/* Send intermediate chunk to DS28E17. */
23662306a36Sopenharmony_ci			command[0] = W1_F19_WRITE_DATA_ONLY;
23762306a36Sopenharmony_ci			result = __w1_f19_i2c_write(sl, command, 1, p,
23862306a36Sopenharmony_ci					W1_F19_WRITE_DATA_LIMIT);
23962306a36Sopenharmony_ci			if (result < 0)
24062306a36Sopenharmony_ci				return result;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci			/* Resume to same DS28E17. */
24362306a36Sopenharmony_ci			if (w1_reset_resume_command(sl->master))
24462306a36Sopenharmony_ci				return -EIO;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci			/* Next data chunk. */
24762306a36Sopenharmony_ci			p += W1_F19_WRITE_DATA_LIMIT;
24862306a36Sopenharmony_ci			remaining -= W1_F19_WRITE_DATA_LIMIT;
24962306a36Sopenharmony_ci		}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		/* Send final chunk to DS28E17. */
25262306a36Sopenharmony_ci		command[0] = (stop ? W1_F19_WRITE_DATA_ONLY_WITH_STOP
25362306a36Sopenharmony_ci			: W1_F19_WRITE_DATA_ONLY);
25462306a36Sopenharmony_ci		result = __w1_f19_i2c_write(sl, command, 1, p, remaining);
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return result;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* Read data from I2C slave. */
26262306a36Sopenharmony_cistatic int w1_f19_i2c_read(struct w1_slave *sl, u16 i2c_address,
26362306a36Sopenharmony_ci	u8 *buffer, size_t count)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	u16 crc;
26662306a36Sopenharmony_ci	int error;
26762306a36Sopenharmony_ci	u8 w1_buf[5];
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* Check input. */
27062306a36Sopenharmony_ci	if (count == 0)
27162306a36Sopenharmony_ci		return -EOPNOTSUPP;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Send command to DS28E17. */
27462306a36Sopenharmony_ci	w1_buf[0] = W1_F19_READ_DATA_WITH_STOP;
27562306a36Sopenharmony_ci	w1_buf[1] = i2c_address << 1 | 0x01;
27662306a36Sopenharmony_ci	w1_buf[2] = count;
27762306a36Sopenharmony_ci	crc = crc16(CRC16_INIT, w1_buf, 3);
27862306a36Sopenharmony_ci	w1_buf[3] = ~(crc & 0xFF);
27962306a36Sopenharmony_ci	w1_buf[4] = ~((crc >> 8) & 0xFF);
28062306a36Sopenharmony_ci	w1_write_block(sl->master, w1_buf, 5);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* Wait until busy flag clears (or timeout). */
28362306a36Sopenharmony_ci	if (w1_f19_i2c_busy_wait(sl, count + 1) < 0)
28462306a36Sopenharmony_ci		return -ETIMEDOUT;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Read status from DS28E17. */
28762306a36Sopenharmony_ci	w1_buf[0] = w1_read_8(sl->master);
28862306a36Sopenharmony_ci	w1_buf[1] = 0;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* Check error conditions. */
29162306a36Sopenharmony_ci	error = w1_f19_error(sl, w1_buf);
29262306a36Sopenharmony_ci	if (error < 0)
29362306a36Sopenharmony_ci		return error;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* Read received I2C data from DS28E17. */
29662306a36Sopenharmony_ci	return w1_read_block(sl->master, buffer, count);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/* Write to, then read data from I2C slave. */
30162306a36Sopenharmony_cistatic int w1_f19_i2c_write_read(struct w1_slave *sl, u16 i2c_address,
30262306a36Sopenharmony_ci	const u8 *wbuffer, size_t wcount, u8 *rbuffer, size_t rcount)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	u16 crc;
30562306a36Sopenharmony_ci	int error;
30662306a36Sopenharmony_ci	u8 w1_buf[3];
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* Check input. */
30962306a36Sopenharmony_ci	if (wcount == 0 || rcount == 0)
31062306a36Sopenharmony_ci		return -EOPNOTSUPP;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/* Send command and I2C data to DS28E17. */
31362306a36Sopenharmony_ci	w1_buf[0] = W1_F19_WRITE_READ_DATA_WITH_STOP;
31462306a36Sopenharmony_ci	w1_buf[1] = i2c_address << 1;
31562306a36Sopenharmony_ci	w1_buf[2] = wcount;
31662306a36Sopenharmony_ci	crc = crc16(CRC16_INIT, w1_buf, 3);
31762306a36Sopenharmony_ci	w1_write_block(sl->master, w1_buf, 3);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	crc = crc16(crc, wbuffer, wcount);
32062306a36Sopenharmony_ci	w1_write_block(sl->master, wbuffer, wcount);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	w1_buf[0] = rcount;
32362306a36Sopenharmony_ci	crc = crc16(crc, w1_buf, 1);
32462306a36Sopenharmony_ci	w1_buf[1] = ~(crc & 0xFF);
32562306a36Sopenharmony_ci	w1_buf[2] = ~((crc >> 8) & 0xFF);
32662306a36Sopenharmony_ci	w1_write_block(sl->master, w1_buf, 3);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* Wait until busy flag clears (or timeout). */
32962306a36Sopenharmony_ci	if (w1_f19_i2c_busy_wait(sl, wcount + rcount + 2) < 0)
33062306a36Sopenharmony_ci		return -ETIMEDOUT;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* Read status from DS28E17. */
33362306a36Sopenharmony_ci	w1_read_block(sl->master, w1_buf, 2);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* Check error conditions. */
33662306a36Sopenharmony_ci	error = w1_f19_error(sl, w1_buf);
33762306a36Sopenharmony_ci	if (error < 0)
33862306a36Sopenharmony_ci		return error;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* Read received I2C data from DS28E17. */
34162306a36Sopenharmony_ci	return w1_read_block(sl->master, rbuffer, rcount);
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/* Do an I2C master transfer. */
34662306a36Sopenharmony_cistatic int w1_f19_i2c_master_transfer(struct i2c_adapter *adapter,
34762306a36Sopenharmony_ci	struct i2c_msg *msgs, int num)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct w1_slave *sl = (struct w1_slave *) adapter->algo_data;
35062306a36Sopenharmony_ci	int i = 0;
35162306a36Sopenharmony_ci	int result = 0;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* Start onewire transaction. */
35462306a36Sopenharmony_ci	mutex_lock(&sl->master->bus_mutex);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Select DS28E17. */
35762306a36Sopenharmony_ci	if (w1_reset_select_slave(sl)) {
35862306a36Sopenharmony_ci		i = -EIO;
35962306a36Sopenharmony_ci		goto error;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* Loop while there are still messages to transfer. */
36362306a36Sopenharmony_ci	while (i < num) {
36462306a36Sopenharmony_ci		/*
36562306a36Sopenharmony_ci		 * Check for special case: Small write followed
36662306a36Sopenharmony_ci		 * by read to same I2C device.
36762306a36Sopenharmony_ci		 */
36862306a36Sopenharmony_ci		if (i < (num-1)
36962306a36Sopenharmony_ci			&& msgs[i].addr == msgs[i+1].addr
37062306a36Sopenharmony_ci			&& !(msgs[i].flags & I2C_M_RD)
37162306a36Sopenharmony_ci			&& (msgs[i+1].flags & I2C_M_RD)
37262306a36Sopenharmony_ci			&& (msgs[i].len <= W1_F19_WRITE_DATA_LIMIT)) {
37362306a36Sopenharmony_ci			/*
37462306a36Sopenharmony_ci			 * The DS28E17 has a combined transfer
37562306a36Sopenharmony_ci			 * for small write+read.
37662306a36Sopenharmony_ci			 */
37762306a36Sopenharmony_ci			result = w1_f19_i2c_write_read(sl, msgs[i].addr,
37862306a36Sopenharmony_ci				msgs[i].buf, msgs[i].len,
37962306a36Sopenharmony_ci				msgs[i+1].buf, msgs[i+1].len);
38062306a36Sopenharmony_ci			if (result < 0) {
38162306a36Sopenharmony_ci				i = result;
38262306a36Sopenharmony_ci				goto error;
38362306a36Sopenharmony_ci			}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci			/*
38662306a36Sopenharmony_ci			 * Check if we should interpret the read data
38762306a36Sopenharmony_ci			 * as a length byte. The DS28E17 unfortunately
38862306a36Sopenharmony_ci			 * has no read without stop, so we can just do
38962306a36Sopenharmony_ci			 * another simple read in that case.
39062306a36Sopenharmony_ci			 */
39162306a36Sopenharmony_ci			if (msgs[i+1].flags & I2C_M_RECV_LEN) {
39262306a36Sopenharmony_ci				result = w1_f19_i2c_read(sl, msgs[i+1].addr,
39362306a36Sopenharmony_ci					&(msgs[i+1].buf[1]), msgs[i+1].buf[0]);
39462306a36Sopenharmony_ci				if (result < 0) {
39562306a36Sopenharmony_ci					i = result;
39662306a36Sopenharmony_ci					goto error;
39762306a36Sopenharmony_ci				}
39862306a36Sopenharmony_ci			}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci			/* Eat up read message, too. */
40162306a36Sopenharmony_ci			i++;
40262306a36Sopenharmony_ci		} else if (msgs[i].flags & I2C_M_RD) {
40362306a36Sopenharmony_ci			/* Read transfer. */
40462306a36Sopenharmony_ci			result = w1_f19_i2c_read(sl, msgs[i].addr,
40562306a36Sopenharmony_ci				msgs[i].buf, msgs[i].len);
40662306a36Sopenharmony_ci			if (result < 0) {
40762306a36Sopenharmony_ci				i = result;
40862306a36Sopenharmony_ci				goto error;
40962306a36Sopenharmony_ci			}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci			/*
41262306a36Sopenharmony_ci			 * Check if we should interpret the read data
41362306a36Sopenharmony_ci			 * as a length byte. The DS28E17 unfortunately
41462306a36Sopenharmony_ci			 * has no read without stop, so we can just do
41562306a36Sopenharmony_ci			 * another simple read in that case.
41662306a36Sopenharmony_ci			 */
41762306a36Sopenharmony_ci			if (msgs[i].flags & I2C_M_RECV_LEN) {
41862306a36Sopenharmony_ci				result = w1_f19_i2c_read(sl,
41962306a36Sopenharmony_ci					msgs[i].addr,
42062306a36Sopenharmony_ci					&(msgs[i].buf[1]),
42162306a36Sopenharmony_ci					msgs[i].buf[0]);
42262306a36Sopenharmony_ci				if (result < 0) {
42362306a36Sopenharmony_ci					i = result;
42462306a36Sopenharmony_ci					goto error;
42562306a36Sopenharmony_ci				}
42662306a36Sopenharmony_ci			}
42762306a36Sopenharmony_ci		} else {
42862306a36Sopenharmony_ci			/*
42962306a36Sopenharmony_ci			 * Write transfer.
43062306a36Sopenharmony_ci			 * Stop condition only for last
43162306a36Sopenharmony_ci			 * transfer.
43262306a36Sopenharmony_ci			 */
43362306a36Sopenharmony_ci			result = w1_f19_i2c_write(sl,
43462306a36Sopenharmony_ci				msgs[i].addr,
43562306a36Sopenharmony_ci				msgs[i].buf,
43662306a36Sopenharmony_ci				msgs[i].len,
43762306a36Sopenharmony_ci				i == (num-1));
43862306a36Sopenharmony_ci			if (result < 0) {
43962306a36Sopenharmony_ci				i = result;
44062306a36Sopenharmony_ci				goto error;
44162306a36Sopenharmony_ci			}
44262306a36Sopenharmony_ci		}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		/* Next message. */
44562306a36Sopenharmony_ci		i++;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci		/* Are there still messages to send/receive? */
44862306a36Sopenharmony_ci		if (i < num) {
44962306a36Sopenharmony_ci			/* Yes. Resume to same DS28E17. */
45062306a36Sopenharmony_ci			if (w1_reset_resume_command(sl->master)) {
45162306a36Sopenharmony_ci				i = -EIO;
45262306a36Sopenharmony_ci				goto error;
45362306a36Sopenharmony_ci			}
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cierror:
45862306a36Sopenharmony_ci	/* End onewire transaction. */
45962306a36Sopenharmony_ci	mutex_unlock(&sl->master->bus_mutex);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* Return number of messages processed or error. */
46262306a36Sopenharmony_ci	return i;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci/* Get I2C adapter functionality. */
46762306a36Sopenharmony_cistatic u32 w1_f19_i2c_functionality(struct i2c_adapter *adapter)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	/*
47062306a36Sopenharmony_ci	 * Plain I2C functions only.
47162306a36Sopenharmony_ci	 * SMBus is emulated by the kernel's I2C layer.
47262306a36Sopenharmony_ci	 * No "I2C_FUNC_SMBUS_QUICK"
47362306a36Sopenharmony_ci	 * No "I2C_FUNC_SMBUS_READ_BLOCK_DATA"
47462306a36Sopenharmony_ci	 * No "I2C_FUNC_SMBUS_BLOCK_PROC_CALL"
47562306a36Sopenharmony_ci	 */
47662306a36Sopenharmony_ci	return I2C_FUNC_I2C |
47762306a36Sopenharmony_ci		I2C_FUNC_SMBUS_BYTE |
47862306a36Sopenharmony_ci		I2C_FUNC_SMBUS_BYTE_DATA |
47962306a36Sopenharmony_ci		I2C_FUNC_SMBUS_WORD_DATA |
48062306a36Sopenharmony_ci		I2C_FUNC_SMBUS_PROC_CALL |
48162306a36Sopenharmony_ci		I2C_FUNC_SMBUS_WRITE_BLOCK_DATA |
48262306a36Sopenharmony_ci		I2C_FUNC_SMBUS_I2C_BLOCK |
48362306a36Sopenharmony_ci		I2C_FUNC_SMBUS_PEC;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/* I2C adapter quirks. */
48862306a36Sopenharmony_cistatic const struct i2c_adapter_quirks w1_f19_i2c_adapter_quirks = {
48962306a36Sopenharmony_ci	.max_read_len = W1_F19_READ_DATA_LIMIT,
49062306a36Sopenharmony_ci};
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/* I2C algorithm. */
49362306a36Sopenharmony_cistatic const struct i2c_algorithm w1_f19_i2c_algorithm = {
49462306a36Sopenharmony_ci	.master_xfer    = w1_f19_i2c_master_transfer,
49562306a36Sopenharmony_ci	.functionality  = w1_f19_i2c_functionality,
49662306a36Sopenharmony_ci};
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/* Read I2C speed from DS28E17. */
50062306a36Sopenharmony_cistatic int w1_f19_get_i2c_speed(struct w1_slave *sl)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct w1_f19_data *data = sl->family_data;
50362306a36Sopenharmony_ci	int result = -EIO;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* Start onewire transaction. */
50662306a36Sopenharmony_ci	mutex_lock(&sl->master->bus_mutex);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	/* Select slave. */
50962306a36Sopenharmony_ci	if (w1_reset_select_slave(sl))
51062306a36Sopenharmony_ci		goto error;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Read slave configuration byte. */
51362306a36Sopenharmony_ci	w1_write_8(sl->master, W1_F19_READ_CONFIGURATION);
51462306a36Sopenharmony_ci	result = w1_read_8(sl->master);
51562306a36Sopenharmony_ci	if (result < 0 || result > 2) {
51662306a36Sopenharmony_ci		result = -EIO;
51762306a36Sopenharmony_ci		goto error;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* Update speed in slave specific data. */
52162306a36Sopenharmony_ci	data->speed = result;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cierror:
52462306a36Sopenharmony_ci	/* End onewire transaction. */
52562306a36Sopenharmony_ci	mutex_unlock(&sl->master->bus_mutex);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return result;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci/* Set I2C speed on DS28E17. */
53262306a36Sopenharmony_cistatic int __w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct w1_f19_data *data = sl->family_data;
53562306a36Sopenharmony_ci	const int i2c_speeds[3] = { 100, 400, 900 };
53662306a36Sopenharmony_ci	u8 w1_buf[2];
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/* Select slave. */
53962306a36Sopenharmony_ci	if (w1_reset_select_slave(sl))
54062306a36Sopenharmony_ci		return -EIO;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	w1_buf[0] = W1_F19_WRITE_CONFIGURATION;
54362306a36Sopenharmony_ci	w1_buf[1] = speed;
54462306a36Sopenharmony_ci	w1_write_block(sl->master, w1_buf, 2);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	/* Update speed in slave specific data. */
54762306a36Sopenharmony_ci	data->speed = speed;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	dev_info(&sl->dev, "i2c speed set to %d kBaud\n", i2c_speeds[speed]);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	return 0;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic int w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	int result;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/* Start onewire transaction. */
55962306a36Sopenharmony_ci	mutex_lock(&sl->master->bus_mutex);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* Set I2C speed on DS28E17. */
56262306a36Sopenharmony_ci	result = __w1_f19_set_i2c_speed(sl, speed);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	/* End onewire transaction. */
56562306a36Sopenharmony_ci	mutex_unlock(&sl->master->bus_mutex);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return result;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/* Sysfs attributes. */
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/* I2C speed attribute for a single chip. */
57462306a36Sopenharmony_cistatic ssize_t speed_show(struct device *dev, struct device_attribute *attr,
57562306a36Sopenharmony_ci			     char *buf)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(dev);
57862306a36Sopenharmony_ci	int result;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/* Read current speed from slave. Updates data->speed. */
58162306a36Sopenharmony_ci	result = w1_f19_get_i2c_speed(sl);
58262306a36Sopenharmony_ci	if (result < 0)
58362306a36Sopenharmony_ci		return result;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Return current speed value. */
58662306a36Sopenharmony_ci	return sprintf(buf, "%d\n", result);
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic ssize_t speed_store(struct device *dev, struct device_attribute *attr,
59062306a36Sopenharmony_ci			      const char *buf, size_t count)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(dev);
59362306a36Sopenharmony_ci	int error;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* Valid values are: "100", "400", "900" */
59662306a36Sopenharmony_ci	if (count < 3 || count > 4 || !buf)
59762306a36Sopenharmony_ci		return -EINVAL;
59862306a36Sopenharmony_ci	if (count == 4 && buf[3] != '\n')
59962306a36Sopenharmony_ci		return -EINVAL;
60062306a36Sopenharmony_ci	if (buf[1] != '0' || buf[2] != '0')
60162306a36Sopenharmony_ci		return -EINVAL;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* Set speed on slave. */
60462306a36Sopenharmony_ci	switch (buf[0]) {
60562306a36Sopenharmony_ci	case '1':
60662306a36Sopenharmony_ci		error = w1_f19_set_i2c_speed(sl, 0);
60762306a36Sopenharmony_ci		break;
60862306a36Sopenharmony_ci	case '4':
60962306a36Sopenharmony_ci		error = w1_f19_set_i2c_speed(sl, 1);
61062306a36Sopenharmony_ci		break;
61162306a36Sopenharmony_ci	case '9':
61262306a36Sopenharmony_ci		error = w1_f19_set_i2c_speed(sl, 2);
61362306a36Sopenharmony_ci		break;
61462306a36Sopenharmony_ci	default:
61562306a36Sopenharmony_ci		return -EINVAL;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (error < 0)
61962306a36Sopenharmony_ci		return error;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* Return bytes written. */
62262306a36Sopenharmony_ci	return count;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(speed);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci/* Busy stretch attribute for a single chip. */
62962306a36Sopenharmony_cistatic ssize_t stretch_show(struct device *dev, struct device_attribute *attr,
63062306a36Sopenharmony_ci			     char *buf)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(dev);
63362306a36Sopenharmony_ci	struct w1_f19_data *data = sl->family_data;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/* Return current stretch value. */
63662306a36Sopenharmony_ci	return sprintf(buf, "%d\n", data->stretch);
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic ssize_t stretch_store(struct device *dev, struct device_attribute *attr,
64062306a36Sopenharmony_ci			      const char *buf, size_t count)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(dev);
64362306a36Sopenharmony_ci	struct w1_f19_data *data = sl->family_data;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* Valid values are '1' to '9' */
64662306a36Sopenharmony_ci	if (count < 1 || count > 2 || !buf)
64762306a36Sopenharmony_ci		return -EINVAL;
64862306a36Sopenharmony_ci	if (count == 2 && buf[1] != '\n')
64962306a36Sopenharmony_ci		return -EINVAL;
65062306a36Sopenharmony_ci	if (buf[0] < '1' || buf[0] > '9')
65162306a36Sopenharmony_ci		return -EINVAL;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* Set busy stretch value. */
65462306a36Sopenharmony_ci	data->stretch = buf[0] & 0x0F;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/* Return bytes written. */
65762306a36Sopenharmony_ci	return count;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(stretch);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci/* All attributes. */
66462306a36Sopenharmony_cistatic struct attribute *w1_f19_attrs[] = {
66562306a36Sopenharmony_ci	&dev_attr_speed.attr,
66662306a36Sopenharmony_ci	&dev_attr_stretch.attr,
66762306a36Sopenharmony_ci	NULL,
66862306a36Sopenharmony_ci};
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic const struct attribute_group w1_f19_group = {
67162306a36Sopenharmony_ci	.attrs		= w1_f19_attrs,
67262306a36Sopenharmony_ci};
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic const struct attribute_group *w1_f19_groups[] = {
67562306a36Sopenharmony_ci	&w1_f19_group,
67662306a36Sopenharmony_ci	NULL,
67762306a36Sopenharmony_ci};
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci/* Slave add and remove functions. */
68162306a36Sopenharmony_cistatic int w1_f19_add_slave(struct w1_slave *sl)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct w1_f19_data *data = NULL;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/* Allocate memory for slave specific data. */
68662306a36Sopenharmony_ci	data = devm_kzalloc(&sl->dev, sizeof(*data), GFP_KERNEL);
68762306a36Sopenharmony_ci	if (!data)
68862306a36Sopenharmony_ci		return -ENOMEM;
68962306a36Sopenharmony_ci	sl->family_data = data;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	/* Setup default I2C speed on slave. */
69262306a36Sopenharmony_ci	switch (i2c_speed) {
69362306a36Sopenharmony_ci	case 100:
69462306a36Sopenharmony_ci		__w1_f19_set_i2c_speed(sl, 0);
69562306a36Sopenharmony_ci		break;
69662306a36Sopenharmony_ci	case 400:
69762306a36Sopenharmony_ci		__w1_f19_set_i2c_speed(sl, 1);
69862306a36Sopenharmony_ci		break;
69962306a36Sopenharmony_ci	case 900:
70062306a36Sopenharmony_ci		__w1_f19_set_i2c_speed(sl, 2);
70162306a36Sopenharmony_ci		break;
70262306a36Sopenharmony_ci	default:
70362306a36Sopenharmony_ci		/*
70462306a36Sopenharmony_ci		 * A i2c_speed module parameter of anything else
70562306a36Sopenharmony_ci		 * than 100, 400, 900 means not to touch the
70662306a36Sopenharmony_ci		 * speed of the DS28E17.
70762306a36Sopenharmony_ci		 * We assume 400kBaud, the power-on value.
70862306a36Sopenharmony_ci		 */
70962306a36Sopenharmony_ci		data->speed = 1;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/*
71362306a36Sopenharmony_ci	 * Setup default busy stretch
71462306a36Sopenharmony_ci	 * configuration for the DS28E17.
71562306a36Sopenharmony_ci	 */
71662306a36Sopenharmony_ci	data->stretch = i2c_stretch;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* Setup I2C adapter. */
71962306a36Sopenharmony_ci	data->adapter.owner      = THIS_MODULE;
72062306a36Sopenharmony_ci	data->adapter.algo       = &w1_f19_i2c_algorithm;
72162306a36Sopenharmony_ci	data->adapter.algo_data  = sl;
72262306a36Sopenharmony_ci	strcpy(data->adapter.name, "w1-");
72362306a36Sopenharmony_ci	strcat(data->adapter.name, sl->name);
72462306a36Sopenharmony_ci	data->adapter.dev.parent = &sl->dev;
72562306a36Sopenharmony_ci	data->adapter.quirks     = &w1_f19_i2c_adapter_quirks;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return i2c_add_adapter(&data->adapter);
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic void w1_f19_remove_slave(struct w1_slave *sl)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct w1_f19_data *family_data = sl->family_data;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* Delete I2C adapter. */
73562306a36Sopenharmony_ci	i2c_del_adapter(&family_data->adapter);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	/* Free slave specific data. */
73862306a36Sopenharmony_ci	devm_kfree(&sl->dev, family_data);
73962306a36Sopenharmony_ci	sl->family_data = NULL;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci/* Declarations within the w1 subsystem. */
74462306a36Sopenharmony_cistatic const struct w1_family_ops w1_f19_fops = {
74562306a36Sopenharmony_ci	.add_slave = w1_f19_add_slave,
74662306a36Sopenharmony_ci	.remove_slave = w1_f19_remove_slave,
74762306a36Sopenharmony_ci	.groups = w1_f19_groups,
74862306a36Sopenharmony_ci};
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic struct w1_family w1_family_19 = {
75162306a36Sopenharmony_ci	.fid = W1_FAMILY_DS28E17,
75262306a36Sopenharmony_ci	.fops = &w1_f19_fops,
75362306a36Sopenharmony_ci};
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cimodule_w1_family(w1_family_19);
756