aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap/regcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r--drivers/base/regmap/regcache.c97
1 files changed, 73 insertions, 24 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 5cd2a37e7688..938cb1d2ea26 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -35,12 +35,17 @@ static int regcache_hw_init(struct regmap *map)
35 return -EINVAL; 35 return -EINVAL;
36 36
37 if (!map->reg_defaults_raw) { 37 if (!map->reg_defaults_raw) {
38 u32 cache_bypass = map->cache_bypass;
38 dev_warn(map->dev, "No cache defaults, reading back from HW\n"); 39 dev_warn(map->dev, "No cache defaults, reading back from HW\n");
40
41 /* Bypass the cache access till data read from HW*/
42 map->cache_bypass = 1;
39 tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); 43 tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
40 if (!tmp_buf) 44 if (!tmp_buf)
41 return -EINVAL; 45 return -EINVAL;
42 ret = regmap_bulk_read(map, 0, tmp_buf, 46 ret = regmap_bulk_read(map, 0, tmp_buf,
43 map->num_reg_defaults_raw); 47 map->num_reg_defaults_raw);
48 map->cache_bypass = cache_bypass;
44 if (ret < 0) { 49 if (ret < 0) {
45 kfree(tmp_buf); 50 kfree(tmp_buf);
46 return ret; 51 return ret;
@@ -211,7 +216,6 @@ int regcache_read(struct regmap *map,
211 216
212 return -EINVAL; 217 return -EINVAL;
213} 218}
214EXPORT_SYMBOL_GPL(regcache_read);
215 219
216/** 220/**
217 * regcache_write: Set the value of a given register in the cache. 221 * regcache_write: Set the value of a given register in the cache.
@@ -238,7 +242,6 @@ int regcache_write(struct regmap *map,
238 242
239 return 0; 243 return 0;
240} 244}
241EXPORT_SYMBOL_GPL(regcache_write);
242 245
243/** 246/**
244 * regcache_sync: Sync the register cache with the hardware. 247 * regcache_sync: Sync the register cache with the hardware.
@@ -254,12 +257,11 @@ EXPORT_SYMBOL_GPL(regcache_write);
254int regcache_sync(struct regmap *map) 257int regcache_sync(struct regmap *map)
255{ 258{
256 int ret = 0; 259 int ret = 0;
257 unsigned int val;
258 unsigned int i; 260 unsigned int i;
259 const char *name; 261 const char *name;
260 unsigned int bypass; 262 unsigned int bypass;
261 263
262 BUG_ON(!map->cache_ops); 264 BUG_ON(!map->cache_ops || !map->cache_ops->sync);
263 265
264 mutex_lock(&map->lock); 266 mutex_lock(&map->lock);
265 /* Remember the initial bypass state */ 267 /* Remember the initial bypass state */
@@ -269,7 +271,11 @@ int regcache_sync(struct regmap *map)
269 name = map->cache_ops->name; 271 name = map->cache_ops->name;
270 trace_regcache_sync(map->dev, name, "start"); 272 trace_regcache_sync(map->dev, name, "start");
271 273
274 if (!map->cache_dirty)
275 goto out;
276
272 /* Apply any patch first */ 277 /* Apply any patch first */
278 map->cache_bypass = 1;
273 for (i = 0; i < map->patch_regs; i++) { 279 for (i = 0; i < map->patch_regs; i++) {
274 ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); 280 ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
275 if (ret != 0) { 281 if (ret != 0) {
@@ -278,27 +284,13 @@ int regcache_sync(struct regmap *map)
278 goto out; 284 goto out;
279 } 285 }
280 } 286 }
287 map->cache_bypass = 0;
281 288
282 if (!map->cache_dirty) 289 ret = map->cache_ops->sync(map, 0, map->max_register);
283 goto out; 290
284 if (map->cache_ops->sync) { 291 if (ret == 0)
285 ret = map->cache_ops->sync(map); 292 map->cache_dirty = false;
286 } else {
287 for (i = 0; i < map->num_reg_defaults; i++) {
288 ret = regcache_read(map, i, &val);
289 if (ret < 0)
290 goto out;
291 map->cache_bypass = 1;
292 ret = _regmap_write(map, i, val);
293 map->cache_bypass = 0;
294 if (ret < 0)
295 goto out;
296 dev_dbg(map->dev, "Synced register %#x, value %#x\n",
297 map->reg_defaults[i].reg,
298 map->reg_defaults[i].def);
299 }
300 293
301 }
302out: 294out:
303 trace_regcache_sync(map->dev, name, "stop"); 295 trace_regcache_sync(map->dev, name, "stop");
304 /* Restore the bypass state */ 296 /* Restore the bypass state */
@@ -310,6 +302,51 @@ out:
310EXPORT_SYMBOL_GPL(regcache_sync); 302EXPORT_SYMBOL_GPL(regcache_sync);
311 303
312/** 304/**
305 * regcache_sync_region: Sync part of the register cache with the hardware.
306 *
307 * @map: map to sync.
308 * @min: first register to sync
309 * @max: last register to sync
310 *
311 * Write all non-default register values in the specified region to
312 * the hardware.
313 *
314 * Return a negative value on failure, 0 on success.
315 */
316int regcache_sync_region(struct regmap *map, unsigned int min,
317 unsigned int max)
318{
319 int ret = 0;
320 const char *name;
321 unsigned int bypass;
322
323 BUG_ON(!map->cache_ops || !map->cache_ops->sync);
324
325 mutex_lock(&map->lock);
326
327 /* Remember the initial bypass state */
328 bypass = map->cache_bypass;
329
330 name = map->cache_ops->name;
331 dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
332
333 trace_regcache_sync(map->dev, name, "start region");
334
335 if (!map->cache_dirty)
336 goto out;
337
338 ret = map->cache_ops->sync(map, min, max);
339
340out:
341 trace_regcache_sync(map->dev, name, "stop region");
342 /* Restore the bypass state */
343 map->cache_bypass = bypass;
344 mutex_unlock(&map->lock);
345
346 return ret;
347}
348
349/**
313 * regcache_cache_only: Put a register map into cache only mode 350 * regcache_cache_only: Put a register map into cache only mode
314 * 351 *
315 * @map: map to configure 352 * @map: map to configure
@@ -326,6 +363,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
326 mutex_lock(&map->lock); 363 mutex_lock(&map->lock);
327 WARN_ON(map->cache_bypass && enable); 364 WARN_ON(map->cache_bypass && enable);
328 map->cache_only = enable; 365 map->cache_only = enable;
366 trace_regmap_cache_only(map->dev, enable);
329 mutex_unlock(&map->lock); 367 mutex_unlock(&map->lock);
330} 368}
331EXPORT_SYMBOL_GPL(regcache_cache_only); 369EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -363,6 +401,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
363 mutex_lock(&map->lock); 401 mutex_lock(&map->lock);
364 WARN_ON(map->cache_only && enable); 402 WARN_ON(map->cache_only && enable);
365 map->cache_bypass = enable; 403 map->cache_bypass = enable;
404 trace_regmap_cache_bypass(map->dev, enable);
366 mutex_unlock(&map->lock); 405 mutex_unlock(&map->lock);
367} 406}
368EXPORT_SYMBOL_GPL(regcache_cache_bypass); 407EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -385,10 +424,16 @@ bool regcache_set_val(void *base, unsigned int idx,
385 cache[idx] = val; 424 cache[idx] = val;
386 break; 425 break;
387 } 426 }
427 case 4: {
428 u32 *cache = base;
429 if (cache[idx] == val)
430 return true;
431 cache[idx] = val;
432 break;
433 }
388 default: 434 default:
389 BUG(); 435 BUG();
390 } 436 }
391 /* unreachable */
392 return false; 437 return false;
393} 438}
394 439
@@ -407,6 +452,10 @@ unsigned int regcache_get_val(const void *base, unsigned int idx,
407 const u16 *cache = base; 452 const u16 *cache = base;
408 return cache[idx]; 453 return cache[idx];
409 } 454 }
455 case 4: {
456 const u32 *cache = base;
457 return cache[idx];
458 }
410 default: 459 default:
411 BUG(); 460 BUG();
412 } 461 }