1 /* 2 * Register map access API - W1 (1-Wire) support 3 * 4 * Copyright (c) 2017 Radioavionica Corporation 5 * Author: Alex A. Mihaylov <minimumlaw@rambler.ru> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation 10 */ 11 12 #include <linux/regmap.h> 13 #include <linux/module.h> 14 #include <linux/w1.h> 15 16 #include "internal.h" 17 18 #define W1_CMD_READ_DATA 0x69 19 #define W1_CMD_WRITE_DATA 0x6C 20 21 /* 22 * 1-Wire slaves registers with addess 8 bit and data 8 bit 23 */ 24 25 static int w1_reg_a8_v8_read(void *context, unsigned int reg, unsigned int *val) 26 { 27 struct device *dev = context; 28 struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 29 int ret = 0; 30 31 if (reg > 255) 32 return -EINVAL; 33 34 mutex_lock(&sl->master->bus_mutex); 35 if (!w1_reset_select_slave(sl)) { 36 w1_write_8(sl->master, W1_CMD_READ_DATA); 37 w1_write_8(sl->master, reg); 38 *val = w1_read_8(sl->master); 39 } else { 40 ret = -ENODEV; 41 } 42 mutex_unlock(&sl->master->bus_mutex); 43 44 return ret; 45 } 46 47 static int w1_reg_a8_v8_write(void *context, unsigned int reg, unsigned int val) 48 { 49 struct device *dev = context; 50 struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 51 int ret = 0; 52 53 if (reg > 255) 54 return -EINVAL; 55 56 mutex_lock(&sl->master->bus_mutex); 57 if (!w1_reset_select_slave(sl)) { 58 w1_write_8(sl->master, W1_CMD_WRITE_DATA); 59 w1_write_8(sl->master, reg); 60 w1_write_8(sl->master, val); 61 } else { 62 ret = -ENODEV; 63 } 64 mutex_unlock(&sl->master->bus_mutex); 65 66 return ret; 67 } 68 69 /* 70 * 1-Wire slaves registers with addess 8 bit and data 16 bit 71 */ 72 73 static int w1_reg_a8_v16_read(void *context, unsigned int reg, 74 unsigned int *val) 75 { 76 struct device *dev = context; 77 struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 78 int ret = 0; 79 80 if (reg > 255) 81 return -EINVAL; 82 83 mutex_lock(&sl->master->bus_mutex); 84 if (!w1_reset_select_slave(sl)) { 85 w1_write_8(sl->master, W1_CMD_READ_DATA); 86 w1_write_8(sl->master, reg); 87 *val = w1_read_8(sl->master); 88 *val |= w1_read_8(sl->master)<<8; 89 } else { 90 ret = -ENODEV; 91 } 92 mutex_unlock(&sl->master->bus_mutex); 93 94 return ret; 95 } 96 97 static int w1_reg_a8_v16_write(void *context, unsigned int reg, 98 unsigned int val) 99 { 100 struct device *dev = context; 101 struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 102 int ret = 0; 103 104 if (reg > 255) 105 return -EINVAL; 106 107 mutex_lock(&sl->master->bus_mutex); 108 if (!w1_reset_select_slave(sl)) { 109 w1_write_8(sl->master, W1_CMD_WRITE_DATA); 110 w1_write_8(sl->master, reg); 111 w1_write_8(sl->master, val & 0x00FF); 112 w1_write_8(sl->master, val>>8 & 0x00FF); 113 } else { 114 ret = -ENODEV; 115 } 116 mutex_unlock(&sl->master->bus_mutex); 117 118 return ret; 119 } 120 121 /* 122 * 1-Wire slaves registers with addess 16 bit and data 16 bit 123 */ 124 125 static int w1_reg_a16_v16_read(void *context, unsigned int reg, 126 unsigned int *val) 127 { 128 struct device *dev = context; 129 struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 130 int ret = 0; 131 132 if (reg > 65535) 133 return -EINVAL; 134 135 mutex_lock(&sl->master->bus_mutex); 136 if (!w1_reset_select_slave(sl)) { 137 w1_write_8(sl->master, W1_CMD_READ_DATA); 138 w1_write_8(sl->master, reg & 0x00FF); 139 w1_write_8(sl->master, reg>>8 & 0x00FF); 140 *val = w1_read_8(sl->master); 141 *val |= w1_read_8(sl->master)<<8; 142 } else { 143 ret = -ENODEV; 144 } 145 mutex_unlock(&sl->master->bus_mutex); 146 147 return ret; 148 } 149 150 static int w1_reg_a16_v16_write(void *context, unsigned int reg, 151 unsigned int val) 152 { 153 struct device *dev = context; 154 struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 155 int ret = 0; 156 157 if (reg > 65535) 158 return -EINVAL; 159 160 mutex_lock(&sl->master->bus_mutex); 161 if (!w1_reset_select_slave(sl)) { 162 w1_write_8(sl->master, W1_CMD_WRITE_DATA); 163 w1_write_8(sl->master, reg & 0x00FF); 164 w1_write_8(sl->master, reg>>8 & 0x00FF); 165 w1_write_8(sl->master, val & 0x00FF); 166 w1_write_8(sl->master, val>>8 & 0x00FF); 167 } else { 168 ret = -ENODEV; 169 } 170 mutex_unlock(&sl->master->bus_mutex); 171 172 return ret; 173 } 174 175 /* 176 * Various types of supported bus addressing 177 */ 178 179 static struct regmap_bus regmap_w1_bus_a8_v8 = { 180 .reg_read = w1_reg_a8_v8_read, 181 .reg_write = w1_reg_a8_v8_write, 182 }; 183 184 static struct regmap_bus regmap_w1_bus_a8_v16 = { 185 .reg_read = w1_reg_a8_v16_read, 186 .reg_write = w1_reg_a8_v16_write, 187 }; 188 189 static struct regmap_bus regmap_w1_bus_a16_v16 = { 190 .reg_read = w1_reg_a16_v16_read, 191 .reg_write = w1_reg_a16_v16_write, 192 }; 193 194 static const struct regmap_bus *regmap_get_w1_bus(struct device *w1_dev, 195 const struct regmap_config *config) 196 { 197 if (config->reg_bits == 8 && config->val_bits == 8) 198 return ®map_w1_bus_a8_v8; 199 200 if (config->reg_bits == 8 && config->val_bits == 16) 201 return ®map_w1_bus_a8_v16; 202 203 if (config->reg_bits == 16 && config->val_bits == 16) 204 return ®map_w1_bus_a16_v16; 205 206 return ERR_PTR(-ENOTSUPP); 207 } 208 209 struct regmap *__regmap_init_w1(struct device *w1_dev, 210 const struct regmap_config *config, 211 struct lock_class_key *lock_key, 212 const char *lock_name) 213 { 214 215 const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config); 216 217 if (IS_ERR(bus)) 218 return ERR_CAST(bus); 219 220 return __regmap_init(w1_dev, bus, w1_dev, config, 221 lock_key, lock_name); 222 223 return NULL; 224 } 225 EXPORT_SYMBOL_GPL(__regmap_init_w1); 226 227 struct regmap *__devm_regmap_init_w1(struct device *w1_dev, 228 const struct regmap_config *config, 229 struct lock_class_key *lock_key, 230 const char *lock_name) 231 { 232 233 const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config); 234 235 if (IS_ERR(bus)) 236 return ERR_CAST(bus); 237 238 return __devm_regmap_init(w1_dev, bus, w1_dev, config, 239 lock_key, lock_name); 240 241 return NULL; 242 } 243 EXPORT_SYMBOL_GPL(__devm_regmap_init_w1); 244 245 MODULE_LICENSE("GPL"); 246