Linux Audio

Check our new training course

Loading...
v3.15
  1/*
  2 * Register cache access API - LZO caching support
  3 *
  4 * Copyright 2011 Wolfson Microelectronics plc
  5 *
  6 * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
  7 *
  8 * This program is free software; you can redistribute it and/or modify
  9 * it under the terms of the GNU General Public License version 2 as
 10 * published by the Free Software Foundation.
 11 */
 12
 13#include <linux/slab.h>
 14#include <linux/device.h>
 15#include <linux/lzo.h>
 
 16
 17#include "internal.h"
 18
 19static int regcache_lzo_exit(struct regmap *map);
 20
 21struct regcache_lzo_ctx {
 22	void *wmem;
 23	void *dst;
 24	const void *src;
 25	size_t src_len;
 26	size_t dst_len;
 27	size_t decompressed_size;
 28	unsigned long *sync_bmp;
 29	int sync_bmp_nbits;
 30};
 31
 32#define LZO_BLOCK_NUM 8
 33static int regcache_lzo_block_count(struct regmap *map)
 34{
 35	return LZO_BLOCK_NUM;
 36}
 37
 38static int regcache_lzo_prepare(struct regcache_lzo_ctx *lzo_ctx)
 39{
 40	lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
 41	if (!lzo_ctx->wmem)
 42		return -ENOMEM;
 43	return 0;
 44}
 45
 46static int regcache_lzo_compress(struct regcache_lzo_ctx *lzo_ctx)
 47{
 48	size_t compress_size;
 49	int ret;
 50
 51	ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
 52			       lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
 53	if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
 54		return -EINVAL;
 55	lzo_ctx->dst_len = compress_size;
 56	return 0;
 57}
 58
 59static int regcache_lzo_decompress(struct regcache_lzo_ctx *lzo_ctx)
 60{
 61	size_t dst_len;
 62	int ret;
 63
 64	dst_len = lzo_ctx->dst_len;
 65	ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
 66				    lzo_ctx->dst, &dst_len);
 67	if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
 68		return -EINVAL;
 69	return 0;
 70}
 71
 72static int regcache_lzo_compress_cache_block(struct regmap *map,
 73		struct regcache_lzo_ctx *lzo_ctx)
 74{
 75	int ret;
 76
 77	lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
 78	lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
 79	if (!lzo_ctx->dst) {
 80		lzo_ctx->dst_len = 0;
 81		return -ENOMEM;
 82	}
 83
 84	ret = regcache_lzo_compress(lzo_ctx);
 85	if (ret < 0)
 86		return ret;
 87	return 0;
 88}
 89
 90static int regcache_lzo_decompress_cache_block(struct regmap *map,
 91		struct regcache_lzo_ctx *lzo_ctx)
 92{
 93	int ret;
 94
 95	lzo_ctx->dst_len = lzo_ctx->decompressed_size;
 96	lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
 97	if (!lzo_ctx->dst) {
 98		lzo_ctx->dst_len = 0;
 99		return -ENOMEM;
100	}
101
102	ret = regcache_lzo_decompress(lzo_ctx);
103	if (ret < 0)
104		return ret;
105	return 0;
106}
107
108static inline int regcache_lzo_get_blkindex(struct regmap *map,
109					    unsigned int reg)
110{
111	return ((reg / map->reg_stride) * map->cache_word_size) /
112		DIV_ROUND_UP(map->cache_size_raw,
113			     regcache_lzo_block_count(map));
114}
115
116static inline int regcache_lzo_get_blkpos(struct regmap *map,
117					  unsigned int reg)
118{
119	return (reg / map->reg_stride) %
120		    (DIV_ROUND_UP(map->cache_size_raw,
121				  regcache_lzo_block_count(map)) /
122		     map->cache_word_size);
123}
124
125static inline int regcache_lzo_get_blksize(struct regmap *map)
126{
127	return DIV_ROUND_UP(map->cache_size_raw,
128			    regcache_lzo_block_count(map));
129}
130
131static int regcache_lzo_init(struct regmap *map)
132{
133	struct regcache_lzo_ctx **lzo_blocks;
134	size_t bmp_size;
135	int ret, i, blksize, blkcount;
136	const char *p, *end;
137	unsigned long *sync_bmp;
138
139	ret = 0;
140
141	blkcount = regcache_lzo_block_count(map);
142	map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
143			     GFP_KERNEL);
144	if (!map->cache)
145		return -ENOMEM;
146	lzo_blocks = map->cache;
147
148	/*
149	 * allocate a bitmap to be used when syncing the cache with
150	 * the hardware.  Each time a register is modified, the corresponding
151	 * bit is set in the bitmap, so we know that we have to sync
152	 * that register.
153	 */
154	bmp_size = map->num_reg_defaults_raw;
155	sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
156			   GFP_KERNEL);
157	if (!sync_bmp) {
158		ret = -ENOMEM;
159		goto err;
160	}
161	bitmap_zero(sync_bmp, bmp_size);
162
163	/* allocate the lzo blocks and initialize them */
164	for (i = 0; i < blkcount; i++) {
165		lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
166					GFP_KERNEL);
167		if (!lzo_blocks[i]) {
168			kfree(sync_bmp);
169			ret = -ENOMEM;
170			goto err;
171		}
172		lzo_blocks[i]->sync_bmp = sync_bmp;
173		lzo_blocks[i]->sync_bmp_nbits = bmp_size;
174		/* alloc the working space for the compressed block */
175		ret = regcache_lzo_prepare(lzo_blocks[i]);
176		if (ret < 0)
177			goto err;
178	}
179
180	blksize = regcache_lzo_get_blksize(map);
181	p = map->reg_defaults_raw;
182	end = map->reg_defaults_raw + map->cache_size_raw;
183	/* compress the register map and fill the lzo blocks */
184	for (i = 0; i < blkcount; i++, p += blksize) {
185		lzo_blocks[i]->src = p;
186		if (p + blksize > end)
187			lzo_blocks[i]->src_len = end - p;
188		else
189			lzo_blocks[i]->src_len = blksize;
190		ret = regcache_lzo_compress_cache_block(map,
191						       lzo_blocks[i]);
192		if (ret < 0)
193			goto err;
194		lzo_blocks[i]->decompressed_size =
195			lzo_blocks[i]->src_len;
196	}
197
198	return 0;
199err:
200	regcache_lzo_exit(map);
201	return ret;
202}
203
204static int regcache_lzo_exit(struct regmap *map)
205{
206	struct regcache_lzo_ctx **lzo_blocks;
207	int i, blkcount;
208
209	lzo_blocks = map->cache;
210	if (!lzo_blocks)
211		return 0;
212
213	blkcount = regcache_lzo_block_count(map);
214	/*
215	 * the pointer to the bitmap used for syncing the cache
216	 * is shared amongst all lzo_blocks.  Ensure it is freed
217	 * only once.
218	 */
219	if (lzo_blocks[0])
220		kfree(lzo_blocks[0]->sync_bmp);
221	for (i = 0; i < blkcount; i++) {
222		if (lzo_blocks[i]) {
223			kfree(lzo_blocks[i]->wmem);
224			kfree(lzo_blocks[i]->dst);
225		}
226		/* each lzo_block is a pointer returned by kmalloc or NULL */
227		kfree(lzo_blocks[i]);
228	}
229	kfree(lzo_blocks);
230	map->cache = NULL;
231	return 0;
232}
233
234static int regcache_lzo_read(struct regmap *map,
235			     unsigned int reg, unsigned int *value)
236{
237	struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
238	int ret, blkindex, blkpos;
239	size_t blksize, tmp_dst_len;
240	void *tmp_dst;
241
242	/* index of the compressed lzo block */
243	blkindex = regcache_lzo_get_blkindex(map, reg);
244	/* register index within the decompressed block */
245	blkpos = regcache_lzo_get_blkpos(map, reg);
246	/* size of the compressed block */
247	blksize = regcache_lzo_get_blksize(map);
248	lzo_blocks = map->cache;
249	lzo_block = lzo_blocks[blkindex];
250
251	/* save the pointer and length of the compressed block */
252	tmp_dst = lzo_block->dst;
253	tmp_dst_len = lzo_block->dst_len;
254
255	/* prepare the source to be the compressed block */
256	lzo_block->src = lzo_block->dst;
257	lzo_block->src_len = lzo_block->dst_len;
258
259	/* decompress the block */
260	ret = regcache_lzo_decompress_cache_block(map, lzo_block);
261	if (ret >= 0)
262		/* fetch the value from the cache */
263		*value = regcache_get_val(map, lzo_block->dst, blkpos);
264
265	kfree(lzo_block->dst);
266	/* restore the pointer and length of the compressed block */
267	lzo_block->dst = tmp_dst;
268	lzo_block->dst_len = tmp_dst_len;
269
270	return ret;
271}
272
273static int regcache_lzo_write(struct regmap *map,
274			      unsigned int reg, unsigned int value)
275{
276	struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
277	int ret, blkindex, blkpos;
278	size_t blksize, tmp_dst_len;
279	void *tmp_dst;
280
281	/* index of the compressed lzo block */
282	blkindex = regcache_lzo_get_blkindex(map, reg);
283	/* register index within the decompressed block */
284	blkpos = regcache_lzo_get_blkpos(map, reg);
285	/* size of the compressed block */
286	blksize = regcache_lzo_get_blksize(map);
287	lzo_blocks = map->cache;
288	lzo_block = lzo_blocks[blkindex];
289
290	/* save the pointer and length of the compressed block */
291	tmp_dst = lzo_block->dst;
292	tmp_dst_len = lzo_block->dst_len;
293
294	/* prepare the source to be the compressed block */
295	lzo_block->src = lzo_block->dst;
296	lzo_block->src_len = lzo_block->dst_len;
297
298	/* decompress the block */
299	ret = regcache_lzo_decompress_cache_block(map, lzo_block);
300	if (ret < 0) {
301		kfree(lzo_block->dst);
302		goto out;
303	}
304
305	/* write the new value to the cache */
306	if (regcache_set_val(map, lzo_block->dst, blkpos, value)) {
307		kfree(lzo_block->dst);
308		goto out;
309	}
310
311	/* prepare the source to be the decompressed block */
312	lzo_block->src = lzo_block->dst;
313	lzo_block->src_len = lzo_block->dst_len;
314
315	/* compress the block */
316	ret = regcache_lzo_compress_cache_block(map, lzo_block);
317	if (ret < 0) {
318		kfree(lzo_block->dst);
319		kfree(lzo_block->src);
320		goto out;
321	}
322
323	/* set the bit so we know we have to sync this register */
324	set_bit(reg / map->reg_stride, lzo_block->sync_bmp);
325	kfree(tmp_dst);
326	kfree(lzo_block->src);
327	return 0;
328out:
329	lzo_block->dst = tmp_dst;
330	lzo_block->dst_len = tmp_dst_len;
331	return ret;
332}
333
334static int regcache_lzo_sync(struct regmap *map, unsigned int min,
335			     unsigned int max)
336{
337	struct regcache_lzo_ctx **lzo_blocks;
338	unsigned int val;
339	int i;
340	int ret;
341
342	lzo_blocks = map->cache;
343	i = min;
344	for_each_set_bit_from(i, lzo_blocks[0]->sync_bmp,
345			      lzo_blocks[0]->sync_bmp_nbits) {
346		if (i > max)
347			continue;
348
349		ret = regcache_read(map, i, &val);
350		if (ret)
351			return ret;
352
353		/* Is this the hardware default?  If so skip. */
354		ret = regcache_lookup_reg(map, i);
355		if (ret > 0 && val == map->reg_defaults[ret].def)
356			continue;
357
358		map->cache_bypass = 1;
359		ret = _regmap_write(map, i, val);
360		map->cache_bypass = 0;
361		if (ret)
362			return ret;
363		dev_dbg(map->dev, "Synced register %#x, value %#x\n",
364			i, val);
365	}
366
367	return 0;
368}
369
370struct regcache_ops regcache_lzo_ops = {
371	.type = REGCACHE_COMPRESSED,
372	.name = "lzo",
373	.init = regcache_lzo_init,
374	.exit = regcache_lzo_exit,
375	.read = regcache_lzo_read,
376	.write = regcache_lzo_write,
377	.sync = regcache_lzo_sync
378};
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// Register cache access API - LZO caching support
  4//
  5// Copyright 2011 Wolfson Microelectronics plc
  6//
  7// Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
 
 
 
 
  8
 
  9#include <linux/device.h>
 10#include <linux/lzo.h>
 11#include <linux/slab.h>
 12
 13#include "internal.h"
 14
 15static int regcache_lzo_exit(struct regmap *map);
 16
 17struct regcache_lzo_ctx {
 18	void *wmem;
 19	void *dst;
 20	const void *src;
 21	size_t src_len;
 22	size_t dst_len;
 23	size_t decompressed_size;
 24	unsigned long *sync_bmp;
 25	int sync_bmp_nbits;
 26};
 27
 28#define LZO_BLOCK_NUM 8
 29static int regcache_lzo_block_count(struct regmap *map)
 30{
 31	return LZO_BLOCK_NUM;
 32}
 33
 34static int regcache_lzo_prepare(struct regcache_lzo_ctx *lzo_ctx)
 35{
 36	lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
 37	if (!lzo_ctx->wmem)
 38		return -ENOMEM;
 39	return 0;
 40}
 41
 42static int regcache_lzo_compress(struct regcache_lzo_ctx *lzo_ctx)
 43{
 44	size_t compress_size;
 45	int ret;
 46
 47	ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
 48			       lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
 49	if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
 50		return -EINVAL;
 51	lzo_ctx->dst_len = compress_size;
 52	return 0;
 53}
 54
 55static int regcache_lzo_decompress(struct regcache_lzo_ctx *lzo_ctx)
 56{
 57	size_t dst_len;
 58	int ret;
 59
 60	dst_len = lzo_ctx->dst_len;
 61	ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
 62				    lzo_ctx->dst, &dst_len);
 63	if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
 64		return -EINVAL;
 65	return 0;
 66}
 67
 68static int regcache_lzo_compress_cache_block(struct regmap *map,
 69		struct regcache_lzo_ctx *lzo_ctx)
 70{
 71	int ret;
 72
 73	lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
 74	lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
 75	if (!lzo_ctx->dst) {
 76		lzo_ctx->dst_len = 0;
 77		return -ENOMEM;
 78	}
 79
 80	ret = regcache_lzo_compress(lzo_ctx);
 81	if (ret < 0)
 82		return ret;
 83	return 0;
 84}
 85
 86static int regcache_lzo_decompress_cache_block(struct regmap *map,
 87		struct regcache_lzo_ctx *lzo_ctx)
 88{
 89	int ret;
 90
 91	lzo_ctx->dst_len = lzo_ctx->decompressed_size;
 92	lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
 93	if (!lzo_ctx->dst) {
 94		lzo_ctx->dst_len = 0;
 95		return -ENOMEM;
 96	}
 97
 98	ret = regcache_lzo_decompress(lzo_ctx);
 99	if (ret < 0)
100		return ret;
101	return 0;
102}
103
104static inline int regcache_lzo_get_blkindex(struct regmap *map,
105					    unsigned int reg)
106{
107	return ((reg / map->reg_stride) * map->cache_word_size) /
108		DIV_ROUND_UP(map->cache_size_raw,
109			     regcache_lzo_block_count(map));
110}
111
112static inline int regcache_lzo_get_blkpos(struct regmap *map,
113					  unsigned int reg)
114{
115	return (reg / map->reg_stride) %
116		    (DIV_ROUND_UP(map->cache_size_raw,
117				  regcache_lzo_block_count(map)) /
118		     map->cache_word_size);
119}
120
121static inline int regcache_lzo_get_blksize(struct regmap *map)
122{
123	return DIV_ROUND_UP(map->cache_size_raw,
124			    regcache_lzo_block_count(map));
125}
126
127static int regcache_lzo_init(struct regmap *map)
128{
129	struct regcache_lzo_ctx **lzo_blocks;
130	size_t bmp_size;
131	int ret, i, blksize, blkcount;
132	const char *p, *end;
133	unsigned long *sync_bmp;
134
135	ret = 0;
136
137	blkcount = regcache_lzo_block_count(map);
138	map->cache = kcalloc(blkcount, sizeof(*lzo_blocks),
139			     GFP_KERNEL);
140	if (!map->cache)
141		return -ENOMEM;
142	lzo_blocks = map->cache;
143
144	/*
145	 * allocate a bitmap to be used when syncing the cache with
146	 * the hardware.  Each time a register is modified, the corresponding
147	 * bit is set in the bitmap, so we know that we have to sync
148	 * that register.
149	 */
150	bmp_size = map->num_reg_defaults_raw;
151	sync_bmp = bitmap_zalloc(bmp_size, GFP_KERNEL);
 
152	if (!sync_bmp) {
153		ret = -ENOMEM;
154		goto err;
155	}
 
156
157	/* allocate the lzo blocks and initialize them */
158	for (i = 0; i < blkcount; i++) {
159		lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
160					GFP_KERNEL);
161		if (!lzo_blocks[i]) {
162			bitmap_free(sync_bmp);
163			ret = -ENOMEM;
164			goto err;
165		}
166		lzo_blocks[i]->sync_bmp = sync_bmp;
167		lzo_blocks[i]->sync_bmp_nbits = bmp_size;
168		/* alloc the working space for the compressed block */
169		ret = regcache_lzo_prepare(lzo_blocks[i]);
170		if (ret < 0)
171			goto err;
172	}
173
174	blksize = regcache_lzo_get_blksize(map);
175	p = map->reg_defaults_raw;
176	end = map->reg_defaults_raw + map->cache_size_raw;
177	/* compress the register map and fill the lzo blocks */
178	for (i = 0; i < blkcount; i++, p += blksize) {
179		lzo_blocks[i]->src = p;
180		if (p + blksize > end)
181			lzo_blocks[i]->src_len = end - p;
182		else
183			lzo_blocks[i]->src_len = blksize;
184		ret = regcache_lzo_compress_cache_block(map,
185						       lzo_blocks[i]);
186		if (ret < 0)
187			goto err;
188		lzo_blocks[i]->decompressed_size =
189			lzo_blocks[i]->src_len;
190	}
191
192	return 0;
193err:
194	regcache_lzo_exit(map);
195	return ret;
196}
197
198static int regcache_lzo_exit(struct regmap *map)
199{
200	struct regcache_lzo_ctx **lzo_blocks;
201	int i, blkcount;
202
203	lzo_blocks = map->cache;
204	if (!lzo_blocks)
205		return 0;
206
207	blkcount = regcache_lzo_block_count(map);
208	/*
209	 * the pointer to the bitmap used for syncing the cache
210	 * is shared amongst all lzo_blocks.  Ensure it is freed
211	 * only once.
212	 */
213	if (lzo_blocks[0])
214		bitmap_free(lzo_blocks[0]->sync_bmp);
215	for (i = 0; i < blkcount; i++) {
216		if (lzo_blocks[i]) {
217			kfree(lzo_blocks[i]->wmem);
218			kfree(lzo_blocks[i]->dst);
219		}
220		/* each lzo_block is a pointer returned by kmalloc or NULL */
221		kfree(lzo_blocks[i]);
222	}
223	kfree(lzo_blocks);
224	map->cache = NULL;
225	return 0;
226}
227
228static int regcache_lzo_read(struct regmap *map,
229			     unsigned int reg, unsigned int *value)
230{
231	struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
232	int ret, blkindex, blkpos;
233	size_t tmp_dst_len;
234	void *tmp_dst;
235
236	/* index of the compressed lzo block */
237	blkindex = regcache_lzo_get_blkindex(map, reg);
238	/* register index within the decompressed block */
239	blkpos = regcache_lzo_get_blkpos(map, reg);
 
 
240	lzo_blocks = map->cache;
241	lzo_block = lzo_blocks[blkindex];
242
243	/* save the pointer and length of the compressed block */
244	tmp_dst = lzo_block->dst;
245	tmp_dst_len = lzo_block->dst_len;
246
247	/* prepare the source to be the compressed block */
248	lzo_block->src = lzo_block->dst;
249	lzo_block->src_len = lzo_block->dst_len;
250
251	/* decompress the block */
252	ret = regcache_lzo_decompress_cache_block(map, lzo_block);
253	if (ret >= 0)
254		/* fetch the value from the cache */
255		*value = regcache_get_val(map, lzo_block->dst, blkpos);
256
257	kfree(lzo_block->dst);
258	/* restore the pointer and length of the compressed block */
259	lzo_block->dst = tmp_dst;
260	lzo_block->dst_len = tmp_dst_len;
261
262	return ret;
263}
264
265static int regcache_lzo_write(struct regmap *map,
266			      unsigned int reg, unsigned int value)
267{
268	struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
269	int ret, blkindex, blkpos;
270	size_t tmp_dst_len;
271	void *tmp_dst;
272
273	/* index of the compressed lzo block */
274	blkindex = regcache_lzo_get_blkindex(map, reg);
275	/* register index within the decompressed block */
276	blkpos = regcache_lzo_get_blkpos(map, reg);
 
 
277	lzo_blocks = map->cache;
278	lzo_block = lzo_blocks[blkindex];
279
280	/* save the pointer and length of the compressed block */
281	tmp_dst = lzo_block->dst;
282	tmp_dst_len = lzo_block->dst_len;
283
284	/* prepare the source to be the compressed block */
285	lzo_block->src = lzo_block->dst;
286	lzo_block->src_len = lzo_block->dst_len;
287
288	/* decompress the block */
289	ret = regcache_lzo_decompress_cache_block(map, lzo_block);
290	if (ret < 0) {
291		kfree(lzo_block->dst);
292		goto out;
293	}
294
295	/* write the new value to the cache */
296	if (regcache_set_val(map, lzo_block->dst, blkpos, value)) {
297		kfree(lzo_block->dst);
298		goto out;
299	}
300
301	/* prepare the source to be the decompressed block */
302	lzo_block->src = lzo_block->dst;
303	lzo_block->src_len = lzo_block->dst_len;
304
305	/* compress the block */
306	ret = regcache_lzo_compress_cache_block(map, lzo_block);
307	if (ret < 0) {
308		kfree(lzo_block->dst);
309		kfree(lzo_block->src);
310		goto out;
311	}
312
313	/* set the bit so we know we have to sync this register */
314	set_bit(reg / map->reg_stride, lzo_block->sync_bmp);
315	kfree(tmp_dst);
316	kfree(lzo_block->src);
317	return 0;
318out:
319	lzo_block->dst = tmp_dst;
320	lzo_block->dst_len = tmp_dst_len;
321	return ret;
322}
323
324static int regcache_lzo_sync(struct regmap *map, unsigned int min,
325			     unsigned int max)
326{
327	struct regcache_lzo_ctx **lzo_blocks;
328	unsigned int val;
329	int i;
330	int ret;
331
332	lzo_blocks = map->cache;
333	i = min;
334	for_each_set_bit_from(i, lzo_blocks[0]->sync_bmp,
335			      lzo_blocks[0]->sync_bmp_nbits) {
336		if (i > max)
337			continue;
338
339		ret = regcache_read(map, i, &val);
340		if (ret)
341			return ret;
342
343		/* Is this the hardware default?  If so skip. */
344		ret = regcache_lookup_reg(map, i);
345		if (ret > 0 && val == map->reg_defaults[ret].def)
346			continue;
347
348		map->cache_bypass = true;
349		ret = _regmap_write(map, i, val);
350		map->cache_bypass = false;
351		if (ret)
352			return ret;
353		dev_dbg(map->dev, "Synced register %#x, value %#x\n",
354			i, val);
355	}
356
357	return 0;
358}
359
360struct regcache_ops regcache_lzo_ops = {
361	.type = REGCACHE_COMPRESSED,
362	.name = "lzo",
363	.init = regcache_lzo_init,
364	.exit = regcache_lzo_exit,
365	.read = regcache_lzo_read,
366	.write = regcache_lzo_write,
367	.sync = regcache_lzo_sync
368};