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, ®map_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, ®map_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, ®map_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, ®map_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