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