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