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