diff options
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r-- | drivers/base/regmap/regcache.c | 97 |
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 | } |
214 | EXPORT_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 | } |
241 | EXPORT_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); | |||
254 | int regcache_sync(struct regmap *map) | 257 | int 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 | } | ||
302 | out: | 294 | out: |
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: | |||
310 | EXPORT_SYMBOL_GPL(regcache_sync); | 302 | EXPORT_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 | */ | ||
316 | int 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 | |||
340 | out: | ||
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 | } |
331 | EXPORT_SYMBOL_GPL(regcache_cache_only); | 369 | EXPORT_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 | } |
368 | EXPORT_SYMBOL_GPL(regcache_cache_bypass); | 407 | EXPORT_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 | } |