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