162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	w1_therm.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/types.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/moduleparam.h>
1362306a36Sopenharmony_ci#include <linux/sched.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/hwmon.h>
1962306a36Sopenharmony_ci#include <linux/string.h>
2062306a36Sopenharmony_ci#include <linux/jiffies.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/w1.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define W1_THERM_DS18S20	0x10
2562306a36Sopenharmony_ci#define W1_THERM_DS1822		0x22
2662306a36Sopenharmony_ci#define W1_THERM_DS18B20	0x28
2762306a36Sopenharmony_ci#define W1_THERM_DS1825		0x3B
2862306a36Sopenharmony_ci#define W1_THERM_DS28EA00	0x42
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * Allow the strong pullup to be disabled, but default to enabled.
3262306a36Sopenharmony_ci * If it was disabled a parasite powered device might not get the require
3362306a36Sopenharmony_ci * current to do a temperature conversion.  If it is enabled parasite powered
3462306a36Sopenharmony_ci * devices have a better chance of getting the current required.
3562306a36Sopenharmony_ci * In case the parasite power-detection is not working (seems to be the case
3662306a36Sopenharmony_ci * for some DS18S20) the strong pullup can also be forced, regardless of the
3762306a36Sopenharmony_ci * power state of the devices.
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * Summary of options:
4062306a36Sopenharmony_ci * - strong_pullup = 0	Disable strong pullup completely
4162306a36Sopenharmony_ci * - strong_pullup = 1	Enable automatic strong pullup detection
4262306a36Sopenharmony_ci * - strong_pullup = 2	Force strong pullup
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_cistatic int w1_strong_pullup = 1;
4562306a36Sopenharmony_cimodule_param_named(strong_pullup, w1_strong_pullup, int, 0);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* Counter for devices supporting bulk reading */
4862306a36Sopenharmony_cistatic u16 bulk_read_device_counter; /* =0 as per C standard */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* This command should be in public header w1.h but is not */
5162306a36Sopenharmony_ci#define W1_RECALL_EEPROM	0xB8
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Nb of try for an operation */
5462306a36Sopenharmony_ci#define W1_THERM_MAX_TRY		5
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* ms delay to retry bus mutex */
5762306a36Sopenharmony_ci#define W1_THERM_RETRY_DELAY		20
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* delay in ms to write in EEPROM */
6062306a36Sopenharmony_ci#define W1_THERM_EEPROM_WRITE_DELAY	10
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define EEPROM_CMD_WRITE    "save"	/* cmd for write eeprom sysfs */
6362306a36Sopenharmony_ci#define EEPROM_CMD_READ     "restore"	/* cmd for read eeprom sysfs */
6462306a36Sopenharmony_ci#define BULK_TRIGGER_CMD    "trigger"	/* cmd to trigger a bulk read */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define MIN_TEMP	-55	/* min temperature that can be measured */
6762306a36Sopenharmony_ci#define MAX_TEMP	125	/* max temperature that can be measured */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* Allowed values for sysfs conv_time attribute */
7062306a36Sopenharmony_ci#define CONV_TIME_DEFAULT 0
7162306a36Sopenharmony_ci#define CONV_TIME_MEASURE 1
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* Bits in sysfs "features" value */
7462306a36Sopenharmony_ci#define W1_THERM_CHECK_RESULT 1	/* Enable conversion success check */
7562306a36Sopenharmony_ci#define W1_THERM_POLL_COMPLETION 2	/* Poll for conversion completion */
7662306a36Sopenharmony_ci#define W1_THERM_FEATURES_MASK 3		/* All values mask */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* Poll period in milliseconds. Should be less then a shortest operation on the device */
7962306a36Sopenharmony_ci#define W1_POLL_PERIOD 32
8062306a36Sopenharmony_ci#define W1_POLL_CONVERT_TEMP 2000	/* Timeout for W1_CONVERT_TEMP, ms */
8162306a36Sopenharmony_ci#define W1_POLL_RECALL_EEPROM 500	/* Timeout for W1_RECALL_EEPROM, ms*/
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* Masks for resolution functions, work with all devices */
8462306a36Sopenharmony_ci/* Bit mask for config register for all devices, bits 7,6,5 */
8562306a36Sopenharmony_ci#define W1_THERM_RESOLUTION_MASK 0xE0
8662306a36Sopenharmony_ci/* Bit offset of resolution in config register for all devices */
8762306a36Sopenharmony_ci#define W1_THERM_RESOLUTION_SHIFT 5
8862306a36Sopenharmony_ci/* Bit offset of resolution in config register for all devices */
8962306a36Sopenharmony_ci#define W1_THERM_RESOLUTION_SHIFT 5
9062306a36Sopenharmony_ci/* Add this to bit value to get resolution */
9162306a36Sopenharmony_ci#define W1_THERM_RESOLUTION_MIN 9
9262306a36Sopenharmony_ci/* Maximum allowed value */
9362306a36Sopenharmony_ci#define W1_THERM_RESOLUTION_MAX 14
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* Helpers Macros */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/*
9862306a36Sopenharmony_ci * return a pointer on the slave w1_therm_family_converter struct:
9962306a36Sopenharmony_ci * always test family data existence before using this macro
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_ci#define SLAVE_SPECIFIC_FUNC(sl) \
10262306a36Sopenharmony_ci	(((struct w1_therm_family_data *)(sl->family_data))->specific_functions)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * return the power mode of the sl slave : 1-ext, 0-parasite, <0 unknown
10662306a36Sopenharmony_ci * always test family data existence before using this macro
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_ci#define SLAVE_POWERMODE(sl) \
10962306a36Sopenharmony_ci	(((struct w1_therm_family_data *)(sl->family_data))->external_powered)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/*
11262306a36Sopenharmony_ci * return the resolution in bit of the sl slave : <0 unknown
11362306a36Sopenharmony_ci * always test family data existence before using this macro
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ci#define SLAVE_RESOLUTION(sl) \
11662306a36Sopenharmony_ci	(((struct w1_therm_family_data *)(sl->family_data))->resolution)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/*
11962306a36Sopenharmony_ci * return the conv_time_override of the sl slave
12062306a36Sopenharmony_ci * always test family data existence before using this macro
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_ci #define SLAVE_CONV_TIME_OVERRIDE(sl) \
12362306a36Sopenharmony_ci	(((struct w1_therm_family_data *)(sl->family_data))->conv_time_override)
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * return the features of the sl slave
12762306a36Sopenharmony_ci * always test family data existence before using this macro
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ci #define SLAVE_FEATURES(sl) \
13062306a36Sopenharmony_ci	(((struct w1_therm_family_data *)(sl->family_data))->features)
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * return whether or not a converT command has been issued to the slave
13462306a36Sopenharmony_ci * * 0: no bulk read is pending
13562306a36Sopenharmony_ci * * -1: conversion is in progress
13662306a36Sopenharmony_ci * * 1: conversion done, result to be read
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_ci#define SLAVE_CONVERT_TRIGGERED(sl) \
13962306a36Sopenharmony_ci	(((struct w1_therm_family_data *)(sl->family_data))->convert_triggered)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* return the address of the refcnt in the family data */
14262306a36Sopenharmony_ci#define THERM_REFCNT(family_data) \
14362306a36Sopenharmony_ci	(&((struct w1_therm_family_data *)family_data)->refcnt)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* Structs definition */
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/**
14862306a36Sopenharmony_ci * struct w1_therm_family_converter - bind device specific functions
14962306a36Sopenharmony_ci * @broken: flag for non-registred families
15062306a36Sopenharmony_ci * @reserved: not used here
15162306a36Sopenharmony_ci * @f: pointer to the device binding structure
15262306a36Sopenharmony_ci * @convert: pointer to the device conversion function
15362306a36Sopenharmony_ci * @get_conversion_time: pointer to the device conversion time function
15462306a36Sopenharmony_ci * @set_resolution: pointer to the device set_resolution function
15562306a36Sopenharmony_ci * @get_resolution: pointer to the device get_resolution function
15662306a36Sopenharmony_ci * @write_data: pointer to the device writing function (2 or 3 bytes)
15762306a36Sopenharmony_ci * @bulk_read: true if device family support bulk read, false otherwise
15862306a36Sopenharmony_ci */
15962306a36Sopenharmony_cistruct w1_therm_family_converter {
16062306a36Sopenharmony_ci	u8		broken;
16162306a36Sopenharmony_ci	u16		reserved;
16262306a36Sopenharmony_ci	struct w1_family	*f;
16362306a36Sopenharmony_ci	int		(*convert)(u8 rom[9]);
16462306a36Sopenharmony_ci	int		(*get_conversion_time)(struct w1_slave *sl);
16562306a36Sopenharmony_ci	int		(*set_resolution)(struct w1_slave *sl, int val);
16662306a36Sopenharmony_ci	int		(*get_resolution)(struct w1_slave *sl);
16762306a36Sopenharmony_ci	int		(*write_data)(struct w1_slave *sl, const u8 *data);
16862306a36Sopenharmony_ci	bool		bulk_read;
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/**
17262306a36Sopenharmony_ci * struct w1_therm_family_data - device data
17362306a36Sopenharmony_ci * @rom: ROM device id (64bit Lasered ROM code + 1 CRC byte)
17462306a36Sopenharmony_ci * @refcnt: ref count
17562306a36Sopenharmony_ci * @external_powered:	1 device powered externally,
17662306a36Sopenharmony_ci *				0 device parasite powered,
17762306a36Sopenharmony_ci *				-x error or undefined
17862306a36Sopenharmony_ci * @resolution: current device resolution
17962306a36Sopenharmony_ci * @convert_triggered: conversion state of the device
18062306a36Sopenharmony_ci * @conv_time_override: user selected conversion time or CONV_TIME_DEFAULT
18162306a36Sopenharmony_ci * @features: bit mask - enable temperature validity check, poll for completion
18262306a36Sopenharmony_ci * @specific_functions: pointer to struct of device specific function
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_cistruct w1_therm_family_data {
18562306a36Sopenharmony_ci	uint8_t rom[9];
18662306a36Sopenharmony_ci	atomic_t refcnt;
18762306a36Sopenharmony_ci	int external_powered;
18862306a36Sopenharmony_ci	int resolution;
18962306a36Sopenharmony_ci	int convert_triggered;
19062306a36Sopenharmony_ci	int conv_time_override;
19162306a36Sopenharmony_ci	unsigned int features;
19262306a36Sopenharmony_ci	struct w1_therm_family_converter *specific_functions;
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/**
19662306a36Sopenharmony_ci * struct therm_info - store temperature reading
19762306a36Sopenharmony_ci * @rom: read device data (8 data bytes + 1 CRC byte)
19862306a36Sopenharmony_ci * @crc: computed crc from rom
19962306a36Sopenharmony_ci * @verdict: 1 crc checked, 0 crc not matching
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_cistruct therm_info {
20262306a36Sopenharmony_ci	u8 rom[9];
20362306a36Sopenharmony_ci	u8 crc;
20462306a36Sopenharmony_ci	u8 verdict;
20562306a36Sopenharmony_ci};
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/* Hardware Functions declaration */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci/**
21062306a36Sopenharmony_ci * reset_select_slave() - reset and select a slave
21162306a36Sopenharmony_ci * @sl: the slave to select
21262306a36Sopenharmony_ci *
21362306a36Sopenharmony_ci * Resets the bus and select the slave by sending a ROM MATCH cmd
21462306a36Sopenharmony_ci * w1_reset_select_slave() from w1_io.c could not be used here because
21562306a36Sopenharmony_ci * it sent a SKIP ROM command if only one device is on the line.
21662306a36Sopenharmony_ci * At the beginning of the such process, sl->master->slave_count is 1 even if
21762306a36Sopenharmony_ci * more devices are on the line, causing collision on the line.
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci * Context: The w1 master lock must be held.
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * Return: 0 if success, negative kernel error code otherwise.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_cistatic int reset_select_slave(struct w1_slave *sl);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/**
22662306a36Sopenharmony_ci * convert_t() - Query the device for temperature conversion and read
22762306a36Sopenharmony_ci * @sl: pointer to the slave to read
22862306a36Sopenharmony_ci * @info: pointer to a structure to store the read results
22962306a36Sopenharmony_ci *
23062306a36Sopenharmony_ci * Return: 0 if success, -kernel error code otherwise
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_cistatic int convert_t(struct w1_slave *sl, struct therm_info *info);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci/**
23562306a36Sopenharmony_ci * read_scratchpad() - read the data in device RAM
23662306a36Sopenharmony_ci * @sl: pointer to the slave to read
23762306a36Sopenharmony_ci * @info: pointer to a structure to store the read results
23862306a36Sopenharmony_ci *
23962306a36Sopenharmony_ci * Return: 0 if success, -kernel error code otherwise
24062306a36Sopenharmony_ci */
24162306a36Sopenharmony_cistatic int read_scratchpad(struct w1_slave *sl, struct therm_info *info);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/**
24462306a36Sopenharmony_ci * write_scratchpad() - write nb_bytes in the device RAM
24562306a36Sopenharmony_ci * @sl: pointer to the slave to write in
24662306a36Sopenharmony_ci * @data: pointer to an array of 3 bytes, as 3 bytes MUST be written
24762306a36Sopenharmony_ci * @nb_bytes: number of bytes to be written (2 for DS18S20, 3 otherwise)
24862306a36Sopenharmony_ci *
24962306a36Sopenharmony_ci * Return: 0 if success, -kernel error code otherwise
25062306a36Sopenharmony_ci */
25162306a36Sopenharmony_cistatic int write_scratchpad(struct w1_slave *sl, const u8 *data, u8 nb_bytes);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/**
25462306a36Sopenharmony_ci * copy_scratchpad() - Copy the content of scratchpad in device EEPROM
25562306a36Sopenharmony_ci * @sl: slave involved
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * Return: 0 if success, -kernel error code otherwise
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cistatic int copy_scratchpad(struct w1_slave *sl);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/**
26262306a36Sopenharmony_ci * recall_eeprom() - Restore EEPROM data to device RAM
26362306a36Sopenharmony_ci * @sl: slave involved
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * Return: 0 if success, -kernel error code otherwise
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_cistatic int recall_eeprom(struct w1_slave *sl);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/**
27062306a36Sopenharmony_ci * read_powermode() - Query the power mode of the slave
27162306a36Sopenharmony_ci * @sl: slave to retrieve the power mode
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * Ask the device to get its power mode (external or parasite)
27462306a36Sopenharmony_ci * and store the power status in the &struct w1_therm_family_data.
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci * Return:
27762306a36Sopenharmony_ci * * 0 parasite powered device
27862306a36Sopenharmony_ci * * 1 externally powered device
27962306a36Sopenharmony_ci * * <0 kernel error code
28062306a36Sopenharmony_ci */
28162306a36Sopenharmony_cistatic int read_powermode(struct w1_slave *sl);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/**
28462306a36Sopenharmony_ci * trigger_bulk_read() - function to trigger a bulk read on the bus
28562306a36Sopenharmony_ci * @dev_master: the device master of the bus
28662306a36Sopenharmony_ci *
28762306a36Sopenharmony_ci * Send a SKIP ROM follow by a CONVERT T command on the bus.
28862306a36Sopenharmony_ci * It also set the status flag in each slave &struct w1_therm_family_data
28962306a36Sopenharmony_ci * to signal that a conversion is in progress.
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * Return: 0 if success, -kernel error code otherwise
29262306a36Sopenharmony_ci */
29362306a36Sopenharmony_cistatic int trigger_bulk_read(struct w1_master *dev_master);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/* Sysfs interface declaration */
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic ssize_t w1_slave_show(struct device *device,
29862306a36Sopenharmony_ci	struct device_attribute *attr, char *buf);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic ssize_t w1_slave_store(struct device *device,
30162306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic ssize_t w1_seq_show(struct device *device,
30462306a36Sopenharmony_ci	struct device_attribute *attr, char *buf);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic ssize_t temperature_show(struct device *device,
30762306a36Sopenharmony_ci	struct device_attribute *attr, char *buf);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic ssize_t ext_power_show(struct device *device,
31062306a36Sopenharmony_ci	struct device_attribute *attr, char *buf);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic ssize_t resolution_show(struct device *device,
31362306a36Sopenharmony_ci	struct device_attribute *attr, char *buf);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic ssize_t resolution_store(struct device *device,
31662306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic ssize_t eeprom_cmd_store(struct device *device,
31962306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic ssize_t alarms_store(struct device *device,
32262306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic ssize_t alarms_show(struct device *device,
32562306a36Sopenharmony_ci	struct device_attribute *attr, char *buf);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic ssize_t therm_bulk_read_store(struct device *device,
32862306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic ssize_t therm_bulk_read_show(struct device *device,
33162306a36Sopenharmony_ci	struct device_attribute *attr, char *buf);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic ssize_t conv_time_show(struct device *device,
33462306a36Sopenharmony_ci			      struct device_attribute *attr, char *buf);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic ssize_t conv_time_store(struct device *device,
33762306a36Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
33862306a36Sopenharmony_ci			       size_t size);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic ssize_t features_show(struct device *device,
34162306a36Sopenharmony_ci			      struct device_attribute *attr, char *buf);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic ssize_t features_store(struct device *device,
34462306a36Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
34562306a36Sopenharmony_ci			       size_t size);
34662306a36Sopenharmony_ci/* Attributes declarations */
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(w1_slave);
34962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(w1_seq);
35062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(temperature);
35162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ext_power);
35262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(resolution);
35362306a36Sopenharmony_cistatic DEVICE_ATTR_WO(eeprom_cmd);
35462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(alarms);
35562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(conv_time);
35662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(features);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(therm_bulk_read); /* attribut at master level */
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci/* Interface Functions declaration */
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/**
36362306a36Sopenharmony_ci * w1_therm_add_slave() - Called when a new slave is discovered
36462306a36Sopenharmony_ci * @sl: slave just discovered by the master.
36562306a36Sopenharmony_ci *
36662306a36Sopenharmony_ci * Called by the master when the slave is discovered on the bus. Used to
36762306a36Sopenharmony_ci * initialize slave state before the beginning of any communication.
36862306a36Sopenharmony_ci *
36962306a36Sopenharmony_ci * Return: 0 - If success, negative kernel code otherwise
37062306a36Sopenharmony_ci */
37162306a36Sopenharmony_cistatic int w1_therm_add_slave(struct w1_slave *sl);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/**
37462306a36Sopenharmony_ci * w1_therm_remove_slave() - Called when a slave is removed
37562306a36Sopenharmony_ci * @sl: slave to be removed.
37662306a36Sopenharmony_ci *
37762306a36Sopenharmony_ci * Called by the master when the slave is considered not to be on the bus
37862306a36Sopenharmony_ci * anymore. Used to free memory.
37962306a36Sopenharmony_ci */
38062306a36Sopenharmony_cistatic void w1_therm_remove_slave(struct w1_slave *sl);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci/* Family attributes */
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic struct attribute *w1_therm_attrs[] = {
38562306a36Sopenharmony_ci	&dev_attr_w1_slave.attr,
38662306a36Sopenharmony_ci	&dev_attr_temperature.attr,
38762306a36Sopenharmony_ci	&dev_attr_ext_power.attr,
38862306a36Sopenharmony_ci	&dev_attr_resolution.attr,
38962306a36Sopenharmony_ci	&dev_attr_eeprom_cmd.attr,
39062306a36Sopenharmony_ci	&dev_attr_alarms.attr,
39162306a36Sopenharmony_ci	&dev_attr_conv_time.attr,
39262306a36Sopenharmony_ci	&dev_attr_features.attr,
39362306a36Sopenharmony_ci	NULL,
39462306a36Sopenharmony_ci};
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic struct attribute *w1_ds18s20_attrs[] = {
39762306a36Sopenharmony_ci	&dev_attr_w1_slave.attr,
39862306a36Sopenharmony_ci	&dev_attr_temperature.attr,
39962306a36Sopenharmony_ci	&dev_attr_ext_power.attr,
40062306a36Sopenharmony_ci	&dev_attr_eeprom_cmd.attr,
40162306a36Sopenharmony_ci	&dev_attr_alarms.attr,
40262306a36Sopenharmony_ci	&dev_attr_conv_time.attr,
40362306a36Sopenharmony_ci	&dev_attr_features.attr,
40462306a36Sopenharmony_ci	NULL,
40562306a36Sopenharmony_ci};
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic struct attribute *w1_ds28ea00_attrs[] = {
40862306a36Sopenharmony_ci	&dev_attr_w1_slave.attr,
40962306a36Sopenharmony_ci	&dev_attr_w1_seq.attr,
41062306a36Sopenharmony_ci	&dev_attr_temperature.attr,
41162306a36Sopenharmony_ci	&dev_attr_ext_power.attr,
41262306a36Sopenharmony_ci	&dev_attr_resolution.attr,
41362306a36Sopenharmony_ci	&dev_attr_eeprom_cmd.attr,
41462306a36Sopenharmony_ci	&dev_attr_alarms.attr,
41562306a36Sopenharmony_ci	&dev_attr_conv_time.attr,
41662306a36Sopenharmony_ci	&dev_attr_features.attr,
41762306a36Sopenharmony_ci	NULL,
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci/* Attribute groups */
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ciATTRIBUTE_GROUPS(w1_therm);
42362306a36Sopenharmony_ciATTRIBUTE_GROUPS(w1_ds18s20);
42462306a36Sopenharmony_ciATTRIBUTE_GROUPS(w1_ds28ea00);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_HWMON)
42762306a36Sopenharmony_cistatic int w1_read_temp(struct device *dev, u32 attr, int channel,
42862306a36Sopenharmony_ci			long *val);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic umode_t w1_is_visible(const void *_data, enum hwmon_sensor_types type,
43162306a36Sopenharmony_ci			     u32 attr, int channel)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	return attr == hwmon_temp_input ? 0444 : 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int w1_read(struct device *dev, enum hwmon_sensor_types type,
43762306a36Sopenharmony_ci		   u32 attr, int channel, long *val)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	switch (type) {
44062306a36Sopenharmony_ci	case hwmon_temp:
44162306a36Sopenharmony_ci		return w1_read_temp(dev, attr, channel, val);
44262306a36Sopenharmony_ci	default:
44362306a36Sopenharmony_ci		return -EOPNOTSUPP;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic const u32 w1_temp_config[] = {
44862306a36Sopenharmony_ci	HWMON_T_INPUT,
44962306a36Sopenharmony_ci	0
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic const struct hwmon_channel_info w1_temp = {
45362306a36Sopenharmony_ci	.type = hwmon_temp,
45462306a36Sopenharmony_ci	.config = w1_temp_config,
45562306a36Sopenharmony_ci};
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic const struct hwmon_channel_info * const w1_info[] = {
45862306a36Sopenharmony_ci	&w1_temp,
45962306a36Sopenharmony_ci	NULL
46062306a36Sopenharmony_ci};
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic const struct hwmon_ops w1_hwmon_ops = {
46362306a36Sopenharmony_ci	.is_visible = w1_is_visible,
46462306a36Sopenharmony_ci	.read = w1_read,
46562306a36Sopenharmony_ci};
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic const struct hwmon_chip_info w1_chip_info = {
46862306a36Sopenharmony_ci	.ops = &w1_hwmon_ops,
46962306a36Sopenharmony_ci	.info = w1_info,
47062306a36Sopenharmony_ci};
47162306a36Sopenharmony_ci#define W1_CHIPINFO	(&w1_chip_info)
47262306a36Sopenharmony_ci#else
47362306a36Sopenharmony_ci#define W1_CHIPINFO	NULL
47462306a36Sopenharmony_ci#endif
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/* Family operations */
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic const struct w1_family_ops w1_therm_fops = {
47962306a36Sopenharmony_ci	.add_slave	= w1_therm_add_slave,
48062306a36Sopenharmony_ci	.remove_slave	= w1_therm_remove_slave,
48162306a36Sopenharmony_ci	.groups		= w1_therm_groups,
48262306a36Sopenharmony_ci	.chip_info	= W1_CHIPINFO,
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic const struct w1_family_ops w1_ds18s20_fops = {
48662306a36Sopenharmony_ci	.add_slave	= w1_therm_add_slave,
48762306a36Sopenharmony_ci	.remove_slave	= w1_therm_remove_slave,
48862306a36Sopenharmony_ci	.groups		= w1_ds18s20_groups,
48962306a36Sopenharmony_ci	.chip_info	= W1_CHIPINFO,
49062306a36Sopenharmony_ci};
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic const struct w1_family_ops w1_ds28ea00_fops = {
49362306a36Sopenharmony_ci	.add_slave	= w1_therm_add_slave,
49462306a36Sopenharmony_ci	.remove_slave	= w1_therm_remove_slave,
49562306a36Sopenharmony_ci	.groups		= w1_ds28ea00_groups,
49662306a36Sopenharmony_ci	.chip_info	= W1_CHIPINFO,
49762306a36Sopenharmony_ci};
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/* Family binding operations struct */
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic struct w1_family w1_therm_family_DS18S20 = {
50262306a36Sopenharmony_ci	.fid = W1_THERM_DS18S20,
50362306a36Sopenharmony_ci	.fops = &w1_ds18s20_fops,
50462306a36Sopenharmony_ci};
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic struct w1_family w1_therm_family_DS18B20 = {
50762306a36Sopenharmony_ci	.fid = W1_THERM_DS18B20,
50862306a36Sopenharmony_ci	.fops = &w1_therm_fops,
50962306a36Sopenharmony_ci};
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic struct w1_family w1_therm_family_DS1822 = {
51262306a36Sopenharmony_ci	.fid = W1_THERM_DS1822,
51362306a36Sopenharmony_ci	.fops = &w1_therm_fops,
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic struct w1_family w1_therm_family_DS28EA00 = {
51762306a36Sopenharmony_ci	.fid = W1_THERM_DS28EA00,
51862306a36Sopenharmony_ci	.fops = &w1_ds28ea00_fops,
51962306a36Sopenharmony_ci};
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic struct w1_family w1_therm_family_DS1825 = {
52262306a36Sopenharmony_ci	.fid = W1_THERM_DS1825,
52362306a36Sopenharmony_ci	.fops = &w1_therm_fops,
52462306a36Sopenharmony_ci};
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci/* Device dependent func */
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic inline int w1_DS18B20_convert_time(struct w1_slave *sl)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	int ret;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (!sl->family_data)
53362306a36Sopenharmony_ci		return -ENODEV;	/* device unknown */
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (SLAVE_CONV_TIME_OVERRIDE(sl) != CONV_TIME_DEFAULT)
53662306a36Sopenharmony_ci		return SLAVE_CONV_TIME_OVERRIDE(sl);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/* Return the conversion time, depending on resolution,
53962306a36Sopenharmony_ci	 * select maximum conversion time among all compatible devices
54062306a36Sopenharmony_ci	 */
54162306a36Sopenharmony_ci	switch (SLAVE_RESOLUTION(sl)) {
54262306a36Sopenharmony_ci	case 9:
54362306a36Sopenharmony_ci		ret = 95;
54462306a36Sopenharmony_ci		break;
54562306a36Sopenharmony_ci	case 10:
54662306a36Sopenharmony_ci		ret = 190;
54762306a36Sopenharmony_ci		break;
54862306a36Sopenharmony_ci	case 11:
54962306a36Sopenharmony_ci		ret = 375;
55062306a36Sopenharmony_ci		break;
55162306a36Sopenharmony_ci	case 12:
55262306a36Sopenharmony_ci		ret = 750;
55362306a36Sopenharmony_ci		break;
55462306a36Sopenharmony_ci	case 13:
55562306a36Sopenharmony_ci		ret = 850;  /* GX20MH01 only. Datasheet says 500ms, but that's not enough. */
55662306a36Sopenharmony_ci		break;
55762306a36Sopenharmony_ci	case 14:
55862306a36Sopenharmony_ci		ret = 1600; /* GX20MH01 only. Datasheet says 1000ms - not enough */
55962306a36Sopenharmony_ci		break;
56062306a36Sopenharmony_ci	default:
56162306a36Sopenharmony_ci		ret = 750;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci	return ret;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic inline int w1_DS18S20_convert_time(struct w1_slave *sl)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	if (!sl->family_data)
56962306a36Sopenharmony_ci		return -ENODEV;	/* device unknown */
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (SLAVE_CONV_TIME_OVERRIDE(sl) == CONV_TIME_DEFAULT)
57262306a36Sopenharmony_ci		return 750; /* default for DS18S20 */
57362306a36Sopenharmony_ci	else
57462306a36Sopenharmony_ci		return SLAVE_CONV_TIME_OVERRIDE(sl);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic inline int w1_DS1825_convert_time(struct w1_slave *sl)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	int ret;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (!sl->family_data)
58262306a36Sopenharmony_ci		return -ENODEV;	/* device unknown */
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (SLAVE_CONV_TIME_OVERRIDE(sl) != CONV_TIME_DEFAULT)
58562306a36Sopenharmony_ci		return SLAVE_CONV_TIME_OVERRIDE(sl);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* Return the conversion time, depending on resolution,
58862306a36Sopenharmony_ci	 * select maximum conversion time among all compatible devices
58962306a36Sopenharmony_ci	 */
59062306a36Sopenharmony_ci	switch (SLAVE_RESOLUTION(sl)) {
59162306a36Sopenharmony_ci	case 9:
59262306a36Sopenharmony_ci		ret = 95;
59362306a36Sopenharmony_ci		break;
59462306a36Sopenharmony_ci	case 10:
59562306a36Sopenharmony_ci		ret = 190;
59662306a36Sopenharmony_ci		break;
59762306a36Sopenharmony_ci	case 11:
59862306a36Sopenharmony_ci		ret = 375;
59962306a36Sopenharmony_ci		break;
60062306a36Sopenharmony_ci	case 12:
60162306a36Sopenharmony_ci		ret = 750;
60262306a36Sopenharmony_ci		break;
60362306a36Sopenharmony_ci	case 14:
60462306a36Sopenharmony_ci		ret = 100; /* MAX31850 only. Datasheet says 100ms  */
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci	default:
60762306a36Sopenharmony_ci		ret = 750;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci	return ret;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic inline int w1_DS18B20_write_data(struct w1_slave *sl,
61362306a36Sopenharmony_ci				const u8 *data)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	return write_scratchpad(sl, data, 3);
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cistatic inline int w1_DS18S20_write_data(struct w1_slave *sl,
61962306a36Sopenharmony_ci				const u8 *data)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	/* No config register */
62262306a36Sopenharmony_ci	return write_scratchpad(sl, data, 2);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic inline int w1_DS18B20_set_resolution(struct w1_slave *sl, int val)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	int ret;
62862306a36Sopenharmony_ci	struct therm_info info, info2;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* DS18B20 resolution is 9 to 12 bits */
63162306a36Sopenharmony_ci	/* GX20MH01 resolution is 9 to 14 bits */
63262306a36Sopenharmony_ci	/* MAX31850 resolution is fixed 14 bits */
63362306a36Sopenharmony_ci	if (val < W1_THERM_RESOLUTION_MIN || val > W1_THERM_RESOLUTION_MAX)
63462306a36Sopenharmony_ci		return -EINVAL;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* Calc bit value from resolution */
63762306a36Sopenharmony_ci	val = (val - W1_THERM_RESOLUTION_MIN) << W1_THERM_RESOLUTION_SHIFT;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	/*
64062306a36Sopenharmony_ci	 * Read the scratchpad to change only the required bits
64162306a36Sopenharmony_ci	 * (bit5 & bit 6 from byte 4)
64262306a36Sopenharmony_ci	 */
64362306a36Sopenharmony_ci	ret = read_scratchpad(sl, &info);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (ret)
64662306a36Sopenharmony_ci		return ret;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	info.rom[4] &= ~W1_THERM_RESOLUTION_MASK;
65062306a36Sopenharmony_ci	info.rom[4] |= val;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Write data in the device RAM */
65362306a36Sopenharmony_ci	ret = w1_DS18B20_write_data(sl, info.rom + 2);
65462306a36Sopenharmony_ci	if (ret)
65562306a36Sopenharmony_ci		return ret;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* Have to read back the resolution to verify an actual value
65862306a36Sopenharmony_ci	 * GX20MH01 and DS18B20 are indistinguishable by family number, but resolutions differ
65962306a36Sopenharmony_ci	 * Some DS18B20 clones don't support resolution change
66062306a36Sopenharmony_ci	 */
66162306a36Sopenharmony_ci	ret = read_scratchpad(sl, &info2);
66262306a36Sopenharmony_ci	if (ret)
66362306a36Sopenharmony_ci		/* Scratchpad read fail */
66462306a36Sopenharmony_ci		return ret;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if ((info2.rom[4] & W1_THERM_RESOLUTION_MASK) == (info.rom[4] & W1_THERM_RESOLUTION_MASK))
66762306a36Sopenharmony_ci		return 0;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/* Resolution verify error */
67062306a36Sopenharmony_ci	return -EIO;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic inline int w1_DS18B20_get_resolution(struct w1_slave *sl)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	int ret;
67662306a36Sopenharmony_ci	int resolution;
67762306a36Sopenharmony_ci	struct therm_info info;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	ret = read_scratchpad(sl, &info);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (ret)
68262306a36Sopenharmony_ci		return ret;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	resolution = ((info.rom[4] & W1_THERM_RESOLUTION_MASK) >> W1_THERM_RESOLUTION_SHIFT)
68562306a36Sopenharmony_ci		+ W1_THERM_RESOLUTION_MIN;
68662306a36Sopenharmony_ci	/* GX20MH01 has one special case:
68762306a36Sopenharmony_ci	 *   >=14 means 14 bits when getting resolution from bit value.
68862306a36Sopenharmony_ci	 * MAX31850 delivers fixed 15 and has 14 bits.
68962306a36Sopenharmony_ci	 * Other devices have no more then 12 bits.
69062306a36Sopenharmony_ci	 */
69162306a36Sopenharmony_ci	if (resolution > W1_THERM_RESOLUTION_MAX)
69262306a36Sopenharmony_ci		resolution = W1_THERM_RESOLUTION_MAX;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return resolution;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci/**
69862306a36Sopenharmony_ci * w1_DS18B20_convert_temp() - temperature computation for DS18B20
69962306a36Sopenharmony_ci * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
70062306a36Sopenharmony_ci *
70162306a36Sopenharmony_ci * Can be called for any DS18B20 compliant device.
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * Return: value in millidegrees Celsius.
70462306a36Sopenharmony_ci */
70562306a36Sopenharmony_cistatic inline int w1_DS18B20_convert_temp(u8 rom[9])
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	u16 bv;
70862306a36Sopenharmony_ci	s16 t;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	/* Signed 16-bit value to unsigned, cpu order */
71162306a36Sopenharmony_ci	bv = le16_to_cpup((__le16 *)rom);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* Config register bit R2 = 1 - GX20MH01 in 13 or 14 bit resolution mode */
71462306a36Sopenharmony_ci	if (rom[4] & 0x80) {
71562306a36Sopenharmony_ci		/* Insert two temperature bits from config register */
71662306a36Sopenharmony_ci		/* Avoid arithmetic shift of signed value */
71762306a36Sopenharmony_ci		bv = (bv << 2) | (rom[4] & 3);
71862306a36Sopenharmony_ci		t = (s16) bv;	/* Degrees, lowest bit is 2^-6 */
71962306a36Sopenharmony_ci		return (int)t * 1000 / 64;	/* Sign-extend to int; millidegrees */
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci	t = (s16)bv;	/* Degrees, lowest bit is 2^-4 */
72262306a36Sopenharmony_ci	return (int)t * 1000 / 16;	/* Sign-extend to int; millidegrees */
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci/**
72662306a36Sopenharmony_ci * w1_DS18S20_convert_temp() - temperature computation for DS18S20
72762306a36Sopenharmony_ci * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
72862306a36Sopenharmony_ci *
72962306a36Sopenharmony_ci * Can be called for any DS18S20 compliant device.
73062306a36Sopenharmony_ci *
73162306a36Sopenharmony_ci * Return: value in millidegrees Celsius.
73262306a36Sopenharmony_ci */
73362306a36Sopenharmony_cistatic inline int w1_DS18S20_convert_temp(u8 rom[9])
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	int t, h;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	if (!rom[7]) {
73862306a36Sopenharmony_ci		pr_debug("%s: Invalid argument for conversion\n", __func__);
73962306a36Sopenharmony_ci		return 0;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (rom[1] == 0)
74362306a36Sopenharmony_ci		t = ((s32)rom[0] >> 1)*1000;
74462306a36Sopenharmony_ci	else
74562306a36Sopenharmony_ci		t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	t -= 250;
74862306a36Sopenharmony_ci	h = 1000*((s32)rom[7] - (s32)rom[6]);
74962306a36Sopenharmony_ci	h /= (s32)rom[7];
75062306a36Sopenharmony_ci	t += h;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	return t;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/**
75662306a36Sopenharmony_ci * w1_DS1825_convert_temp() - temperature computation for DS1825
75762306a36Sopenharmony_ci * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
75862306a36Sopenharmony_ci *
75962306a36Sopenharmony_ci * Can be called for any DS1825 compliant device.
76062306a36Sopenharmony_ci * Is used by MAX31850, too
76162306a36Sopenharmony_ci *
76262306a36Sopenharmony_ci * Return: value in millidegrees Celsius.
76362306a36Sopenharmony_ci */
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cistatic inline int w1_DS1825_convert_temp(u8 rom[9])
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	u16 bv;
76862306a36Sopenharmony_ci	s16 t;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	/* Signed 16-bit value to unsigned, cpu order */
77162306a36Sopenharmony_ci	bv = le16_to_cpup((__le16 *)rom);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	/* Config register bit 7 = 1 - MA31850 found, 14 bit resolution */
77462306a36Sopenharmony_ci	if (rom[4] & 0x80) {
77562306a36Sopenharmony_ci		/* Mask out bits 0 (Fault) and 1 (Reserved) */
77662306a36Sopenharmony_ci		/* Avoid arithmetic shift of signed value */
77762306a36Sopenharmony_ci		bv = (bv & 0xFFFC); /* Degrees, lowest 4 bits are 2^-1, 2^-2 and 2 zero bits */
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci	t = (s16)bv;	/* Degrees, lowest bit is 2^-4 */
78062306a36Sopenharmony_ci	return (int)t * 1000 / 16;	/* Sign-extend to int; millidegrees */
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci/* Device capability description */
78462306a36Sopenharmony_ci/* GX20MH01 device shares family number and structure with DS18B20 */
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic struct w1_therm_family_converter w1_therm_families[] = {
78762306a36Sopenharmony_ci	{
78862306a36Sopenharmony_ci		.f				= &w1_therm_family_DS18S20,
78962306a36Sopenharmony_ci		.convert			= w1_DS18S20_convert_temp,
79062306a36Sopenharmony_ci		.get_conversion_time	= w1_DS18S20_convert_time,
79162306a36Sopenharmony_ci		.set_resolution		= NULL,	/* no config register */
79262306a36Sopenharmony_ci		.get_resolution		= NULL,	/* no config register */
79362306a36Sopenharmony_ci		.write_data			= w1_DS18S20_write_data,
79462306a36Sopenharmony_ci		.bulk_read			= true
79562306a36Sopenharmony_ci	},
79662306a36Sopenharmony_ci	{
79762306a36Sopenharmony_ci		.f				= &w1_therm_family_DS1822,
79862306a36Sopenharmony_ci		.convert			= w1_DS18B20_convert_temp,
79962306a36Sopenharmony_ci		.get_conversion_time	= w1_DS18B20_convert_time,
80062306a36Sopenharmony_ci		.set_resolution		= w1_DS18B20_set_resolution,
80162306a36Sopenharmony_ci		.get_resolution		= w1_DS18B20_get_resolution,
80262306a36Sopenharmony_ci		.write_data			= w1_DS18B20_write_data,
80362306a36Sopenharmony_ci		.bulk_read			= true
80462306a36Sopenharmony_ci	},
80562306a36Sopenharmony_ci	{
80662306a36Sopenharmony_ci		/* Also used for GX20MH01 */
80762306a36Sopenharmony_ci		.f				= &w1_therm_family_DS18B20,
80862306a36Sopenharmony_ci		.convert			= w1_DS18B20_convert_temp,
80962306a36Sopenharmony_ci		.get_conversion_time	= w1_DS18B20_convert_time,
81062306a36Sopenharmony_ci		.set_resolution		= w1_DS18B20_set_resolution,
81162306a36Sopenharmony_ci		.get_resolution		= w1_DS18B20_get_resolution,
81262306a36Sopenharmony_ci		.write_data			= w1_DS18B20_write_data,
81362306a36Sopenharmony_ci		.bulk_read			= true
81462306a36Sopenharmony_ci	},
81562306a36Sopenharmony_ci	{
81662306a36Sopenharmony_ci		.f				= &w1_therm_family_DS28EA00,
81762306a36Sopenharmony_ci		.convert			= w1_DS18B20_convert_temp,
81862306a36Sopenharmony_ci		.get_conversion_time	= w1_DS18B20_convert_time,
81962306a36Sopenharmony_ci		.set_resolution		= w1_DS18B20_set_resolution,
82062306a36Sopenharmony_ci		.get_resolution		= w1_DS18B20_get_resolution,
82162306a36Sopenharmony_ci		.write_data			= w1_DS18B20_write_data,
82262306a36Sopenharmony_ci		.bulk_read			= false
82362306a36Sopenharmony_ci	},
82462306a36Sopenharmony_ci	{
82562306a36Sopenharmony_ci		/* Also used for MAX31850 */
82662306a36Sopenharmony_ci		.f				= &w1_therm_family_DS1825,
82762306a36Sopenharmony_ci		.convert			= w1_DS1825_convert_temp,
82862306a36Sopenharmony_ci		.get_conversion_time	= w1_DS1825_convert_time,
82962306a36Sopenharmony_ci		.set_resolution		= w1_DS18B20_set_resolution,
83062306a36Sopenharmony_ci		.get_resolution		= w1_DS18B20_get_resolution,
83162306a36Sopenharmony_ci		.write_data			= w1_DS18B20_write_data,
83262306a36Sopenharmony_ci		.bulk_read			= true
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci};
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci/* Helpers Functions */
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci/**
83962306a36Sopenharmony_ci * device_family() - Retrieve a pointer on &struct w1_therm_family_converter
84062306a36Sopenharmony_ci * @sl: slave to retrieve the device specific structure
84162306a36Sopenharmony_ci *
84262306a36Sopenharmony_ci * Return: pointer to the slaves's family converter, NULL if not known
84362306a36Sopenharmony_ci */
84462306a36Sopenharmony_cistatic struct w1_therm_family_converter *device_family(struct w1_slave *sl)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct w1_therm_family_converter *ret = NULL;
84762306a36Sopenharmony_ci	int i;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
85062306a36Sopenharmony_ci		if (w1_therm_families[i].f->fid == sl->family->fid) {
85162306a36Sopenharmony_ci			ret = &w1_therm_families[i];
85262306a36Sopenharmony_ci			break;
85362306a36Sopenharmony_ci		}
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci	return ret;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/**
85962306a36Sopenharmony_ci * bus_mutex_lock() - Acquire the mutex
86062306a36Sopenharmony_ci * @lock: w1 bus mutex to acquire
86162306a36Sopenharmony_ci *
86262306a36Sopenharmony_ci * It try to acquire the mutex W1_THERM_MAX_TRY times and wait
86362306a36Sopenharmony_ci * W1_THERM_RETRY_DELAY between 2 attempts.
86462306a36Sopenharmony_ci *
86562306a36Sopenharmony_ci * Return: true is mutex is acquired and lock, false otherwise
86662306a36Sopenharmony_ci */
86762306a36Sopenharmony_cistatic inline bool bus_mutex_lock(struct mutex *lock)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/* try to acquire the mutex, if not, sleep retry_delay before retry) */
87262306a36Sopenharmony_ci	while (mutex_lock_interruptible(lock) != 0 && max_trying > 0) {
87362306a36Sopenharmony_ci		unsigned long sleep_rem;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		sleep_rem = msleep_interruptible(W1_THERM_RETRY_DELAY);
87662306a36Sopenharmony_ci		if (!sleep_rem)
87762306a36Sopenharmony_ci			max_trying--;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	if (!max_trying)
88162306a36Sopenharmony_ci		return false;	/* Didn't acquire the bus mutex */
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	return true;
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci/**
88762306a36Sopenharmony_ci * check_family_data() - Check if family data and specific functions are present
88862306a36Sopenharmony_ci * @sl: W1 device data
88962306a36Sopenharmony_ci *
89062306a36Sopenharmony_ci * Return: 0 - OK, negative value - error
89162306a36Sopenharmony_ci */
89262306a36Sopenharmony_cistatic int check_family_data(struct w1_slave *sl)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
89562306a36Sopenharmony_ci		dev_info(&sl->dev,
89662306a36Sopenharmony_ci			 "%s: Device is not supported by the driver\n", __func__);
89762306a36Sopenharmony_ci		return -EINVAL;  /* No device family */
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci	return 0;
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci/**
90362306a36Sopenharmony_ci * bulk_read_support() - check if slave support bulk read
90462306a36Sopenharmony_ci * @sl: device to check the ability
90562306a36Sopenharmony_ci *
90662306a36Sopenharmony_ci * Return: true if bulk read is supported, false if not or error
90762306a36Sopenharmony_ci */
90862306a36Sopenharmony_cistatic inline bool bulk_read_support(struct w1_slave *sl)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	if (SLAVE_SPECIFIC_FUNC(sl))
91162306a36Sopenharmony_ci		return SLAVE_SPECIFIC_FUNC(sl)->bulk_read;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	dev_info(&sl->dev,
91462306a36Sopenharmony_ci		"%s: Device not supported by the driver\n", __func__);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	return false;  /* No device family */
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci/**
92062306a36Sopenharmony_ci * conversion_time() - get the Tconv for the slave
92162306a36Sopenharmony_ci * @sl: device to get the conversion time
92262306a36Sopenharmony_ci *
92362306a36Sopenharmony_ci * On device supporting resolution settings, conversion time depend
92462306a36Sopenharmony_ci * on the resolution setting. This helper function get the slave timing,
92562306a36Sopenharmony_ci * depending on its current setting.
92662306a36Sopenharmony_ci *
92762306a36Sopenharmony_ci * Return: conversion time in ms, negative values are kernel error code
92862306a36Sopenharmony_ci */
92962306a36Sopenharmony_cistatic inline int conversion_time(struct w1_slave *sl)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	if (SLAVE_SPECIFIC_FUNC(sl))
93262306a36Sopenharmony_ci		return SLAVE_SPECIFIC_FUNC(sl)->get_conversion_time(sl);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	dev_info(&sl->dev,
93562306a36Sopenharmony_ci		"%s: Device not supported by the driver\n", __func__);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	return -ENODEV;  /* No device family */
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci/**
94162306a36Sopenharmony_ci * temperature_from_RAM() - Convert the read info to temperature
94262306a36Sopenharmony_ci * @sl: device that sent the RAM data
94362306a36Sopenharmony_ci * @rom: read value on the slave device RAM
94462306a36Sopenharmony_ci *
94562306a36Sopenharmony_ci * Device dependent, the function bind the correct computation method.
94662306a36Sopenharmony_ci *
94762306a36Sopenharmony_ci * Return: temperature in 1/1000degC, 0 on error.
94862306a36Sopenharmony_ci */
94962306a36Sopenharmony_cistatic inline int temperature_from_RAM(struct w1_slave *sl, u8 rom[9])
95062306a36Sopenharmony_ci{
95162306a36Sopenharmony_ci	if (SLAVE_SPECIFIC_FUNC(sl))
95262306a36Sopenharmony_ci		return SLAVE_SPECIFIC_FUNC(sl)->convert(rom);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	dev_info(&sl->dev,
95562306a36Sopenharmony_ci		"%s: Device not supported by the driver\n", __func__);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	return 0;  /* No device family */
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci/**
96162306a36Sopenharmony_ci * int_to_short() - Safe casting of int to short
96262306a36Sopenharmony_ci *
96362306a36Sopenharmony_ci * @i: integer to be converted to short
96462306a36Sopenharmony_ci *
96562306a36Sopenharmony_ci * Device register use 1 byte to store signed integer.
96662306a36Sopenharmony_ci * This helper function convert the int in a signed short,
96762306a36Sopenharmony_ci * using the min/max values that device can measure as limits.
96862306a36Sopenharmony_ci * min/max values are defined by macro.
96962306a36Sopenharmony_ci *
97062306a36Sopenharmony_ci * Return: a short in the range of min/max value
97162306a36Sopenharmony_ci */
97262306a36Sopenharmony_cistatic inline s8 int_to_short(int i)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	/* Prepare to cast to short by eliminating out of range values */
97562306a36Sopenharmony_ci	i = clamp(i, MIN_TEMP, MAX_TEMP);
97662306a36Sopenharmony_ci	return (s8) i;
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci/* Interface Functions */
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic int w1_therm_add_slave(struct w1_slave *sl)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct w1_therm_family_converter *sl_family_conv;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* Allocate memory */
98662306a36Sopenharmony_ci	sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
98762306a36Sopenharmony_ci		GFP_KERNEL);
98862306a36Sopenharmony_ci	if (!sl->family_data)
98962306a36Sopenharmony_ci		return -ENOMEM;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	atomic_set(THERM_REFCNT(sl->family_data), 1);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/* Get a pointer to the device specific function struct */
99462306a36Sopenharmony_ci	sl_family_conv = device_family(sl);
99562306a36Sopenharmony_ci	if (!sl_family_conv) {
99662306a36Sopenharmony_ci		kfree(sl->family_data);
99762306a36Sopenharmony_ci		return -ENODEV;
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci	/* save this pointer to the device structure */
100062306a36Sopenharmony_ci	SLAVE_SPECIFIC_FUNC(sl) = sl_family_conv;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	if (bulk_read_support(sl)) {
100362306a36Sopenharmony_ci		/*
100462306a36Sopenharmony_ci		 * add the sys entry to trigger bulk_read
100562306a36Sopenharmony_ci		 * at master level only the 1st time
100662306a36Sopenharmony_ci		 */
100762306a36Sopenharmony_ci		if (!bulk_read_device_counter) {
100862306a36Sopenharmony_ci			int err = device_create_file(&sl->master->dev,
100962306a36Sopenharmony_ci				&dev_attr_therm_bulk_read);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci			if (err)
101262306a36Sopenharmony_ci				dev_warn(&sl->dev,
101362306a36Sopenharmony_ci				"%s: Device has been added, but bulk read is unavailable. err=%d\n",
101462306a36Sopenharmony_ci				__func__, err);
101562306a36Sopenharmony_ci		}
101662306a36Sopenharmony_ci		/* Increment the counter */
101762306a36Sopenharmony_ci		bulk_read_device_counter++;
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	/* Getting the power mode of the device {external, parasite} */
102162306a36Sopenharmony_ci	SLAVE_POWERMODE(sl) = read_powermode(sl);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (SLAVE_POWERMODE(sl) < 0) {
102462306a36Sopenharmony_ci		/* no error returned as device has been added */
102562306a36Sopenharmony_ci		dev_warn(&sl->dev,
102662306a36Sopenharmony_ci			"%s: Device has been added, but power_mode may be corrupted. err=%d\n",
102762306a36Sopenharmony_ci			 __func__, SLAVE_POWERMODE(sl));
102862306a36Sopenharmony_ci	}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	/* Getting the resolution of the device */
103162306a36Sopenharmony_ci	if (SLAVE_SPECIFIC_FUNC(sl)->get_resolution) {
103262306a36Sopenharmony_ci		SLAVE_RESOLUTION(sl) =
103362306a36Sopenharmony_ci			SLAVE_SPECIFIC_FUNC(sl)->get_resolution(sl);
103462306a36Sopenharmony_ci		if (SLAVE_RESOLUTION(sl) < 0) {
103562306a36Sopenharmony_ci			/* no error returned as device has been added */
103662306a36Sopenharmony_ci			dev_warn(&sl->dev,
103762306a36Sopenharmony_ci				"%s:Device has been added, but resolution may be corrupted. err=%d\n",
103862306a36Sopenharmony_ci				__func__, SLAVE_RESOLUTION(sl));
103962306a36Sopenharmony_ci		}
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	/* Finally initialize convert_triggered flag */
104362306a36Sopenharmony_ci	SLAVE_CONVERT_TRIGGERED(sl) = 0;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	return 0;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic void w1_therm_remove_slave(struct w1_slave *sl)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (bulk_read_support(sl)) {
105362306a36Sopenharmony_ci		bulk_read_device_counter--;
105462306a36Sopenharmony_ci		/* Delete the entry if no more device support the feature */
105562306a36Sopenharmony_ci		if (!bulk_read_device_counter)
105662306a36Sopenharmony_ci			device_remove_file(&sl->master->dev,
105762306a36Sopenharmony_ci				&dev_attr_therm_bulk_read);
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	while (refcnt) {
106162306a36Sopenharmony_ci		msleep(1000);
106262306a36Sopenharmony_ci		refcnt = atomic_read(THERM_REFCNT(sl->family_data));
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci	kfree(sl->family_data);
106562306a36Sopenharmony_ci	sl->family_data = NULL;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci/* Hardware Functions */
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci/* Safe version of reset_select_slave - avoid using the one in w_io.c */
107162306a36Sopenharmony_cistatic int reset_select_slave(struct w1_slave *sl)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	u8 match[9] = { W1_MATCH_ROM, };
107462306a36Sopenharmony_ci	u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (w1_reset_bus(sl->master))
107762306a36Sopenharmony_ci		return -ENODEV;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	memcpy(&match[1], &rn, 8);
108062306a36Sopenharmony_ci	w1_write_block(sl->master, match, 9);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	return 0;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci/**
108662306a36Sopenharmony_ci * w1_poll_completion - Poll for operation completion, with timeout
108762306a36Sopenharmony_ci * @dev_master: the device master of the bus
108862306a36Sopenharmony_ci * @tout_ms: timeout in milliseconds
108962306a36Sopenharmony_ci *
109062306a36Sopenharmony_ci * The device is answering 0's while an operation is in progress and 1's after it completes
109162306a36Sopenharmony_ci * Timeout may happen if the previous command was not recognised due to a line noise
109262306a36Sopenharmony_ci *
109362306a36Sopenharmony_ci * Return: 0 - OK, negative error - timeout
109462306a36Sopenharmony_ci */
109562306a36Sopenharmony_cistatic int w1_poll_completion(struct w1_master *dev_master, int tout_ms)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	int i;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	for (i = 0; i < tout_ms/W1_POLL_PERIOD; i++) {
110062306a36Sopenharmony_ci		/* Delay is before poll, for device to recognize a command */
110162306a36Sopenharmony_ci		msleep(W1_POLL_PERIOD);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		/* Compare all 8 bits to mitigate a noise on the bus */
110462306a36Sopenharmony_ci		if (w1_read_8(dev_master) == 0xFF)
110562306a36Sopenharmony_ci			break;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci	if (i == tout_ms/W1_POLL_PERIOD)
110862306a36Sopenharmony_ci		return -EIO;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	return 0;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int convert_t(struct w1_slave *sl, struct therm_info *info)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct w1_master *dev_master = sl->master;
111662306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
111762306a36Sopenharmony_ci	int t_conv;
111862306a36Sopenharmony_ci	int ret = -ENODEV;
111962306a36Sopenharmony_ci	bool strong_pullup;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	if (!sl->family_data)
112262306a36Sopenharmony_ci		goto error;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	strong_pullup = (w1_strong_pullup == 2 ||
112562306a36Sopenharmony_ci					(!SLAVE_POWERMODE(sl) &&
112662306a36Sopenharmony_ci					w1_strong_pullup));
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (strong_pullup && SLAVE_FEATURES(sl) & W1_THERM_POLL_COMPLETION) {
112962306a36Sopenharmony_ci		dev_warn(&sl->dev,
113062306a36Sopenharmony_ci			"%s: Disabling W1_THERM_POLL_COMPLETION in parasite power mode.\n",
113162306a36Sopenharmony_ci			__func__);
113262306a36Sopenharmony_ci		SLAVE_FEATURES(sl) &= ~W1_THERM_POLL_COMPLETION;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	/* get conversion duration device and id dependent */
113662306a36Sopenharmony_ci	t_conv = conversion_time(sl);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	memset(info->rom, 0, sizeof(info->rom));
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/* prevent the slave from going away in sleep */
114162306a36Sopenharmony_ci	atomic_inc(THERM_REFCNT(sl->family_data));
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
114462306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
114562306a36Sopenharmony_ci		goto dec_refcnt;
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	while (max_trying-- && ret) { /* ret should be 0 */
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci		info->verdict = 0;
115162306a36Sopenharmony_ci		info->crc = 0;
115262306a36Sopenharmony_ci		/* safe version to select slave */
115362306a36Sopenharmony_ci		if (!reset_select_slave(sl)) {
115462306a36Sopenharmony_ci			unsigned long sleep_rem;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci			/* 750ms strong pullup (or delay) after the convert */
115762306a36Sopenharmony_ci			if (strong_pullup)
115862306a36Sopenharmony_ci				w1_next_pullup(dev_master, t_conv);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci			w1_write_8(dev_master, W1_CONVERT_TEMP);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci			if (SLAVE_FEATURES(sl) & W1_THERM_POLL_COMPLETION) {
116362306a36Sopenharmony_ci				ret = w1_poll_completion(dev_master, W1_POLL_CONVERT_TEMP);
116462306a36Sopenharmony_ci				if (ret) {
116562306a36Sopenharmony_ci					dev_dbg(&sl->dev, "%s: Timeout\n", __func__);
116662306a36Sopenharmony_ci					goto mt_unlock;
116762306a36Sopenharmony_ci				}
116862306a36Sopenharmony_ci				mutex_unlock(&dev_master->bus_mutex);
116962306a36Sopenharmony_ci			} else if (!strong_pullup) { /*no device need pullup */
117062306a36Sopenharmony_ci				sleep_rem = msleep_interruptible(t_conv);
117162306a36Sopenharmony_ci				if (sleep_rem != 0) {
117262306a36Sopenharmony_ci					ret = -EINTR;
117362306a36Sopenharmony_ci					goto mt_unlock;
117462306a36Sopenharmony_ci				}
117562306a36Sopenharmony_ci				mutex_unlock(&dev_master->bus_mutex);
117662306a36Sopenharmony_ci			} else { /*some device need pullup */
117762306a36Sopenharmony_ci				mutex_unlock(&dev_master->bus_mutex);
117862306a36Sopenharmony_ci				sleep_rem = msleep_interruptible(t_conv);
117962306a36Sopenharmony_ci				if (sleep_rem != 0) {
118062306a36Sopenharmony_ci					ret = -EINTR;
118162306a36Sopenharmony_ci					goto dec_refcnt;
118262306a36Sopenharmony_ci				}
118362306a36Sopenharmony_ci			}
118462306a36Sopenharmony_ci			ret = read_scratchpad(sl, info);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci			/* If enabled, check for conversion success */
118762306a36Sopenharmony_ci			if ((SLAVE_FEATURES(sl) & W1_THERM_CHECK_RESULT) &&
118862306a36Sopenharmony_ci				(info->rom[6] == 0xC) &&
118962306a36Sopenharmony_ci				((info->rom[1] == 0x5 && info->rom[0] == 0x50) ||
119062306a36Sopenharmony_ci				(info->rom[1] == 0x7 && info->rom[0] == 0xFF))
119162306a36Sopenharmony_ci			) {
119262306a36Sopenharmony_ci				/* Invalid reading (scratchpad byte 6 = 0xC)
119362306a36Sopenharmony_ci				 * due to insufficient conversion time
119462306a36Sopenharmony_ci				 * or power failure.
119562306a36Sopenharmony_ci				 */
119662306a36Sopenharmony_ci				ret = -EIO;
119762306a36Sopenharmony_ci			}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci			goto dec_refcnt;
120062306a36Sopenharmony_ci		}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_cimt_unlock:
120562306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
120662306a36Sopenharmony_cidec_refcnt:
120762306a36Sopenharmony_ci	atomic_dec(THERM_REFCNT(sl->family_data));
120862306a36Sopenharmony_cierror:
120962306a36Sopenharmony_ci	return ret;
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_cistatic int conv_time_measure(struct w1_slave *sl, int *conv_time)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	struct therm_info inf,
121562306a36Sopenharmony_ci		*info = &inf;
121662306a36Sopenharmony_ci	struct w1_master *dev_master = sl->master;
121762306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
121862306a36Sopenharmony_ci	int ret = -ENODEV;
121962306a36Sopenharmony_ci	bool strong_pullup;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (!sl->family_data)
122262306a36Sopenharmony_ci		goto error;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	strong_pullup = (w1_strong_pullup == 2 ||
122562306a36Sopenharmony_ci		(!SLAVE_POWERMODE(sl) &&
122662306a36Sopenharmony_ci		w1_strong_pullup));
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (strong_pullup) {
122962306a36Sopenharmony_ci		pr_info("%s: Measure with strong_pullup is not supported.\n", __func__);
123062306a36Sopenharmony_ci		return -EINVAL;
123162306a36Sopenharmony_ci	}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	memset(info->rom, 0, sizeof(info->rom));
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	/* prevent the slave from going away in sleep */
123662306a36Sopenharmony_ci	atomic_inc(THERM_REFCNT(sl->family_data));
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
123962306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
124062306a36Sopenharmony_ci		goto dec_refcnt;
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	while (max_trying-- && ret) { /* ret should be 0 */
124462306a36Sopenharmony_ci		info->verdict = 0;
124562306a36Sopenharmony_ci		info->crc = 0;
124662306a36Sopenharmony_ci		/* safe version to select slave */
124762306a36Sopenharmony_ci		if (!reset_select_slave(sl)) {
124862306a36Sopenharmony_ci			int j_start, j_end;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci			/*no device need pullup */
125162306a36Sopenharmony_ci			w1_write_8(dev_master, W1_CONVERT_TEMP);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci			j_start = jiffies;
125462306a36Sopenharmony_ci			ret = w1_poll_completion(dev_master, W1_POLL_CONVERT_TEMP);
125562306a36Sopenharmony_ci			if (ret) {
125662306a36Sopenharmony_ci				dev_dbg(&sl->dev, "%s: Timeout\n", __func__);
125762306a36Sopenharmony_ci				goto mt_unlock;
125862306a36Sopenharmony_ci			}
125962306a36Sopenharmony_ci			j_end = jiffies;
126062306a36Sopenharmony_ci			/* 1.2x increase for variation and changes over temperature range */
126162306a36Sopenharmony_ci			*conv_time = jiffies_to_msecs(j_end-j_start)*12/10;
126262306a36Sopenharmony_ci			pr_debug("W1 Measure complete, conv_time = %d, HZ=%d.\n",
126362306a36Sopenharmony_ci				*conv_time, HZ);
126462306a36Sopenharmony_ci			if (*conv_time <= CONV_TIME_MEASURE) {
126562306a36Sopenharmony_ci				ret = -EIO;
126662306a36Sopenharmony_ci				goto mt_unlock;
126762306a36Sopenharmony_ci			}
126862306a36Sopenharmony_ci			mutex_unlock(&dev_master->bus_mutex);
126962306a36Sopenharmony_ci			ret = read_scratchpad(sl, info);
127062306a36Sopenharmony_ci			goto dec_refcnt;
127162306a36Sopenharmony_ci		}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_cimt_unlock:
127562306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
127662306a36Sopenharmony_cidec_refcnt:
127762306a36Sopenharmony_ci	atomic_dec(THERM_REFCNT(sl->family_data));
127862306a36Sopenharmony_cierror:
127962306a36Sopenharmony_ci	return ret;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int read_scratchpad(struct w1_slave *sl, struct therm_info *info)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	struct w1_master *dev_master = sl->master;
128562306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
128662306a36Sopenharmony_ci	int ret = -ENODEV;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	info->verdict = 0;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	if (!sl->family_data)
129162306a36Sopenharmony_ci		goto error;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	memset(info->rom, 0, sizeof(info->rom));
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	/* prevent the slave from going away in sleep */
129662306a36Sopenharmony_ci	atomic_inc(THERM_REFCNT(sl->family_data));
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
129962306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
130062306a36Sopenharmony_ci		goto dec_refcnt;
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	while (max_trying-- && ret) { /* ret should be 0 */
130462306a36Sopenharmony_ci		/* safe version to select slave */
130562306a36Sopenharmony_ci		if (!reset_select_slave(sl)) {
130662306a36Sopenharmony_ci			u8 nb_bytes_read;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci			w1_write_8(dev_master, W1_READ_SCRATCHPAD);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci			nb_bytes_read = w1_read_block(dev_master, info->rom, 9);
131162306a36Sopenharmony_ci			if (nb_bytes_read != 9) {
131262306a36Sopenharmony_ci				dev_warn(&sl->dev,
131362306a36Sopenharmony_ci					"w1_read_block(): returned %u instead of 9.\n",
131462306a36Sopenharmony_ci					nb_bytes_read);
131562306a36Sopenharmony_ci				ret = -EIO;
131662306a36Sopenharmony_ci			}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci			info->crc = w1_calc_crc8(info->rom, 8);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci			if (info->rom[8] == info->crc) {
132162306a36Sopenharmony_ci				info->verdict = 1;
132262306a36Sopenharmony_ci				ret = 0;
132362306a36Sopenharmony_ci			} else
132462306a36Sopenharmony_ci				ret = -EIO; /* CRC not checked */
132562306a36Sopenharmony_ci		}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	}
132862306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cidec_refcnt:
133162306a36Sopenharmony_ci	atomic_dec(THERM_REFCNT(sl->family_data));
133262306a36Sopenharmony_cierror:
133362306a36Sopenharmony_ci	return ret;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic int write_scratchpad(struct w1_slave *sl, const u8 *data, u8 nb_bytes)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	struct w1_master *dev_master = sl->master;
133962306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
134062306a36Sopenharmony_ci	int ret = -ENODEV;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	if (!sl->family_data)
134362306a36Sopenharmony_ci		goto error;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	/* prevent the slave from going away in sleep */
134662306a36Sopenharmony_ci	atomic_inc(THERM_REFCNT(sl->family_data));
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
134962306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
135062306a36Sopenharmony_ci		goto dec_refcnt;
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	while (max_trying-- && ret) { /* ret should be 0 */
135462306a36Sopenharmony_ci		/* safe version to select slave */
135562306a36Sopenharmony_ci		if (!reset_select_slave(sl)) {
135662306a36Sopenharmony_ci			w1_write_8(dev_master, W1_WRITE_SCRATCHPAD);
135762306a36Sopenharmony_ci			w1_write_block(dev_master, data, nb_bytes);
135862306a36Sopenharmony_ci			ret = 0;
135962306a36Sopenharmony_ci		}
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_cidec_refcnt:
136462306a36Sopenharmony_ci	atomic_dec(THERM_REFCNT(sl->family_data));
136562306a36Sopenharmony_cierror:
136662306a36Sopenharmony_ci	return ret;
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_cistatic int copy_scratchpad(struct w1_slave *sl)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	struct w1_master *dev_master = sl->master;
137262306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
137362306a36Sopenharmony_ci	int t_write, ret = -ENODEV;
137462306a36Sopenharmony_ci	bool strong_pullup;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	if (!sl->family_data)
137762306a36Sopenharmony_ci		goto error;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	t_write = W1_THERM_EEPROM_WRITE_DELAY;
138062306a36Sopenharmony_ci	strong_pullup = (w1_strong_pullup == 2 ||
138162306a36Sopenharmony_ci					(!SLAVE_POWERMODE(sl) &&
138262306a36Sopenharmony_ci					w1_strong_pullup));
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	/* prevent the slave from going away in sleep */
138562306a36Sopenharmony_ci	atomic_inc(THERM_REFCNT(sl->family_data));
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
138862306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
138962306a36Sopenharmony_ci		goto dec_refcnt;
139062306a36Sopenharmony_ci	}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	while (max_trying-- && ret) { /* ret should be 0 */
139362306a36Sopenharmony_ci		/* safe version to select slave */
139462306a36Sopenharmony_ci		if (!reset_select_slave(sl)) {
139562306a36Sopenharmony_ci			unsigned long sleep_rem;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci			/* 10ms strong pullup (or delay) after the convert */
139862306a36Sopenharmony_ci			if (strong_pullup)
139962306a36Sopenharmony_ci				w1_next_pullup(dev_master, t_write);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci			w1_write_8(dev_master, W1_COPY_SCRATCHPAD);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci			if (strong_pullup) {
140462306a36Sopenharmony_ci				sleep_rem = msleep_interruptible(t_write);
140562306a36Sopenharmony_ci				if (sleep_rem != 0) {
140662306a36Sopenharmony_ci					ret = -EINTR;
140762306a36Sopenharmony_ci					goto mt_unlock;
140862306a36Sopenharmony_ci				}
140962306a36Sopenharmony_ci			}
141062306a36Sopenharmony_ci			ret = 0;
141162306a36Sopenharmony_ci		}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_cimt_unlock:
141662306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
141762306a36Sopenharmony_cidec_refcnt:
141862306a36Sopenharmony_ci	atomic_dec(THERM_REFCNT(sl->family_data));
141962306a36Sopenharmony_cierror:
142062306a36Sopenharmony_ci	return ret;
142162306a36Sopenharmony_ci}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_cistatic int recall_eeprom(struct w1_slave *sl)
142462306a36Sopenharmony_ci{
142562306a36Sopenharmony_ci	struct w1_master *dev_master = sl->master;
142662306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
142762306a36Sopenharmony_ci	int ret = -ENODEV;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	if (!sl->family_data)
143062306a36Sopenharmony_ci		goto error;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	/* prevent the slave from going away in sleep */
143362306a36Sopenharmony_ci	atomic_inc(THERM_REFCNT(sl->family_data));
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
143662306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
143762306a36Sopenharmony_ci		goto dec_refcnt;
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	while (max_trying-- && ret) { /* ret should be 0 */
144162306a36Sopenharmony_ci		/* safe version to select slave */
144262306a36Sopenharmony_ci		if (!reset_select_slave(sl)) {
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci			w1_write_8(dev_master, W1_RECALL_EEPROM);
144562306a36Sopenharmony_ci			ret = w1_poll_completion(dev_master, W1_POLL_RECALL_EEPROM);
144662306a36Sopenharmony_ci		}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cidec_refcnt:
145362306a36Sopenharmony_ci	atomic_dec(THERM_REFCNT(sl->family_data));
145462306a36Sopenharmony_cierror:
145562306a36Sopenharmony_ci	return ret;
145662306a36Sopenharmony_ci}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_cistatic int read_powermode(struct w1_slave *sl)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	struct w1_master *dev_master = sl->master;
146162306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
146262306a36Sopenharmony_ci	int  ret = -ENODEV;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	if (!sl->family_data)
146562306a36Sopenharmony_ci		goto error;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	/* prevent the slave from going away in sleep */
146862306a36Sopenharmony_ci	atomic_inc(THERM_REFCNT(sl->family_data));
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
147162306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
147262306a36Sopenharmony_ci		goto dec_refcnt;
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	while ((max_trying--) && (ret < 0)) {
147662306a36Sopenharmony_ci		/* safe version to select slave */
147762306a36Sopenharmony_ci		if (!reset_select_slave(sl)) {
147862306a36Sopenharmony_ci			w1_write_8(dev_master, W1_READ_PSUPPLY);
147962306a36Sopenharmony_ci			/*
148062306a36Sopenharmony_ci			 * Emit a read time slot and read only one bit,
148162306a36Sopenharmony_ci			 * 1 is externally powered,
148262306a36Sopenharmony_ci			 * 0 is parasite powered
148362306a36Sopenharmony_ci			 */
148462306a36Sopenharmony_ci			ret = w1_touch_bit(dev_master, 1);
148562306a36Sopenharmony_ci			/* ret should be either 1 either 0 */
148662306a36Sopenharmony_ci		}
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cidec_refcnt:
149162306a36Sopenharmony_ci	atomic_dec(THERM_REFCNT(sl->family_data));
149262306a36Sopenharmony_cierror:
149362306a36Sopenharmony_ci	return ret;
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_cistatic int trigger_bulk_read(struct w1_master *dev_master)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	struct w1_slave *sl = NULL; /* used to iterate through slaves */
149962306a36Sopenharmony_ci	int max_trying = W1_THERM_MAX_TRY;
150062306a36Sopenharmony_ci	int t_conv = 0;
150162306a36Sopenharmony_ci	int ret = -ENODEV;
150262306a36Sopenharmony_ci	bool strong_pullup = false;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	/*
150562306a36Sopenharmony_ci	 * Check whether there are parasite powered device on the bus,
150662306a36Sopenharmony_ci	 * and compute duration of conversion for these devices
150762306a36Sopenharmony_ci	 * so we can apply a strong pullup if required
150862306a36Sopenharmony_ci	 */
150962306a36Sopenharmony_ci	list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
151062306a36Sopenharmony_ci		if (!sl->family_data)
151162306a36Sopenharmony_ci			goto error;
151262306a36Sopenharmony_ci		if (bulk_read_support(sl)) {
151362306a36Sopenharmony_ci			int t_cur = conversion_time(sl);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci			t_conv = max(t_cur, t_conv);
151662306a36Sopenharmony_ci			strong_pullup = strong_pullup ||
151762306a36Sopenharmony_ci					(w1_strong_pullup == 2 ||
151862306a36Sopenharmony_ci					(!SLAVE_POWERMODE(sl) &&
151962306a36Sopenharmony_ci					w1_strong_pullup));
152062306a36Sopenharmony_ci		}
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	/*
152462306a36Sopenharmony_ci	 * t_conv is the max conversion time required on the bus
152562306a36Sopenharmony_ci	 * If its 0, no device support the bulk read feature
152662306a36Sopenharmony_ci	 */
152762306a36Sopenharmony_ci	if (!t_conv)
152862306a36Sopenharmony_ci		goto error;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	if (!bus_mutex_lock(&dev_master->bus_mutex)) {
153162306a36Sopenharmony_ci		ret = -EAGAIN;	/* Didn't acquire the mutex */
153262306a36Sopenharmony_ci		goto error;
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	while ((max_trying--) && (ret < 0)) { /* ret should be either 0 */
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci		if (!w1_reset_bus(dev_master)) {	/* Just reset the bus */
153862306a36Sopenharmony_ci			unsigned long sleep_rem;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci			w1_write_8(dev_master, W1_SKIP_ROM);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci			if (strong_pullup)	/* Apply pullup if required */
154362306a36Sopenharmony_ci				w1_next_pullup(dev_master, t_conv);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci			w1_write_8(dev_master, W1_CONVERT_TEMP);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci			/* set a flag to instruct that converT pending */
154862306a36Sopenharmony_ci			list_for_each_entry(sl,
154962306a36Sopenharmony_ci				&dev_master->slist, w1_slave_entry) {
155062306a36Sopenharmony_ci				if (bulk_read_support(sl))
155162306a36Sopenharmony_ci					SLAVE_CONVERT_TRIGGERED(sl) = -1;
155262306a36Sopenharmony_ci			}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci			if (strong_pullup) { /* some device need pullup */
155562306a36Sopenharmony_ci				sleep_rem = msleep_interruptible(t_conv);
155662306a36Sopenharmony_ci				if (sleep_rem != 0) {
155762306a36Sopenharmony_ci					ret = -EINTR;
155862306a36Sopenharmony_ci					goto mt_unlock;
155962306a36Sopenharmony_ci				}
156062306a36Sopenharmony_ci				mutex_unlock(&dev_master->bus_mutex);
156162306a36Sopenharmony_ci			} else {
156262306a36Sopenharmony_ci				mutex_unlock(&dev_master->bus_mutex);
156362306a36Sopenharmony_ci				sleep_rem = msleep_interruptible(t_conv);
156462306a36Sopenharmony_ci				if (sleep_rem != 0) {
156562306a36Sopenharmony_ci					ret = -EINTR;
156662306a36Sopenharmony_ci					goto set_flag;
156762306a36Sopenharmony_ci				}
156862306a36Sopenharmony_ci			}
156962306a36Sopenharmony_ci			ret = 0;
157062306a36Sopenharmony_ci			goto set_flag;
157162306a36Sopenharmony_ci		}
157262306a36Sopenharmony_ci	}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_cimt_unlock:
157562306a36Sopenharmony_ci	mutex_unlock(&dev_master->bus_mutex);
157662306a36Sopenharmony_ciset_flag:
157762306a36Sopenharmony_ci	/* set a flag to register convsersion is done */
157862306a36Sopenharmony_ci	list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
157962306a36Sopenharmony_ci		if (bulk_read_support(sl))
158062306a36Sopenharmony_ci			SLAVE_CONVERT_TRIGGERED(sl) = 1;
158162306a36Sopenharmony_ci	}
158262306a36Sopenharmony_cierror:
158362306a36Sopenharmony_ci	return ret;
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci/* Sysfs Interface definition */
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic ssize_t w1_slave_show(struct device *device,
158962306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
159262306a36Sopenharmony_ci	struct therm_info info;
159362306a36Sopenharmony_ci	u8 *family_data = sl->family_data;
159462306a36Sopenharmony_ci	int ret, i;
159562306a36Sopenharmony_ci	ssize_t c = PAGE_SIZE;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	if (bulk_read_support(sl)) {
159862306a36Sopenharmony_ci		if (SLAVE_CONVERT_TRIGGERED(sl) < 0) {
159962306a36Sopenharmony_ci			dev_dbg(device,
160062306a36Sopenharmony_ci				"%s: Conversion in progress, retry later\n",
160162306a36Sopenharmony_ci				__func__);
160262306a36Sopenharmony_ci			return 0;
160362306a36Sopenharmony_ci		} else if (SLAVE_CONVERT_TRIGGERED(sl) > 0) {
160462306a36Sopenharmony_ci			/* A bulk read has been issued, read the device RAM */
160562306a36Sopenharmony_ci			ret = read_scratchpad(sl, &info);
160662306a36Sopenharmony_ci			SLAVE_CONVERT_TRIGGERED(sl) = 0;
160762306a36Sopenharmony_ci		} else
160862306a36Sopenharmony_ci			ret = convert_t(sl, &info);
160962306a36Sopenharmony_ci	} else
161062306a36Sopenharmony_ci		ret = convert_t(sl, &info);
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	if (ret < 0) {
161362306a36Sopenharmony_ci		dev_dbg(device,
161462306a36Sopenharmony_ci			"%s: Temperature data may be corrupted. err=%d\n",
161562306a36Sopenharmony_ci			__func__, ret);
161662306a36Sopenharmony_ci		return 0;
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	for (i = 0; i < 9; ++i)
162062306a36Sopenharmony_ci		c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", info.rom[i]);
162162306a36Sopenharmony_ci	c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
162262306a36Sopenharmony_ci		      info.crc, (info.verdict) ? "YES" : "NO");
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (info.verdict)
162562306a36Sopenharmony_ci		memcpy(family_data, info.rom, sizeof(info.rom));
162662306a36Sopenharmony_ci	else
162762306a36Sopenharmony_ci		dev_warn(device, "%s:Read failed CRC check\n", __func__);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	for (i = 0; i < 9; ++i)
163062306a36Sopenharmony_ci		c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ",
163162306a36Sopenharmony_ci			      ((u8 *)family_data)[i]);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
163462306a36Sopenharmony_ci			temperature_from_RAM(sl, info.rom));
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	ret = PAGE_SIZE - c;
163762306a36Sopenharmony_ci	return ret;
163862306a36Sopenharmony_ci}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_cistatic ssize_t w1_slave_store(struct device *device,
164162306a36Sopenharmony_ci			      struct device_attribute *attr, const char *buf,
164262306a36Sopenharmony_ci			      size_t size)
164362306a36Sopenharmony_ci{
164462306a36Sopenharmony_ci	int val, ret = 0;
164562306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	ret = kstrtoint(buf, 10, &val); /* converting user entry to int */
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	if (ret) {	/* conversion error */
165062306a36Sopenharmony_ci		dev_info(device,
165162306a36Sopenharmony_ci			"%s: conversion error. err= %d\n", __func__, ret);
165262306a36Sopenharmony_ci		return size;	/* return size to avoid call back again */
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
165662306a36Sopenharmony_ci		dev_info(device,
165762306a36Sopenharmony_ci			"%s: Device not supported by the driver\n", __func__);
165862306a36Sopenharmony_ci		return size;  /* No device family */
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	if (val == 0)	/* val=0 : trigger a EEPROM save */
166262306a36Sopenharmony_ci		ret = copy_scratchpad(sl);
166362306a36Sopenharmony_ci	else {
166462306a36Sopenharmony_ci		if (SLAVE_SPECIFIC_FUNC(sl)->set_resolution)
166562306a36Sopenharmony_ci			ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val);
166662306a36Sopenharmony_ci	}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (ret) {
166962306a36Sopenharmony_ci		dev_warn(device, "%s: Set resolution - error %d\n", __func__, ret);
167062306a36Sopenharmony_ci		/* Propagate error to userspace */
167162306a36Sopenharmony_ci		return ret;
167262306a36Sopenharmony_ci	}
167362306a36Sopenharmony_ci	SLAVE_RESOLUTION(sl) = val;
167462306a36Sopenharmony_ci	/* Reset the conversion time to default - it depends on resolution */
167562306a36Sopenharmony_ci	SLAVE_CONV_TIME_OVERRIDE(sl) = CONV_TIME_DEFAULT;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	return size; /* always return size to avoid infinite calling */
167862306a36Sopenharmony_ci}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_cistatic ssize_t temperature_show(struct device *device,
168162306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
168462306a36Sopenharmony_ci	struct therm_info info;
168562306a36Sopenharmony_ci	int ret = 0;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
168862306a36Sopenharmony_ci		dev_info(device,
168962306a36Sopenharmony_ci			"%s: Device not supported by the driver\n", __func__);
169062306a36Sopenharmony_ci		return 0;  /* No device family */
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	if (bulk_read_support(sl)) {
169462306a36Sopenharmony_ci		if (SLAVE_CONVERT_TRIGGERED(sl) < 0) {
169562306a36Sopenharmony_ci			dev_dbg(device,
169662306a36Sopenharmony_ci				"%s: Conversion in progress, retry later\n",
169762306a36Sopenharmony_ci				__func__);
169862306a36Sopenharmony_ci			return 0;
169962306a36Sopenharmony_ci		} else if (SLAVE_CONVERT_TRIGGERED(sl) > 0) {
170062306a36Sopenharmony_ci			/* A bulk read has been issued, read the device RAM */
170162306a36Sopenharmony_ci			ret = read_scratchpad(sl, &info);
170262306a36Sopenharmony_ci			SLAVE_CONVERT_TRIGGERED(sl) = 0;
170362306a36Sopenharmony_ci		} else
170462306a36Sopenharmony_ci			ret = convert_t(sl, &info);
170562306a36Sopenharmony_ci	} else
170662306a36Sopenharmony_ci		ret = convert_t(sl, &info);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	if (ret < 0) {
170962306a36Sopenharmony_ci		dev_dbg(device,
171062306a36Sopenharmony_ci			"%s: Temperature data may be corrupted. err=%d\n",
171162306a36Sopenharmony_ci			__func__, ret);
171262306a36Sopenharmony_ci		return 0;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", temperature_from_RAM(sl, info.rom));
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_cistatic ssize_t ext_power_show(struct device *device,
171962306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	if (!sl->family_data) {
172462306a36Sopenharmony_ci		dev_info(device,
172562306a36Sopenharmony_ci			"%s: Device not supported by the driver\n", __func__);
172662306a36Sopenharmony_ci		return 0;  /* No device family */
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	/* Getting the power mode of the device {external, parasite} */
173062306a36Sopenharmony_ci	SLAVE_POWERMODE(sl) = read_powermode(sl);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (SLAVE_POWERMODE(sl) < 0) {
173362306a36Sopenharmony_ci		dev_dbg(device,
173462306a36Sopenharmony_ci			"%s: Power_mode may be corrupted. err=%d\n",
173562306a36Sopenharmony_ci			__func__, SLAVE_POWERMODE(sl));
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci	return sprintf(buf, "%d\n", SLAVE_POWERMODE(sl));
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_cistatic ssize_t resolution_show(struct device *device,
174162306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
174662306a36Sopenharmony_ci		dev_info(device,
174762306a36Sopenharmony_ci			"%s: Device not supported by the driver\n", __func__);
174862306a36Sopenharmony_ci		return 0;  /* No device family */
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	/* get the correct function depending on the device */
175262306a36Sopenharmony_ci	SLAVE_RESOLUTION(sl) = SLAVE_SPECIFIC_FUNC(sl)->get_resolution(sl);
175362306a36Sopenharmony_ci	if (SLAVE_RESOLUTION(sl) < 0) {
175462306a36Sopenharmony_ci		dev_dbg(device,
175562306a36Sopenharmony_ci			"%s: Resolution may be corrupted. err=%d\n",
175662306a36Sopenharmony_ci			__func__, SLAVE_RESOLUTION(sl));
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	return sprintf(buf, "%d\n", SLAVE_RESOLUTION(sl));
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_cistatic ssize_t resolution_store(struct device *device,
176362306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size)
176462306a36Sopenharmony_ci{
176562306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
176662306a36Sopenharmony_ci	int val;
176762306a36Sopenharmony_ci	int ret = 0;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	ret = kstrtoint(buf, 10, &val); /* converting user entry to int */
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	if (ret) {	/* conversion error */
177262306a36Sopenharmony_ci		dev_info(device,
177362306a36Sopenharmony_ci			"%s: conversion error. err= %d\n", __func__, ret);
177462306a36Sopenharmony_ci		return size;	/* return size to avoid call back again */
177562306a36Sopenharmony_ci	}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
177862306a36Sopenharmony_ci		dev_info(device,
177962306a36Sopenharmony_ci			"%s: Device not supported by the driver\n", __func__);
178062306a36Sopenharmony_ci		return size;  /* No device family */
178162306a36Sopenharmony_ci	}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/*
178462306a36Sopenharmony_ci	 * Don't deal with the val enterd by user,
178562306a36Sopenharmony_ci	 * only device knows what is correct or not
178662306a36Sopenharmony_ci	 */
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	/* get the correct function depending on the device */
178962306a36Sopenharmony_ci	ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	if (ret)
179262306a36Sopenharmony_ci		return ret;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	SLAVE_RESOLUTION(sl) = val;
179562306a36Sopenharmony_ci	/* Reset the conversion time to default because it depends on resolution */
179662306a36Sopenharmony_ci	SLAVE_CONV_TIME_OVERRIDE(sl) = CONV_TIME_DEFAULT;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	return size;
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_cistatic ssize_t eeprom_cmd_store(struct device *device,
180262306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size)
180362306a36Sopenharmony_ci{
180462306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
180562306a36Sopenharmony_ci	int ret = -EINVAL; /* Invalid argument */
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (size == sizeof(EEPROM_CMD_WRITE)) {
180862306a36Sopenharmony_ci		if (!strncmp(buf, EEPROM_CMD_WRITE, sizeof(EEPROM_CMD_WRITE)-1))
180962306a36Sopenharmony_ci			ret = copy_scratchpad(sl);
181062306a36Sopenharmony_ci	} else if (size == sizeof(EEPROM_CMD_READ)) {
181162306a36Sopenharmony_ci		if (!strncmp(buf, EEPROM_CMD_READ, sizeof(EEPROM_CMD_READ)-1))
181262306a36Sopenharmony_ci			ret = recall_eeprom(sl);
181362306a36Sopenharmony_ci	}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	if (ret)
181662306a36Sopenharmony_ci		dev_info(device, "%s: error in process %d\n", __func__, ret);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	return size;
181962306a36Sopenharmony_ci}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_cistatic ssize_t alarms_show(struct device *device,
182262306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
182362306a36Sopenharmony_ci{
182462306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
182562306a36Sopenharmony_ci	int ret;
182662306a36Sopenharmony_ci	s8 th = 0, tl = 0;
182762306a36Sopenharmony_ci	struct therm_info scratchpad;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	ret = read_scratchpad(sl, &scratchpad);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	if (!ret)	{
183262306a36Sopenharmony_ci		th = scratchpad.rom[2]; /* TH is byte 2 */
183362306a36Sopenharmony_ci		tl = scratchpad.rom[3]; /* TL is byte 3 */
183462306a36Sopenharmony_ci	} else {
183562306a36Sopenharmony_ci		dev_info(device,
183662306a36Sopenharmony_ci			"%s: error reading alarms register %d\n",
183762306a36Sopenharmony_ci			__func__, ret);
183862306a36Sopenharmony_ci	}
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	return sprintf(buf, "%hd %hd\n", tl, th);
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_cistatic ssize_t alarms_store(struct device *device,
184462306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size)
184562306a36Sopenharmony_ci{
184662306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
184762306a36Sopenharmony_ci	struct therm_info info;
184862306a36Sopenharmony_ci	u8 new_config_register[3];	/* array of data to be written */
184962306a36Sopenharmony_ci	int temp, ret;
185062306a36Sopenharmony_ci	char *token = NULL;
185162306a36Sopenharmony_ci	s8 tl, th;	/* 1 byte per value + temp ring order */
185262306a36Sopenharmony_ci	char *p_args, *orig;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	p_args = orig = kmalloc(size, GFP_KERNEL);
185562306a36Sopenharmony_ci	/* Safe string copys as buf is const */
185662306a36Sopenharmony_ci	if (!p_args) {
185762306a36Sopenharmony_ci		dev_warn(device,
185862306a36Sopenharmony_ci			"%s: error unable to allocate memory %d\n",
185962306a36Sopenharmony_ci			__func__, -ENOMEM);
186062306a36Sopenharmony_ci		return size;
186162306a36Sopenharmony_ci	}
186262306a36Sopenharmony_ci	strcpy(p_args, buf);
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	/* Split string using space char */
186562306a36Sopenharmony_ci	token = strsep(&p_args, " ");
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (!token)	{
186862306a36Sopenharmony_ci		dev_info(device,
186962306a36Sopenharmony_ci			"%s: error parsing args %d\n", __func__, -EINVAL);
187062306a36Sopenharmony_ci		goto free_m;
187162306a36Sopenharmony_ci	}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	/* Convert 1st entry to int */
187462306a36Sopenharmony_ci	ret = kstrtoint (token, 10, &temp);
187562306a36Sopenharmony_ci	if (ret) {
187662306a36Sopenharmony_ci		dev_info(device,
187762306a36Sopenharmony_ci			"%s: error parsing args %d\n", __func__, ret);
187862306a36Sopenharmony_ci		goto free_m;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	tl = int_to_short(temp);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	/* Split string using space char */
188462306a36Sopenharmony_ci	token = strsep(&p_args, " ");
188562306a36Sopenharmony_ci	if (!token)	{
188662306a36Sopenharmony_ci		dev_info(device,
188762306a36Sopenharmony_ci			"%s: error parsing args %d\n", __func__, -EINVAL);
188862306a36Sopenharmony_ci		goto free_m;
188962306a36Sopenharmony_ci	}
189062306a36Sopenharmony_ci	/* Convert 2nd entry to int */
189162306a36Sopenharmony_ci	ret = kstrtoint (token, 10, &temp);
189262306a36Sopenharmony_ci	if (ret) {
189362306a36Sopenharmony_ci		dev_info(device,
189462306a36Sopenharmony_ci			"%s: error parsing args %d\n", __func__, ret);
189562306a36Sopenharmony_ci		goto free_m;
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	/* Prepare to cast to short by eliminating out of range values */
189962306a36Sopenharmony_ci	th = int_to_short(temp);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	/* Reorder if required th and tl */
190262306a36Sopenharmony_ci	if (tl > th)
190362306a36Sopenharmony_ci		swap(tl, th);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	/*
190662306a36Sopenharmony_ci	 * Read the scratchpad to change only the required bits
190762306a36Sopenharmony_ci	 * (th : byte 2 - tl: byte 3)
190862306a36Sopenharmony_ci	 */
190962306a36Sopenharmony_ci	ret = read_scratchpad(sl, &info);
191062306a36Sopenharmony_ci	if (!ret) {
191162306a36Sopenharmony_ci		new_config_register[0] = th;	/* Byte 2 */
191262306a36Sopenharmony_ci		new_config_register[1] = tl;	/* Byte 3 */
191362306a36Sopenharmony_ci		new_config_register[2] = info.rom[4];/* Byte 4 */
191462306a36Sopenharmony_ci	} else {
191562306a36Sopenharmony_ci		dev_info(device,
191662306a36Sopenharmony_ci			"%s: error reading from the slave device %d\n",
191762306a36Sopenharmony_ci			__func__, ret);
191862306a36Sopenharmony_ci		goto free_m;
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	/* Write data in the device RAM */
192262306a36Sopenharmony_ci	if (!SLAVE_SPECIFIC_FUNC(sl)) {
192362306a36Sopenharmony_ci		dev_info(device,
192462306a36Sopenharmony_ci			"%s: Device not supported by the driver %d\n",
192562306a36Sopenharmony_ci			__func__, -ENODEV);
192662306a36Sopenharmony_ci		goto free_m;
192762306a36Sopenharmony_ci	}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	ret = SLAVE_SPECIFIC_FUNC(sl)->write_data(sl, new_config_register);
193062306a36Sopenharmony_ci	if (ret)
193162306a36Sopenharmony_ci		dev_info(device,
193262306a36Sopenharmony_ci			"%s: error writing to the slave device %d\n",
193362306a36Sopenharmony_ci			__func__, ret);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_cifree_m:
193662306a36Sopenharmony_ci	/* free allocated memory */
193762306a36Sopenharmony_ci	kfree(orig);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	return size;
194062306a36Sopenharmony_ci}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_cistatic ssize_t therm_bulk_read_store(struct device *device,
194362306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size)
194462306a36Sopenharmony_ci{
194562306a36Sopenharmony_ci	struct w1_master *dev_master = dev_to_w1_master(device);
194662306a36Sopenharmony_ci	int ret = -EINVAL; /* Invalid argument */
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	if (size == sizeof(BULK_TRIGGER_CMD))
194962306a36Sopenharmony_ci		if (!strncmp(buf, BULK_TRIGGER_CMD,
195062306a36Sopenharmony_ci				sizeof(BULK_TRIGGER_CMD)-1))
195162306a36Sopenharmony_ci			ret = trigger_bulk_read(dev_master);
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci	if (ret)
195462306a36Sopenharmony_ci		dev_info(device,
195562306a36Sopenharmony_ci			"%s: unable to trigger a bulk read on the bus. err=%d\n",
195662306a36Sopenharmony_ci			__func__, ret);
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	return size;
195962306a36Sopenharmony_ci}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_cistatic ssize_t therm_bulk_read_show(struct device *device,
196262306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	struct w1_master *dev_master = dev_to_w1_master(device);
196562306a36Sopenharmony_ci	struct w1_slave *sl = NULL;
196662306a36Sopenharmony_ci	int ret = 0;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
196962306a36Sopenharmony_ci		if (sl->family_data) {
197062306a36Sopenharmony_ci			if (bulk_read_support(sl)) {
197162306a36Sopenharmony_ci				if (SLAVE_CONVERT_TRIGGERED(sl) == -1) {
197262306a36Sopenharmony_ci					ret = -1;
197362306a36Sopenharmony_ci					goto show_result;
197462306a36Sopenharmony_ci				}
197562306a36Sopenharmony_ci				if (SLAVE_CONVERT_TRIGGERED(sl) == 1)
197662306a36Sopenharmony_ci					/* continue to check other slaves */
197762306a36Sopenharmony_ci					ret = 1;
197862306a36Sopenharmony_ci			}
197962306a36Sopenharmony_ci		}
198062306a36Sopenharmony_ci	}
198162306a36Sopenharmony_cishow_result:
198262306a36Sopenharmony_ci	return sprintf(buf, "%d\n", ret);
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_cistatic ssize_t conv_time_show(struct device *device,
198662306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
199162306a36Sopenharmony_ci		dev_info(device,
199262306a36Sopenharmony_ci			"%s: Device is not supported by the driver\n", __func__);
199362306a36Sopenharmony_ci		return 0;  /* No device family */
199462306a36Sopenharmony_ci	}
199562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", conversion_time(sl));
199662306a36Sopenharmony_ci}
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_cistatic ssize_t conv_time_store(struct device *device,
199962306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t size)
200062306a36Sopenharmony_ci{
200162306a36Sopenharmony_ci	int val, ret = 0;
200262306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (kstrtoint(buf, 10, &val)) /* converting user entry to int */
200562306a36Sopenharmony_ci		return -EINVAL;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	if (check_family_data(sl))
200862306a36Sopenharmony_ci		return -ENODEV;
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	if (val != CONV_TIME_MEASURE) {
201162306a36Sopenharmony_ci		if (val >= CONV_TIME_DEFAULT)
201262306a36Sopenharmony_ci			SLAVE_CONV_TIME_OVERRIDE(sl) = val;
201362306a36Sopenharmony_ci		else
201462306a36Sopenharmony_ci			return -EINVAL;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	} else {
201762306a36Sopenharmony_ci		int conv_time;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci		ret = conv_time_measure(sl, &conv_time);
202062306a36Sopenharmony_ci		if (ret)
202162306a36Sopenharmony_ci			return -EIO;
202262306a36Sopenharmony_ci		SLAVE_CONV_TIME_OVERRIDE(sl) = conv_time;
202362306a36Sopenharmony_ci	}
202462306a36Sopenharmony_ci	return size;
202562306a36Sopenharmony_ci}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_cistatic ssize_t features_show(struct device *device,
202862306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
202962306a36Sopenharmony_ci{
203062306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
203362306a36Sopenharmony_ci		dev_info(device,
203462306a36Sopenharmony_ci			 "%s: Device not supported by the driver\n", __func__);
203562306a36Sopenharmony_ci		return 0;  /* No device family */
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci	return sprintf(buf, "%u\n", SLAVE_FEATURES(sl));
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_cistatic ssize_t features_store(struct device *device,
204162306a36Sopenharmony_ci			      struct device_attribute *attr, const char *buf, size_t size)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	int val, ret = 0;
204462306a36Sopenharmony_ci	bool strong_pullup;
204562306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	ret = kstrtouint(buf, 10, &val); /* converting user entry to int */
204862306a36Sopenharmony_ci	if (ret)
204962306a36Sopenharmony_ci		return -EINVAL;  /* invalid number */
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
205262306a36Sopenharmony_ci		dev_info(device, "%s: Device not supported by the driver\n", __func__);
205362306a36Sopenharmony_ci		return -ENODEV;
205462306a36Sopenharmony_ci	}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	if ((val & W1_THERM_FEATURES_MASK) != val)
205762306a36Sopenharmony_ci		return -EINVAL;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	SLAVE_FEATURES(sl) = val;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	strong_pullup = (w1_strong_pullup == 2 ||
206262306a36Sopenharmony_ci			 (!SLAVE_POWERMODE(sl) &&
206362306a36Sopenharmony_ci			  w1_strong_pullup));
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	if (strong_pullup && SLAVE_FEATURES(sl) & W1_THERM_POLL_COMPLETION) {
206662306a36Sopenharmony_ci		dev_warn(&sl->dev,
206762306a36Sopenharmony_ci			 "%s: W1_THERM_POLL_COMPLETION disabled in parasite power mode.\n",
206862306a36Sopenharmony_ci			 __func__);
206962306a36Sopenharmony_ci		SLAVE_FEATURES(sl) &= ~W1_THERM_POLL_COMPLETION;
207062306a36Sopenharmony_ci	}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	return size;
207362306a36Sopenharmony_ci}
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_HWMON)
207662306a36Sopenharmony_cistatic int w1_read_temp(struct device *device, u32 attr, int channel,
207762306a36Sopenharmony_ci			long *val)
207862306a36Sopenharmony_ci{
207962306a36Sopenharmony_ci	struct w1_slave *sl = dev_get_drvdata(device);
208062306a36Sopenharmony_ci	struct therm_info info;
208162306a36Sopenharmony_ci	int ret;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	switch (attr) {
208462306a36Sopenharmony_ci	case hwmon_temp_input:
208562306a36Sopenharmony_ci		ret = convert_t(sl, &info);
208662306a36Sopenharmony_ci		if (ret)
208762306a36Sopenharmony_ci			return ret;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci		if (!info.verdict) {
209062306a36Sopenharmony_ci			ret = -EIO;
209162306a36Sopenharmony_ci			return ret;
209262306a36Sopenharmony_ci		}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci		*val = temperature_from_RAM(sl, info.rom);
209562306a36Sopenharmony_ci		ret = 0;
209662306a36Sopenharmony_ci		break;
209762306a36Sopenharmony_ci	default:
209862306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
209962306a36Sopenharmony_ci		break;
210062306a36Sopenharmony_ci	}
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	return ret;
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci#endif
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci#define W1_42_CHAIN	0x99
210762306a36Sopenharmony_ci#define W1_42_CHAIN_OFF	0x3C
210862306a36Sopenharmony_ci#define W1_42_CHAIN_OFF_INV	0xC3
210962306a36Sopenharmony_ci#define W1_42_CHAIN_ON	0x5A
211062306a36Sopenharmony_ci#define W1_42_CHAIN_ON_INV	0xA5
211162306a36Sopenharmony_ci#define W1_42_CHAIN_DONE 0x96
211262306a36Sopenharmony_ci#define W1_42_CHAIN_DONE_INV 0x69
211362306a36Sopenharmony_ci#define W1_42_COND_READ	0x0F
211462306a36Sopenharmony_ci#define W1_42_SUCCESS_CONFIRM_BYTE 0xAA
211562306a36Sopenharmony_ci#define W1_42_FINISHED_BYTE 0xFF
211662306a36Sopenharmony_cistatic ssize_t w1_seq_show(struct device *device,
211762306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(device);
212062306a36Sopenharmony_ci	ssize_t c = PAGE_SIZE;
212162306a36Sopenharmony_ci	int i;
212262306a36Sopenharmony_ci	u8 ack;
212362306a36Sopenharmony_ci	u64 rn;
212462306a36Sopenharmony_ci	struct w1_reg_num *reg_num;
212562306a36Sopenharmony_ci	int seq = 0;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	mutex_lock(&sl->master->bus_mutex);
212862306a36Sopenharmony_ci	/* Place all devices in CHAIN state */
212962306a36Sopenharmony_ci	if (w1_reset_bus(sl->master))
213062306a36Sopenharmony_ci		goto error;
213162306a36Sopenharmony_ci	w1_write_8(sl->master, W1_SKIP_ROM);
213262306a36Sopenharmony_ci	w1_write_8(sl->master, W1_42_CHAIN);
213362306a36Sopenharmony_ci	w1_write_8(sl->master, W1_42_CHAIN_ON);
213462306a36Sopenharmony_ci	w1_write_8(sl->master, W1_42_CHAIN_ON_INV);
213562306a36Sopenharmony_ci	msleep(sl->master->pullup_duration);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	/* check for acknowledgment */
213862306a36Sopenharmony_ci	ack = w1_read_8(sl->master);
213962306a36Sopenharmony_ci	if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
214062306a36Sopenharmony_ci		goto error;
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	/* In case the bus fails to send 0xFF, limit */
214362306a36Sopenharmony_ci	for (i = 0; i <= 64; i++) {
214462306a36Sopenharmony_ci		if (w1_reset_bus(sl->master))
214562306a36Sopenharmony_ci			goto error;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci		w1_write_8(sl->master, W1_42_COND_READ);
214862306a36Sopenharmony_ci		w1_read_block(sl->master, (u8 *)&rn, 8);
214962306a36Sopenharmony_ci		reg_num = (struct w1_reg_num *) &rn;
215062306a36Sopenharmony_ci		if (reg_num->family == W1_42_FINISHED_BYTE)
215162306a36Sopenharmony_ci			break;
215262306a36Sopenharmony_ci		if (sl->reg_num.id == reg_num->id)
215362306a36Sopenharmony_ci			seq = i;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci		if (w1_reset_bus(sl->master))
215662306a36Sopenharmony_ci			goto error;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci		/* Put the device into chain DONE state */
215962306a36Sopenharmony_ci		w1_write_8(sl->master, W1_MATCH_ROM);
216062306a36Sopenharmony_ci		w1_write_block(sl->master, (u8 *)&rn, 8);
216162306a36Sopenharmony_ci		w1_write_8(sl->master, W1_42_CHAIN);
216262306a36Sopenharmony_ci		w1_write_8(sl->master, W1_42_CHAIN_DONE);
216362306a36Sopenharmony_ci		w1_write_8(sl->master, W1_42_CHAIN_DONE_INV);
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci		/* check for acknowledgment */
216662306a36Sopenharmony_ci		ack = w1_read_8(sl->master);
216762306a36Sopenharmony_ci		if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
216862306a36Sopenharmony_ci			goto error;
216962306a36Sopenharmony_ci	}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	/* Exit from CHAIN state */
217262306a36Sopenharmony_ci	if (w1_reset_bus(sl->master))
217362306a36Sopenharmony_ci		goto error;
217462306a36Sopenharmony_ci	w1_write_8(sl->master, W1_SKIP_ROM);
217562306a36Sopenharmony_ci	w1_write_8(sl->master, W1_42_CHAIN);
217662306a36Sopenharmony_ci	w1_write_8(sl->master, W1_42_CHAIN_OFF);
217762306a36Sopenharmony_ci	w1_write_8(sl->master, W1_42_CHAIN_OFF_INV);
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	/* check for acknowledgment */
218062306a36Sopenharmony_ci	ack = w1_read_8(sl->master);
218162306a36Sopenharmony_ci	if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
218262306a36Sopenharmony_ci		goto error;
218362306a36Sopenharmony_ci	mutex_unlock(&sl->master->bus_mutex);
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq);
218662306a36Sopenharmony_ci	return PAGE_SIZE - c;
218762306a36Sopenharmony_cierror:
218862306a36Sopenharmony_ci	mutex_unlock(&sl->master->bus_mutex);
218962306a36Sopenharmony_ci	return -EIO;
219062306a36Sopenharmony_ci}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_cistatic int __init w1_therm_init(void)
219362306a36Sopenharmony_ci{
219462306a36Sopenharmony_ci	int err, i;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
219762306a36Sopenharmony_ci		err = w1_register_family(w1_therm_families[i].f);
219862306a36Sopenharmony_ci		if (err)
219962306a36Sopenharmony_ci			w1_therm_families[i].broken = 1;
220062306a36Sopenharmony_ci	}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	return 0;
220362306a36Sopenharmony_ci}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_cistatic void __exit w1_therm_fini(void)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	int i;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
221062306a36Sopenharmony_ci		if (!w1_therm_families[i].broken)
221162306a36Sopenharmony_ci			w1_unregister_family(w1_therm_families[i].f);
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cimodule_init(w1_therm_init);
221562306a36Sopenharmony_cimodule_exit(w1_therm_fini);
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ciMODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
221862306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
221962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
222062306a36Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18S20));
222162306a36Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1822));
222262306a36Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18B20));
222362306a36Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1825));
222462306a36Sopenharmony_ciMODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00));
2225