xref: /OK3568_Linux_fs/kernel/drivers/base/regmap/regmap-spmi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Register map access API - SPMI support
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
6*4882a593Smuzhiyun //
7*4882a593Smuzhiyun // Based on regmap-i2c.c:
8*4882a593Smuzhiyun // Copyright 2011 Wolfson Microelectronics plc
9*4882a593Smuzhiyun // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/regmap.h>
12*4882a593Smuzhiyun #include <linux/spmi.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun 
regmap_spmi_base_read(void * context,const void * reg,size_t reg_size,void * val,size_t val_size)16*4882a593Smuzhiyun static int regmap_spmi_base_read(void *context,
17*4882a593Smuzhiyun 				 const void *reg, size_t reg_size,
18*4882a593Smuzhiyun 				 void *val, size_t val_size)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun 	u8 addr = *(u8 *)reg;
21*4882a593Smuzhiyun 	int err = 0;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	BUG_ON(reg_size != 1);
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	while (val_size-- && !err)
26*4882a593Smuzhiyun 		err = spmi_register_read(context, addr++, val++);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	return err;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
regmap_spmi_base_gather_write(void * context,const void * reg,size_t reg_size,const void * val,size_t val_size)31*4882a593Smuzhiyun static int regmap_spmi_base_gather_write(void *context,
32*4882a593Smuzhiyun 					 const void *reg, size_t reg_size,
33*4882a593Smuzhiyun 					 const void *val, size_t val_size)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	const u8 *data = val;
36*4882a593Smuzhiyun 	u8 addr = *(u8 *)reg;
37*4882a593Smuzhiyun 	int err = 0;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	BUG_ON(reg_size != 1);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	/*
42*4882a593Smuzhiyun 	 * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
43*4882a593Smuzhiyun 	 * use it when possible.
44*4882a593Smuzhiyun 	 */
45*4882a593Smuzhiyun 	if (addr == 0 && val_size) {
46*4882a593Smuzhiyun 		err = spmi_register_zero_write(context, *data);
47*4882a593Smuzhiyun 		if (err)
48*4882a593Smuzhiyun 			goto err_out;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 		data++;
51*4882a593Smuzhiyun 		addr++;
52*4882a593Smuzhiyun 		val_size--;
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	while (val_size) {
56*4882a593Smuzhiyun 		err = spmi_register_write(context, addr, *data);
57*4882a593Smuzhiyun 		if (err)
58*4882a593Smuzhiyun 			goto err_out;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 		data++;
61*4882a593Smuzhiyun 		addr++;
62*4882a593Smuzhiyun 		val_size--;
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun err_out:
66*4882a593Smuzhiyun 	return err;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
regmap_spmi_base_write(void * context,const void * data,size_t count)69*4882a593Smuzhiyun static int regmap_spmi_base_write(void *context, const void *data,
70*4882a593Smuzhiyun 				  size_t count)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	BUG_ON(count < 1);
73*4882a593Smuzhiyun 	return regmap_spmi_base_gather_write(context, data, 1, data + 1,
74*4882a593Smuzhiyun 					     count - 1);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static const struct regmap_bus regmap_spmi_base = {
78*4882a593Smuzhiyun 	.read				= regmap_spmi_base_read,
79*4882a593Smuzhiyun 	.write				= regmap_spmi_base_write,
80*4882a593Smuzhiyun 	.gather_write			= regmap_spmi_base_gather_write,
81*4882a593Smuzhiyun 	.reg_format_endian_default	= REGMAP_ENDIAN_NATIVE,
82*4882a593Smuzhiyun 	.val_format_endian_default	= REGMAP_ENDIAN_NATIVE,
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
__regmap_init_spmi_base(struct spmi_device * sdev,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)85*4882a593Smuzhiyun struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,
86*4882a593Smuzhiyun 				       const struct regmap_config *config,
87*4882a593Smuzhiyun 				       struct lock_class_key *lock_key,
88*4882a593Smuzhiyun 				       const char *lock_name)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	return __regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
91*4882a593Smuzhiyun 			     lock_key, lock_name);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);
94*4882a593Smuzhiyun 
__devm_regmap_init_spmi_base(struct spmi_device * sdev,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)95*4882a593Smuzhiyun struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,
96*4882a593Smuzhiyun 					    const struct regmap_config *config,
97*4882a593Smuzhiyun 					    struct lock_class_key *lock_key,
98*4882a593Smuzhiyun 					    const char *lock_name)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	return __devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
101*4882a593Smuzhiyun 				  lock_key, lock_name);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);
104*4882a593Smuzhiyun 
regmap_spmi_ext_read(void * context,const void * reg,size_t reg_size,void * val,size_t val_size)105*4882a593Smuzhiyun static int regmap_spmi_ext_read(void *context,
106*4882a593Smuzhiyun 				const void *reg, size_t reg_size,
107*4882a593Smuzhiyun 				void *val, size_t val_size)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	int err = 0;
110*4882a593Smuzhiyun 	size_t len;
111*4882a593Smuzhiyun 	u16 addr;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	BUG_ON(reg_size != 2);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	addr = *(u16 *)reg;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	/*
118*4882a593Smuzhiyun 	 * Split accesses into two to take advantage of the more
119*4882a593Smuzhiyun 	 * bandwidth-efficient 'Extended Register Read' command when possible
120*4882a593Smuzhiyun 	 */
121*4882a593Smuzhiyun 	while (addr <= 0xFF && val_size) {
122*4882a593Smuzhiyun 		len = min_t(size_t, val_size, 16);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 		err = spmi_ext_register_read(context, addr, val, len);
125*4882a593Smuzhiyun 		if (err)
126*4882a593Smuzhiyun 			goto err_out;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 		addr += len;
129*4882a593Smuzhiyun 		val += len;
130*4882a593Smuzhiyun 		val_size -= len;
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	while (val_size) {
134*4882a593Smuzhiyun 		len = min_t(size_t, val_size, 8);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		err = spmi_ext_register_readl(context, addr, val, len);
137*4882a593Smuzhiyun 		if (err)
138*4882a593Smuzhiyun 			goto err_out;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 		addr += len;
141*4882a593Smuzhiyun 		val += len;
142*4882a593Smuzhiyun 		val_size -= len;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun err_out:
146*4882a593Smuzhiyun 	return err;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
regmap_spmi_ext_gather_write(void * context,const void * reg,size_t reg_size,const void * val,size_t val_size)149*4882a593Smuzhiyun static int regmap_spmi_ext_gather_write(void *context,
150*4882a593Smuzhiyun 					const void *reg, size_t reg_size,
151*4882a593Smuzhiyun 					const void *val, size_t val_size)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	int err = 0;
154*4882a593Smuzhiyun 	size_t len;
155*4882a593Smuzhiyun 	u16 addr;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	BUG_ON(reg_size != 2);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	addr = *(u16 *)reg;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	while (addr <= 0xFF && val_size) {
162*4882a593Smuzhiyun 		len = min_t(size_t, val_size, 16);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 		err = spmi_ext_register_write(context, addr, val, len);
165*4882a593Smuzhiyun 		if (err)
166*4882a593Smuzhiyun 			goto err_out;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 		addr += len;
169*4882a593Smuzhiyun 		val += len;
170*4882a593Smuzhiyun 		val_size -= len;
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	while (val_size) {
174*4882a593Smuzhiyun 		len = min_t(size_t, val_size, 8);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		err = spmi_ext_register_writel(context, addr, val, len);
177*4882a593Smuzhiyun 		if (err)
178*4882a593Smuzhiyun 			goto err_out;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		addr += len;
181*4882a593Smuzhiyun 		val += len;
182*4882a593Smuzhiyun 		val_size -= len;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun err_out:
186*4882a593Smuzhiyun 	return err;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
regmap_spmi_ext_write(void * context,const void * data,size_t count)189*4882a593Smuzhiyun static int regmap_spmi_ext_write(void *context, const void *data,
190*4882a593Smuzhiyun 				 size_t count)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	BUG_ON(count < 2);
193*4882a593Smuzhiyun 	return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
194*4882a593Smuzhiyun 					    count - 2);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun static const struct regmap_bus regmap_spmi_ext = {
198*4882a593Smuzhiyun 	.read				= regmap_spmi_ext_read,
199*4882a593Smuzhiyun 	.write				= regmap_spmi_ext_write,
200*4882a593Smuzhiyun 	.gather_write			= regmap_spmi_ext_gather_write,
201*4882a593Smuzhiyun 	.reg_format_endian_default	= REGMAP_ENDIAN_NATIVE,
202*4882a593Smuzhiyun 	.val_format_endian_default	= REGMAP_ENDIAN_NATIVE,
203*4882a593Smuzhiyun };
204*4882a593Smuzhiyun 
__regmap_init_spmi_ext(struct spmi_device * sdev,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)205*4882a593Smuzhiyun struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,
206*4882a593Smuzhiyun 				      const struct regmap_config *config,
207*4882a593Smuzhiyun 				      struct lock_class_key *lock_key,
208*4882a593Smuzhiyun 				      const char *lock_name)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	return __regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
211*4882a593Smuzhiyun 			     lock_key, lock_name);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);
214*4882a593Smuzhiyun 
__devm_regmap_init_spmi_ext(struct spmi_device * sdev,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)215*4882a593Smuzhiyun struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,
216*4882a593Smuzhiyun 					   const struct regmap_config *config,
217*4882a593Smuzhiyun 					   struct lock_class_key *lock_key,
218*4882a593Smuzhiyun 					   const char *lock_name)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	return __devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
221*4882a593Smuzhiyun 				  lock_key, lock_name);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun MODULE_LICENSE("GPL");
226