regcache.c revision 6ff7373809a9b4eb644d83e2e299da297e1cbffa
19fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos/* 29fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * Register cache access API 39fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 49fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * Copyright 2011 Wolfson Microelectronics plc 59fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 69fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> 79fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 89fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * This program is free software; you can redistribute it and/or modify 99fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * it under the terms of the GNU General Public License version 2 as 109fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * published by the Free Software Foundation. 119fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos */ 129fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 139fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos#include <linux/slab.h> 141b6bc32f0a7380102499deb6aa99a59e789efb33Paul Gortmaker#include <linux/export.h> 159fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos#include <trace/events/regmap.h> 16f094fea68f0575286c55c06141cc89ffd0049024Mark Brown#include <linux/bsearch.h> 17c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos#include <linux/sort.h> 189fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 199fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos#include "internal.h" 209fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 219fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosstatic const struct regcache_ops *cache_types[] = { 2228644c809f44498b8cd91d00b4cdb09e63b99843Dimitris Papastamos ®cache_rbtree_ops, 232cbbb579bcbe3e11baf1c59920dcd5a780b80447Dimitris Papastamos ®cache_lzo_ops, 249fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos}; 259fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 269fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosstatic int regcache_hw_init(struct regmap *map) 279fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 289fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos int i, j; 299fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos int ret; 309fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos int count; 319fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos unsigned int val; 329fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos void *tmp_buf; 339fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 349fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!map->num_reg_defaults_raw) 359fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EINVAL; 369fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 379fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!map->reg_defaults_raw) { 389fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos dev_warn(map->dev, "No cache defaults, reading back from HW\n"); 399fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); 409fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!tmp_buf) 419fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EINVAL; 429fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos ret = regmap_bulk_read(map, 0, tmp_buf, 439fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->num_reg_defaults_raw); 449fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (ret < 0) { 459fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos kfree(tmp_buf); 469fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return ret; 479fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 489fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->reg_defaults_raw = tmp_buf; 499fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->cache_free = 1; 509fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 519fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 529fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos /* calculate the size of reg_defaults */ 539fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) { 549fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos val = regcache_get_val(map->reg_defaults_raw, 559fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos i, map->cache_word_size); 569fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!val) 579fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos continue; 589fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos count++; 599fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 609fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 619fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->reg_defaults = kmalloc(count * sizeof(struct reg_default), 629fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos GFP_KERNEL); 63021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen if (!map->reg_defaults) { 64021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen ret = -ENOMEM; 65021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen goto err_free; 66021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen } 679fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 689fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos /* fill the reg_defaults */ 699fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->num_reg_defaults = count; 709fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { 719fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos val = regcache_get_val(map->reg_defaults_raw, 729fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos i, map->cache_word_size); 739fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!val) 749fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos continue; 759fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->reg_defaults[j].reg = i; 769fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->reg_defaults[j].def = val; 779fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos j++; 789fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 799fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 809fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return 0; 81021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen 82021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausenerr_free: 83021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen if (map->cache_free) 84021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen kfree(map->reg_defaults_raw); 85021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen 86021cd616decb4e8a4b31f1f8c466a847e8c04e67Lars-Peter Clausen return ret; 879fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 889fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 89e5e3b8abeda1cf45f5a079458dbc267952694c7aLars-Peter Clausenint regcache_init(struct regmap *map, const struct regmap_config *config) 909fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 919fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos int ret; 929fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos int i; 939fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos void *tmp_buf; 949fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 95e7a6db30df42234bc0f7b9a0af402838e0f146b1Mark Brown if (map->cache_type == REGCACHE_NONE) { 96e7a6db30df42234bc0f7b9a0af402838e0f146b1Mark Brown map->cache_bypass = true; 979fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return 0; 98e7a6db30df42234bc0f7b9a0af402838e0f146b1Mark Brown } 999fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1009fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos for (i = 0; i < ARRAY_SIZE(cache_types); i++) 1019fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (cache_types[i]->type == map->cache_type) 1029fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos break; 1039fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1049fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (i == ARRAY_SIZE(cache_types)) { 1059fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos dev_err(map->dev, "Could not match compress type: %d\n", 1069fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->cache_type); 1079fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EINVAL; 1089fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 1099fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 110e5e3b8abeda1cf45f5a079458dbc267952694c7aLars-Peter Clausen map->num_reg_defaults = config->num_reg_defaults; 111e5e3b8abeda1cf45f5a079458dbc267952694c7aLars-Peter Clausen map->num_reg_defaults_raw = config->num_reg_defaults_raw; 112e5e3b8abeda1cf45f5a079458dbc267952694c7aLars-Peter Clausen map->reg_defaults_raw = config->reg_defaults_raw; 113064d4db11e23949c40b8a2f2f6be11c131b53932Lars-Peter Clausen map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); 114064d4db11e23949c40b8a2f2f6be11c131b53932Lars-Peter Clausen map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; 115e5e3b8abeda1cf45f5a079458dbc267952694c7aLars-Peter Clausen 1169fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->cache = NULL; 1179fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->cache_ops = cache_types[i]; 1189fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1199fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!map->cache_ops->read || 1209fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos !map->cache_ops->write || 1219fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos !map->cache_ops->name) 1229fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EINVAL; 1239fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1249fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos /* We still need to ensure that the reg_defaults 1259fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * won't vanish from under us. We'll need to make 1269fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * a copy of it. 1279fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos */ 128720e4616e8fd85284ef1addd8b8d93d8415e8dbcLars-Peter Clausen if (config->reg_defaults) { 1299fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!map->num_reg_defaults) 1309fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EINVAL; 131720e4616e8fd85284ef1addd8b8d93d8415e8dbcLars-Peter Clausen tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults * 1329fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos sizeof(struct reg_default), GFP_KERNEL); 1339fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!tmp_buf) 1349fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -ENOMEM; 1359fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->reg_defaults = tmp_buf; 1368528bdd450d34687b380c0f87992d105bdf54ca3Mark Brown } else if (map->num_reg_defaults_raw) { 1375fcd2560767cead8f0c741340e132c5417d9f73bMark Brown /* Some devices such as PMICs don't have cache defaults, 1389fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * we cope with this by reading back the HW registers and 1399fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * crafting the cache defaults by hand. 1409fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos */ 1419fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos ret = regcache_hw_init(map); 1429fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (ret < 0) 1439fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return ret; 1449fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 1459fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1469fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!map->max_register) 1479fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->max_register = map->num_reg_defaults_raw; 1489fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1499fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (map->cache_ops->init) { 1509fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos dev_dbg(map->dev, "Initializing %s cache\n", 1519fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->cache_ops->name); 152bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen ret = map->cache_ops->init(map); 153bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen if (ret) 154bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen goto err_free; 1559fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 1569fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return 0; 157bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen 158bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausenerr_free: 159bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen kfree(map->reg_defaults); 160bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen if (map->cache_free) 161bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen kfree(map->reg_defaults_raw); 162bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen 163bd061c78cabc28bb64ed79f784d24918b6bdb791Lars-Peter Clausen return ret; 1649fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 1659fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1669fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosvoid regcache_exit(struct regmap *map) 1679fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 1689fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (map->cache_type == REGCACHE_NONE) 1699fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return; 1709fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1719fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos BUG_ON(!map->cache_ops); 1729fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1739fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos kfree(map->reg_defaults); 1749fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (map->cache_free) 1759fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos kfree(map->reg_defaults_raw); 1769fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1779fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (map->cache_ops->exit) { 1789fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos dev_dbg(map->dev, "Destroying %s cache\n", 1799fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->cache_ops->name); 1809fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos map->cache_ops->exit(map); 1819fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 1829fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 1839fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 1849fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos/** 1859fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * regcache_read: Fetch the value of a given register from the cache. 1869fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 1879fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * @map: map to configure. 1889fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * @reg: The register index. 1899fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * @value: The value to be returned. 1909fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 1919fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * Return a negative value on failure, 0 on success. 1929fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos */ 1939fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosint regcache_read(struct regmap *map, 1949fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos unsigned int reg, unsigned int *value) 1959fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 196bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown int ret; 197bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown 1989fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (map->cache_type == REGCACHE_NONE) 1999fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -ENOSYS; 2009fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2019fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos BUG_ON(!map->cache_ops); 2029fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 203bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown if (!regmap_volatile(map, reg)) { 204bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown ret = map->cache_ops->read(map, reg, value); 205bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown 206bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown if (ret == 0) 207bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown trace_regmap_reg_read_cache(map->dev, reg, *value); 208bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown 209bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown return ret; 210bc7ee55633867909bb05e71f957a4d3c1aa1b488Mark Brown } 2119fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2129fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EINVAL; 2139fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 2149fabe24e9b1af84509b842731d2beaf85e66681eDimitris PapastamosEXPORT_SYMBOL_GPL(regcache_read); 2159fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2169fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos/** 2179fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * regcache_write: Set the value of a given register in the cache. 2189fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 2199fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * @map: map to configure. 2209fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * @reg: The register index. 2219fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * @value: The new register value. 2229fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 2239fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * Return a negative value on failure, 0 on success. 2249fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos */ 2259fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosint regcache_write(struct regmap *map, 2269fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos unsigned int reg, unsigned int value) 2279fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 2289fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (map->cache_type == REGCACHE_NONE) 2299fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return 0; 2309fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2319fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos BUG_ON(!map->cache_ops); 2329fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2339fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!regmap_writeable(map, reg)) 2349fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EIO; 2359fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2369fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!regmap_volatile(map, reg)) 2379fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return map->cache_ops->write(map, reg, value); 2389fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2399fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return 0; 2409fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 2419fabe24e9b1af84509b842731d2beaf85e66681eDimitris PapastamosEXPORT_SYMBOL_GPL(regcache_write); 2429fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 2439fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos/** 2449fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * regcache_sync: Sync the register cache with the hardware. 2459fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 2469fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * @map: map to configure. 2479fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 2489fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * Any registers that should not be synced should be marked as 2499fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * volatile. In general drivers can choose not to use the provided 2509fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * syncing functionality if they so require. 2519fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * 2529fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos * Return a negative value on failure, 0 on success. 2539fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos */ 2549fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosint regcache_sync(struct regmap *map) 2559fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 256954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos int ret = 0; 257954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos unsigned int i; 258593600890110c02eb471cf844649dee213870416Dimitris Papastamos const char *name; 259beb1a10f219ce720c13168203bd5ebe4ce7879e0Dimitris Papastamos unsigned int bypass; 260593600890110c02eb471cf844649dee213870416Dimitris Papastamos 261c3ec23288a92e20e0aff84a4cb6fbc7cc9bcf567Mark Brown BUG_ON(!map->cache_ops || !map->cache_ops->sync); 2629fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 26313753a9088af23c61e2f5c10a8f3ea136d8ebab5Dimitris Papastamos mutex_lock(&map->lock); 264beb1a10f219ce720c13168203bd5ebe4ce7879e0Dimitris Papastamos /* Remember the initial bypass state */ 265beb1a10f219ce720c13168203bd5ebe4ce7879e0Dimitris Papastamos bypass = map->cache_bypass; 266954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos dev_dbg(map->dev, "Syncing %s cache\n", 267954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos map->cache_ops->name); 268954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos name = map->cache_ops->name; 269954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos trace_regcache_sync(map->dev, name, "start"); 27022f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown 271d9db762708e27c2892db9d8a54e735a8e506e16eMark Brown if (!map->cache_dirty) 272d9db762708e27c2892db9d8a54e735a8e506e16eMark Brown goto out; 273d9db762708e27c2892db9d8a54e735a8e506e16eMark Brown 27422f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown /* Apply any patch first */ 2758a892d6996b60c822f19ad1844eb15b96ce393c7Mark Brown map->cache_bypass = 1; 27622f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown for (i = 0; i < map->patch_regs; i++) { 27722f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); 27822f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown if (ret != 0) { 27922f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown dev_err(map->dev, "Failed to write %x = %x: %d\n", 28022f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown map->patch[i].reg, map->patch[i].def, ret); 28122f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown goto out; 28222f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown } 28322f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown } 2848a892d6996b60c822f19ad1844eb15b96ce393c7Mark Brown map->cache_bypass = 0; 28522f0d90a34827812413bb3fbeda6a2a79bb58423Mark Brown 286c3ec23288a92e20e0aff84a4cb6fbc7cc9bcf567Mark Brown ret = map->cache_ops->sync(map); 287954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos 2886ff7373809a9b4eb644d83e2e299da297e1cbffaMark Brown if (ret == 0) 2896ff7373809a9b4eb644d83e2e299da297e1cbffaMark Brown map->cache_dirty = false; 2906ff7373809a9b4eb644d83e2e299da297e1cbffaMark Brown 291954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamosout: 292954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos trace_regcache_sync(map->dev, name, "stop"); 293beb1a10f219ce720c13168203bd5ebe4ce7879e0Dimitris Papastamos /* Restore the bypass state */ 294beb1a10f219ce720c13168203bd5ebe4ce7879e0Dimitris Papastamos map->cache_bypass = bypass; 29513753a9088af23c61e2f5c10a8f3ea136d8ebab5Dimitris Papastamos mutex_unlock(&map->lock); 296954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos 297954757d767a78bc4b863fa9ea703bd7f814c8a55Dimitris Papastamos return ret; 2989fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 2999fabe24e9b1af84509b842731d2beaf85e66681eDimitris PapastamosEXPORT_SYMBOL_GPL(regcache_sync); 3009fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 30192afb286d744511f51a05f8acb6c111d05737617Mark Brown/** 30292afb286d744511f51a05f8acb6c111d05737617Mark Brown * regcache_cache_only: Put a register map into cache only mode 30392afb286d744511f51a05f8acb6c111d05737617Mark Brown * 30492afb286d744511f51a05f8acb6c111d05737617Mark Brown * @map: map to configure 30592afb286d744511f51a05f8acb6c111d05737617Mark Brown * @cache_only: flag if changes should be written to the hardware 30692afb286d744511f51a05f8acb6c111d05737617Mark Brown * 30792afb286d744511f51a05f8acb6c111d05737617Mark Brown * When a register map is marked as cache only writes to the register 30892afb286d744511f51a05f8acb6c111d05737617Mark Brown * map API will only update the register cache, they will not cause 30992afb286d744511f51a05f8acb6c111d05737617Mark Brown * any hardware changes. This is useful for allowing portions of 31092afb286d744511f51a05f8acb6c111d05737617Mark Brown * drivers to act as though the device were functioning as normal when 31192afb286d744511f51a05f8acb6c111d05737617Mark Brown * it is disabled for power saving reasons. 31292afb286d744511f51a05f8acb6c111d05737617Mark Brown */ 31392afb286d744511f51a05f8acb6c111d05737617Mark Brownvoid regcache_cache_only(struct regmap *map, bool enable) 31492afb286d744511f51a05f8acb6c111d05737617Mark Brown{ 3152cd148f1599a425f0f3ac6753da96a1a1aa3ce76Mark Brown mutex_lock(&map->lock); 316ac77a765cb6e3b5aa41c186ad9f37db7fdad7dbeDimitris Papastamos WARN_ON(map->cache_bypass && enable); 31792afb286d744511f51a05f8acb6c111d05737617Mark Brown map->cache_only = enable; 3182cd148f1599a425f0f3ac6753da96a1a1aa3ce76Mark Brown mutex_unlock(&map->lock); 31992afb286d744511f51a05f8acb6c111d05737617Mark Brown} 32092afb286d744511f51a05f8acb6c111d05737617Mark BrownEXPORT_SYMBOL_GPL(regcache_cache_only); 32192afb286d744511f51a05f8acb6c111d05737617Mark Brown 3226eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos/** 3238ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown * regcache_mark_dirty: Mark the register cache as dirty 3248ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown * 3258ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown * @map: map to mark 3268ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown * 3278ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown * Mark the register cache as dirty, for example due to the device 3288ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown * having been powered down for suspend. If the cache is not marked 3298ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown * as dirty then the cache sync will be suppressed. 3308ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown */ 3318ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brownvoid regcache_mark_dirty(struct regmap *map) 3328ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown{ 3338ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown mutex_lock(&map->lock); 3348ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown map->cache_dirty = true; 3358ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown mutex_unlock(&map->lock); 3368ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown} 3378ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark BrownEXPORT_SYMBOL_GPL(regcache_mark_dirty); 3388ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown 3398ae0d7e8a918e9603748abe9b31984fc5d96abb3Mark Brown/** 3406eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * regcache_cache_bypass: Put a register map into cache bypass mode 3416eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * 3426eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * @map: map to configure 3430eef6b0415f58ed16aff95af8c92514ce5c01258Dimitris Papastamos * @cache_bypass: flag if changes should not be written to the hardware 3446eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * 3456eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * When a register map is marked with the cache bypass option, writes 3466eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * to the register map API will only update the hardware and not the 3476eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * the cache directly. This is useful when syncing the cache back to 3486eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos * the hardware. 3496eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos */ 3506eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamosvoid regcache_cache_bypass(struct regmap *map, bool enable) 3516eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos{ 3526eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos mutex_lock(&map->lock); 353ac77a765cb6e3b5aa41c186ad9f37db7fdad7dbeDimitris Papastamos WARN_ON(map->cache_only && enable); 3546eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos map->cache_bypass = enable; 3556eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos mutex_unlock(&map->lock); 3566eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos} 3576eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris PapastamosEXPORT_SYMBOL_GPL(regcache_cache_bypass); 3586eb0f5e0154facfe4f0acdb9f474cde773319efcDimitris Papastamos 3599fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosbool regcache_set_val(void *base, unsigned int idx, 3609fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos unsigned int val, unsigned int word_size) 3619fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 3629fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos switch (word_size) { 3639fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos case 1: { 3649fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos u8 *cache = base; 3659fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (cache[idx] == val) 3669fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return true; 3679fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos cache[idx] = val; 3689fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos break; 3699fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 3709fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos case 2: { 3719fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos u16 *cache = base; 3729fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (cache[idx] == val) 3739fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return true; 3749fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos cache[idx] = val; 3759fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos break; 3769fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 3779fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos default: 3789fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos BUG(); 3799fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 3809fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos /* unreachable */ 3819fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return false; 3829fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 3839fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 3849fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamosunsigned int regcache_get_val(const void *base, unsigned int idx, 3859fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos unsigned int word_size) 3869fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos{ 3879fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos if (!base) 3889fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -EINVAL; 3899fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 3909fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos switch (word_size) { 3919fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos case 1: { 3929fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos const u8 *cache = base; 3939fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return cache[idx]; 3949fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 3959fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos case 2: { 3969fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos const u16 *cache = base; 3979fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return cache[idx]; 3989fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 3999fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos default: 4009fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos BUG(); 4019fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos } 4029fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos /* unreachable */ 4039fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos return -1; 4049fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos} 4059fabe24e9b1af84509b842731d2beaf85e66681eDimitris Papastamos 406f094fea68f0575286c55c06141cc89ffd0049024Mark Brownstatic int regcache_default_cmp(const void *a, const void *b) 407c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos{ 408c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos const struct reg_default *_a = a; 409c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos const struct reg_default *_b = b; 410c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos 411c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos return _a->reg - _b->reg; 412c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos} 413c08604b8ae72b4fa1843a76fc7b403ddec49f8f4Dimitris Papastamos 414f094fea68f0575286c55c06141cc89ffd0049024Mark Brownint regcache_lookup_reg(struct regmap *map, unsigned int reg) 415f094fea68f0575286c55c06141cc89ffd0049024Mark Brown{ 416f094fea68f0575286c55c06141cc89ffd0049024Mark Brown struct reg_default key; 417f094fea68f0575286c55c06141cc89ffd0049024Mark Brown struct reg_default *r; 418f094fea68f0575286c55c06141cc89ffd0049024Mark Brown 419f094fea68f0575286c55c06141cc89ffd0049024Mark Brown key.reg = reg; 420f094fea68f0575286c55c06141cc89ffd0049024Mark Brown key.def = 0; 421f094fea68f0575286c55c06141cc89ffd0049024Mark Brown 422f094fea68f0575286c55c06141cc89ffd0049024Mark Brown r = bsearch(&key, map->reg_defaults, map->num_reg_defaults, 423f094fea68f0575286c55c06141cc89ffd0049024Mark Brown sizeof(struct reg_default), regcache_default_cmp); 424f094fea68f0575286c55c06141cc89ffd0049024Mark Brown 425f094fea68f0575286c55c06141cc89ffd0049024Mark Brown if (r) 426f094fea68f0575286c55c06141cc89ffd0049024Mark Brown return r - map->reg_defaults; 427f094fea68f0575286c55c06141cc89ffd0049024Mark Brown else 4286e6ace00a045251bd172b9b9c2379857bbff3dc7Mark Brown return -ENOENT; 429f094fea68f0575286c55c06141cc89ffd0049024Mark Brown} 430