162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Register map access API - W1 (1-Wire) support 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2017 Radioavionica Corporation 662306a36Sopenharmony_ci// Author: Alex A. Mihaylov <minimumlaw@rambler.ru> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/regmap.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/w1.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "internal.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define W1_CMD_READ_DATA 0x69 1562306a36Sopenharmony_ci#define W1_CMD_WRITE_DATA 0x6C 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * 1-Wire slaves registers with addess 8 bit and data 8 bit 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int w1_reg_a8_v8_read(void *context, unsigned int reg, unsigned int *val) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct device *dev = context; 2462306a36Sopenharmony_ci struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 2562306a36Sopenharmony_ci int ret = 0; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci if (reg > 255) 2862306a36Sopenharmony_ci return -EINVAL; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 3162306a36Sopenharmony_ci if (!w1_reset_select_slave(sl)) { 3262306a36Sopenharmony_ci w1_write_8(sl->master, W1_CMD_READ_DATA); 3362306a36Sopenharmony_ci w1_write_8(sl->master, reg); 3462306a36Sopenharmony_ci *val = w1_read_8(sl->master); 3562306a36Sopenharmony_ci } else { 3662306a36Sopenharmony_ci ret = -ENODEV; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci return ret; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int w1_reg_a8_v8_write(void *context, unsigned int reg, unsigned int val) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct device *dev = context; 4662306a36Sopenharmony_ci struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 4762306a36Sopenharmony_ci int ret = 0; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (reg > 255) 5062306a36Sopenharmony_ci return -EINVAL; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 5362306a36Sopenharmony_ci if (!w1_reset_select_slave(sl)) { 5462306a36Sopenharmony_ci w1_write_8(sl->master, W1_CMD_WRITE_DATA); 5562306a36Sopenharmony_ci w1_write_8(sl->master, reg); 5662306a36Sopenharmony_ci w1_write_8(sl->master, val); 5762306a36Sopenharmony_ci } else { 5862306a36Sopenharmony_ci ret = -ENODEV; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return ret; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * 1-Wire slaves registers with addess 8 bit and data 16 bit 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int w1_reg_a8_v16_read(void *context, unsigned int reg, 7062306a36Sopenharmony_ci unsigned int *val) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct device *dev = context; 7362306a36Sopenharmony_ci struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 7462306a36Sopenharmony_ci int ret = 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (reg > 255) 7762306a36Sopenharmony_ci return -EINVAL; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 8062306a36Sopenharmony_ci if (!w1_reset_select_slave(sl)) { 8162306a36Sopenharmony_ci w1_write_8(sl->master, W1_CMD_READ_DATA); 8262306a36Sopenharmony_ci w1_write_8(sl->master, reg); 8362306a36Sopenharmony_ci *val = w1_read_8(sl->master); 8462306a36Sopenharmony_ci *val |= w1_read_8(sl->master)<<8; 8562306a36Sopenharmony_ci } else { 8662306a36Sopenharmony_ci ret = -ENODEV; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return ret; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int w1_reg_a8_v16_write(void *context, unsigned int reg, 9462306a36Sopenharmony_ci unsigned int val) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct device *dev = context; 9762306a36Sopenharmony_ci struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 9862306a36Sopenharmony_ci int ret = 0; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (reg > 255) 10162306a36Sopenharmony_ci return -EINVAL; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 10462306a36Sopenharmony_ci if (!w1_reset_select_slave(sl)) { 10562306a36Sopenharmony_ci w1_write_8(sl->master, W1_CMD_WRITE_DATA); 10662306a36Sopenharmony_ci w1_write_8(sl->master, reg); 10762306a36Sopenharmony_ci w1_write_8(sl->master, val & 0x00FF); 10862306a36Sopenharmony_ci w1_write_8(sl->master, val>>8 & 0x00FF); 10962306a36Sopenharmony_ci } else { 11062306a36Sopenharmony_ci ret = -ENODEV; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * 1-Wire slaves registers with addess 16 bit and data 16 bit 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int w1_reg_a16_v16_read(void *context, unsigned int reg, 12262306a36Sopenharmony_ci unsigned int *val) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct device *dev = context; 12562306a36Sopenharmony_ci struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 12662306a36Sopenharmony_ci int ret = 0; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (reg > 65535) 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 13262306a36Sopenharmony_ci if (!w1_reset_select_slave(sl)) { 13362306a36Sopenharmony_ci w1_write_8(sl->master, W1_CMD_READ_DATA); 13462306a36Sopenharmony_ci w1_write_8(sl->master, reg & 0x00FF); 13562306a36Sopenharmony_ci w1_write_8(sl->master, reg>>8 & 0x00FF); 13662306a36Sopenharmony_ci *val = w1_read_8(sl->master); 13762306a36Sopenharmony_ci *val |= w1_read_8(sl->master)<<8; 13862306a36Sopenharmony_ci } else { 13962306a36Sopenharmony_ci ret = -ENODEV; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return ret; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int w1_reg_a16_v16_write(void *context, unsigned int reg, 14762306a36Sopenharmony_ci unsigned int val) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct device *dev = context; 15062306a36Sopenharmony_ci struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 15162306a36Sopenharmony_ci int ret = 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (reg > 65535) 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci mutex_lock(&sl->master->bus_mutex); 15762306a36Sopenharmony_ci if (!w1_reset_select_slave(sl)) { 15862306a36Sopenharmony_ci w1_write_8(sl->master, W1_CMD_WRITE_DATA); 15962306a36Sopenharmony_ci w1_write_8(sl->master, reg & 0x00FF); 16062306a36Sopenharmony_ci w1_write_8(sl->master, reg>>8 & 0x00FF); 16162306a36Sopenharmony_ci w1_write_8(sl->master, val & 0x00FF); 16262306a36Sopenharmony_ci w1_write_8(sl->master, val>>8 & 0x00FF); 16362306a36Sopenharmony_ci } else { 16462306a36Sopenharmony_ci ret = -ENODEV; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci mutex_unlock(&sl->master->bus_mutex); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return ret; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * Various types of supported bus addressing 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic const struct regmap_bus regmap_w1_bus_a8_v8 = { 17662306a36Sopenharmony_ci .reg_read = w1_reg_a8_v8_read, 17762306a36Sopenharmony_ci .reg_write = w1_reg_a8_v8_write, 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic const struct regmap_bus regmap_w1_bus_a8_v16 = { 18162306a36Sopenharmony_ci .reg_read = w1_reg_a8_v16_read, 18262306a36Sopenharmony_ci .reg_write = w1_reg_a8_v16_write, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const struct regmap_bus regmap_w1_bus_a16_v16 = { 18662306a36Sopenharmony_ci .reg_read = w1_reg_a16_v16_read, 18762306a36Sopenharmony_ci .reg_write = w1_reg_a16_v16_write, 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic const struct regmap_bus *regmap_get_w1_bus(struct device *w1_dev, 19162306a36Sopenharmony_ci const struct regmap_config *config) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (config->reg_bits == 8 && config->val_bits == 8) 19462306a36Sopenharmony_ci return ®map_w1_bus_a8_v8; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (config->reg_bits == 8 && config->val_bits == 16) 19762306a36Sopenharmony_ci return ®map_w1_bus_a8_v16; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (config->reg_bits == 16 && config->val_bits == 16) 20062306a36Sopenharmony_ci return ®map_w1_bus_a16_v16; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return ERR_PTR(-ENOTSUPP); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistruct regmap *__regmap_init_w1(struct device *w1_dev, 20662306a36Sopenharmony_ci const struct regmap_config *config, 20762306a36Sopenharmony_ci struct lock_class_key *lock_key, 20862306a36Sopenharmony_ci const char *lock_name) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (IS_ERR(bus)) 21462306a36Sopenharmony_ci return ERR_CAST(bus); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return __regmap_init(w1_dev, bus, w1_dev, config, 21762306a36Sopenharmony_ci lock_key, lock_name); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__regmap_init_w1); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistruct regmap *__devm_regmap_init_w1(struct device *w1_dev, 22262306a36Sopenharmony_ci const struct regmap_config *config, 22362306a36Sopenharmony_ci struct lock_class_key *lock_key, 22462306a36Sopenharmony_ci const char *lock_name) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (IS_ERR(bus)) 23062306a36Sopenharmony_ci return ERR_CAST(bus); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return __devm_regmap_init(w1_dev, bus, w1_dev, config, 23362306a36Sopenharmony_ci lock_key, lock_name); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__devm_regmap_init_w1); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 238