blob: 4d8fbb8c708b41db4904997022b57dfb9c6f7026 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302/*
3 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/device.h>
7#include <linux/slab.h>
8#include <linux/mutex.h>
9#include <linux/regmap.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010#include <linux/module.h>
11#include <linux/init.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053012#include <soc/soundwire.h>
13#include <soc/internal.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053014
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053015
16static int regmap_swr_gather_write(void *context,
17 const void *reg, size_t reg_size,
18 const void *val, size_t val_len)
19{
20 struct device *dev = context;
21 struct swr_device *swr = to_swr_device(dev);
22 struct regmap *map = dev_get_regmap(dev, NULL);
23 size_t addr_bytes;
24 size_t val_bytes;
25 int i, ret = 0;
26 u16 reg_addr = 0;
27 u8 *value;
28
29 if (map == NULL) {
30 dev_err(dev, "%s: regmap is NULL\n", __func__);
31 return -EINVAL;
32 }
33 addr_bytes = map->format.reg_bytes;
34 if (swr == NULL) {
35 dev_err(dev, "%s: swr device is NULL\n", __func__);
36 return -EINVAL;
37 }
38 if (reg_size != addr_bytes) {
39 dev_err(dev, "%s: reg size %zd bytes not supported\n",
40 __func__, reg_size);
41 return -EINVAL;
42 }
43 reg_addr = *(u16 *)reg;
44 val_bytes = map->format.val_bytes;
45 /* val_len = val_bytes * val_count */
46 for (i = 0; i < (val_len / val_bytes); i++) {
47 value = (u8 *)val + (val_bytes * i);
48 ret = swr_write(swr, swr->dev_num, (reg_addr + i), value);
49 if (ret < 0) {
50 dev_err(dev, "%s: write reg 0x%x failed, err %d\n",
51 __func__, (reg_addr + i), ret);
52 break;
53 }
54 }
55 return ret;
56}
57
58static int regmap_swr_raw_multi_reg_write(void *context, const void *data,
59 size_t count)
60{
61 struct device *dev = context;
62 struct swr_device *swr = to_swr_device(dev);
63 struct regmap *map = dev_get_regmap(dev, NULL);
64 size_t addr_bytes;
65 size_t val_bytes;
66 size_t pad_bytes;
67 size_t num_regs;
68 int i = 0;
69 int ret = 0;
70 u16 *reg;
71 u8 *val;
72 u8 *buf;
73
74 if (swr == NULL) {
75 dev_err(dev, "%s: swr device is NULL\n", __func__);
76 return -EINVAL;
77 }
78
79 if (map == NULL) {
80 dev_err(dev, "%s: regmap is NULL\n", __func__);
81 return -EINVAL;
82 }
83
84 addr_bytes = map->format.reg_bytes;
85 val_bytes = map->format.val_bytes;
86 pad_bytes = map->format.pad_bytes;
87
88 if (addr_bytes + val_bytes + pad_bytes == 0) {
89 dev_err(dev, "%s: sum of addr, value and pad is 0\n", __func__);
90 return -EINVAL;
91 }
92 num_regs = count / (addr_bytes + val_bytes + pad_bytes);
93
94 reg = kcalloc(num_regs, sizeof(u16), GFP_KERNEL);
95 if (!reg)
96 return -ENOMEM;
97
98 val = kcalloc(num_regs, sizeof(u8), GFP_KERNEL);
99 if (!val) {
100 ret = -ENOMEM;
101 goto mem_fail;
102 }
103
104 buf = (u8 *)data;
105 for (i = 0; i < num_regs; i++) {
106 reg[i] = *(u16 *)buf;
107 buf += (map->format.reg_bytes + map->format.pad_bytes);
108 val[i] = *buf;
109 buf += map->format.val_bytes;
110 }
111 ret = swr_bulk_write(swr, swr->dev_num, reg, val, num_regs);
112 if (ret)
113 dev_err(dev, "%s: multi reg write failed\n", __func__);
114
115 kfree(val);
116mem_fail:
117 kfree(reg);
118 return ret;
119}
120
121static int regmap_swr_write(void *context, const void *data, size_t count)
122{
123 struct device *dev = context;
124 struct regmap *map = dev_get_regmap(dev, NULL);
125 size_t addr_bytes;
126 size_t val_bytes;
127 size_t pad_bytes;
128
129 if (map == NULL) {
130 dev_err(dev, "%s: regmap is NULL\n", __func__);
131 return -EINVAL;
132 }
133 addr_bytes = map->format.reg_bytes;
134 val_bytes = map->format.val_bytes;
135 pad_bytes = map->format.pad_bytes;
136
137 WARN_ON(count < addr_bytes);
138
139 if (count > (addr_bytes + val_bytes + pad_bytes))
140 return regmap_swr_raw_multi_reg_write(context, data, count);
141 else
142 return regmap_swr_gather_write(context, data, addr_bytes,
143 (data + addr_bytes),
144 (count - addr_bytes));
145}
146
147static int regmap_swr_read(void *context,
148 const void *reg, size_t reg_size,
149 void *val, size_t val_size)
150{
151 struct device *dev = context;
152 struct swr_device *swr = to_swr_device(dev);
153 struct regmap *map = dev_get_regmap(dev, NULL);
154 size_t addr_bytes;
155 int ret = 0;
156 u16 reg_addr = 0;
157
158 if (map == NULL) {
159 dev_err(dev, "%s: regmap is NULL\n", __func__);
160 return -EINVAL;
161 }
162 addr_bytes = map->format.reg_bytes;
163 if (swr == NULL) {
164 dev_err(dev, "%s: swr is NULL\n", __func__);
165 return -EINVAL;
166 }
167 if (reg_size != addr_bytes) {
168 dev_err(dev, "%s: register size %zd bytes not supported\n",
169 __func__, reg_size);
170 return -EINVAL;
171 }
172 reg_addr = *(u16 *)reg;
173 ret = swr_read(swr, swr->dev_num, reg_addr, val, val_size);
174 if (ret < 0)
175 dev_err(dev, "%s: codec reg 0x%x read failed %d\n",
176 __func__, reg_addr, ret);
177 return ret;
178}
179
180static struct regmap_bus regmap_swr = {
181 .write = regmap_swr_write,
182 .gather_write = regmap_swr_gather_write,
183 .read = regmap_swr_read,
184 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
185 .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
186};
187
188struct regmap *__regmap_init_swr(struct swr_device *swr,
189 const struct regmap_config *config,
190 struct lock_class_key *lock_key,
191 const char *lock_name)
192{
193 return __regmap_init(&swr->dev, &regmap_swr, &swr->dev, config,
194 lock_key, lock_name);
195}
196EXPORT_SYMBOL(__regmap_init_swr);
197
198struct regmap *__devm_regmap_init_swr(struct swr_device *swr,
199 const struct regmap_config *config,
200 struct lock_class_key *lock_key,
201 const char *lock_name)
202{
203 return __devm_regmap_init(&swr->dev, &regmap_swr, &swr->dev, config,
204 lock_key, lock_name);
205}
206EXPORT_SYMBOL(__devm_regmap_init_swr);
207
208MODULE_LICENSE("GPL v2");