mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
regmap: Updates for v3.19
A couple of new features this time around, nothing that should have any impact on most users: - Cleanups and optimization of the path for reading back the register defaults from the hardware at startup, reducing boot times for devices that use this (most don't, either populating on demand or providing defaults). - A bus implementation for AC'97 devices. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJUhZxqAAoJECTWi3JdVIfQ3k8H/3iWKIYsQost98g214KHlizl tF8a1vI0CG2O51O92Yof6uK3RGnF/Zp8nbCfHOvyvWDMSjQBZVCRfJWwBx0LgxqN 8LwZlMifXjWDDGYKeVt3IYqQMU9G2MrL8Fua5unZApdiIsGKwp8K/ZnIzxjDEO5x +LqGEM/5TFhMRcnQWO/aFRdM1PgnssHCbtghrSPxLdDAXJL2u9WOE9UpgqGBRikF DSv0mtKEdbn+yK3FZzPAs6krUkAX+ztjQHd7J3gGtkEbvgGZ9Xfs0TRU4KvnEgTi CsKpj8GBmO3sFdP8myj/JxFbaD7NdZ+WzeUCUYdE0fXtrLpbYW5ZJWkGP3cTyus= =2+cZ -----END PGP SIGNATURE----- Merge tag 'regmap-v3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap Pull regmap updates from Mark Brown: "A couple of new features this time around, nothing that should have any impact on most users: - Cleanups and optimization of the path for reading back the register defaults from the hardware at startup, reducing boot times for devices that use this (most don't, either populating on demand or providing defaults). - A bus implementation for AC'97 devices" * tag 'regmap-v3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap: ac97: Add generic AC'97 callbacks regmap: cache: Sort include headers alphabetically regmap: cache: Fix possible ZERO_SIZE_PTR pointer dereferencing error. regmap: cache: use kmalloc_array instead of kmalloc regmap: cache: speed regcache_hw_init() up. regmap: cache: fix errno in regcache_hw_init() regmap: cache: cleanup regcache_hw_init() regmap: cache: fix errno in regcache_hw_init()
This commit is contained in:
commit
de74038644
@ -3,12 +3,15 @@
|
||||
# subsystems should select the appropriate symbols.
|
||||
|
||||
config REGMAP
|
||||
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
|
||||
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
|
||||
select LZO_COMPRESS
|
||||
select LZO_DECOMPRESS
|
||||
select IRQ_DOMAIN if REGMAP_IRQ
|
||||
bool
|
||||
|
||||
config REGMAP_AC97
|
||||
tristate
|
||||
|
||||
config REGMAP_I2C
|
||||
tristate
|
||||
depends on I2C
|
||||
|
@ -1,6 +1,7 @@
|
||||
obj-$(CONFIG_REGMAP) += regmap.o regcache.o
|
||||
obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
|
||||
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
|
||||
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
|
||||
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
|
||||
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
|
||||
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
|
||||
|
@ -10,9 +10,9 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
@ -10,9 +10,9 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/lzo.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
@ -10,11 +10,11 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
@ -10,12 +10,12 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/device.h>
|
||||
#include <trace/events/regmap.h>
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
#include <trace/events/regmap.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@ -36,6 +36,23 @@ static int regcache_hw_init(struct regmap *map)
|
||||
if (!map->num_reg_defaults_raw)
|
||||
return -EINVAL;
|
||||
|
||||
/* calculate the size of reg_defaults */
|
||||
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++)
|
||||
if (!regmap_volatile(map, i * map->reg_stride))
|
||||
count++;
|
||||
|
||||
/* all registers are volatile, so just bypass */
|
||||
if (!count) {
|
||||
map->cache_bypass = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
map->num_reg_defaults = count;
|
||||
map->reg_defaults = kmalloc_array(count, sizeof(struct reg_default),
|
||||
GFP_KERNEL);
|
||||
if (!map->reg_defaults)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!map->reg_defaults_raw) {
|
||||
u32 cache_bypass = map->cache_bypass;
|
||||
dev_warn(map->dev, "No cache defaults, reading back from HW\n");
|
||||
@ -43,40 +60,25 @@ static int regcache_hw_init(struct regmap *map)
|
||||
/* Bypass the cache access till data read from HW*/
|
||||
map->cache_bypass = 1;
|
||||
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
|
||||
if (!tmp_buf)
|
||||
return -EINVAL;
|
||||
if (!tmp_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
ret = regmap_raw_read(map, 0, tmp_buf,
|
||||
map->num_reg_defaults_raw);
|
||||
map->cache_bypass = cache_bypass;
|
||||
if (ret < 0) {
|
||||
kfree(tmp_buf);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err_cache_free;
|
||||
|
||||
map->reg_defaults_raw = tmp_buf;
|
||||
map->cache_free = 1;
|
||||
}
|
||||
|
||||
/* calculate the size of reg_defaults */
|
||||
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
|
||||
val = regcache_get_val(map, map->reg_defaults_raw, i);
|
||||
if (regmap_volatile(map, i * map->reg_stride))
|
||||
continue;
|
||||
count++;
|
||||
}
|
||||
|
||||
map->reg_defaults = kmalloc(count * sizeof(struct reg_default),
|
||||
GFP_KERNEL);
|
||||
if (!map->reg_defaults) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* fill the reg_defaults */
|
||||
map->num_reg_defaults = count;
|
||||
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
|
||||
val = regcache_get_val(map, map->reg_defaults_raw, i);
|
||||
if (regmap_volatile(map, i * map->reg_stride))
|
||||
continue;
|
||||
val = regcache_get_val(map, map->reg_defaults_raw, i);
|
||||
map->reg_defaults[j].reg = i * map->reg_stride;
|
||||
map->reg_defaults[j].def = val;
|
||||
j++;
|
||||
@ -84,9 +86,10 @@ static int regcache_hw_init(struct regmap *map)
|
||||
|
||||
return 0;
|
||||
|
||||
err_cache_free:
|
||||
kfree(tmp_buf);
|
||||
err_free:
|
||||
if (map->cache_free)
|
||||
kfree(map->reg_defaults_raw);
|
||||
kfree(map->reg_defaults);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -150,6 +153,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
|
||||
ret = regcache_hw_init(map);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (map->cache_bypass)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!map->max_register)
|
||||
|
114
drivers/base/regmap/regmap-ac97.c
Normal file
114
drivers/base/regmap/regmap-ac97.c
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Register map access API - AC'97 support
|
||||
*
|
||||
* Copyright 2013 Linaro Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <sound/ac97_codec.h>
|
||||
|
||||
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case AC97_RESET:
|
||||
case AC97_POWERDOWN:
|
||||
case AC97_INT_PAGING:
|
||||
case AC97_EXTENDED_ID:
|
||||
case AC97_EXTENDED_STATUS:
|
||||
case AC97_EXTENDED_MID:
|
||||
case AC97_EXTENDED_MSTATUS:
|
||||
case AC97_GPIO_STATUS:
|
||||
case AC97_MISC_AFE:
|
||||
case AC97_VENDOR_ID1:
|
||||
case AC97_VENDOR_ID2:
|
||||
case AC97_CODEC_CLASS_REV:
|
||||
case AC97_PCI_SVID:
|
||||
case AC97_PCI_SID:
|
||||
case AC97_FUNC_SELECT:
|
||||
case AC97_FUNC_INFO:
|
||||
case AC97_SENSE_INFO:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile);
|
||||
|
||||
static int regmap_ac97_reg_read(void *context, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
struct snd_ac97 *ac97 = context;
|
||||
|
||||
*val = ac97->bus->ops->read(ac97, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regmap_ac97_reg_write(void *context, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
struct snd_ac97 *ac97 = context;
|
||||
|
||||
ac97->bus->ops->write(ac97, reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_bus ac97_regmap_bus = {
|
||||
.reg_write = regmap_ac97_reg_write,
|
||||
.reg_read = regmap_ac97_reg_read,
|
||||
};
|
||||
|
||||
/**
|
||||
* regmap_init_ac97(): Initialise AC'97 register map
|
||||
*
|
||||
* @ac97: Device that will be interacted with
|
||||
* @config: Configuration for register map
|
||||
*
|
||||
* The return value will be an ERR_PTR() on error or a valid pointer to
|
||||
* a struct regmap.
|
||||
*/
|
||||
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_init_ac97);
|
||||
|
||||
/**
|
||||
* devm_regmap_init_ac97(): Initialise AC'97 register map
|
||||
*
|
||||
* @ac97: Device that will be interacted with
|
||||
* @config: Configuration for register map
|
||||
*
|
||||
* The return value will be an ERR_PTR() on error or a valid pointer
|
||||
* to a struct regmap. The regmap will be automatically freed by the
|
||||
* device management code.
|
||||
*/
|
||||
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_regmap_init_ac97);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
@ -27,6 +27,7 @@ struct spmi_device;
|
||||
struct regmap;
|
||||
struct regmap_range_cfg;
|
||||
struct regmap_field;
|
||||
struct snd_ac97;
|
||||
|
||||
/* An enum of all the supported cache types */
|
||||
enum regcache_type {
|
||||
@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev,
|
||||
struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
|
||||
void __iomem *regs,
|
||||
const struct regmap_config *config);
|
||||
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config);
|
||||
|
||||
struct regmap *devm_regmap_init(struct device *dev,
|
||||
const struct regmap_bus *bus,
|
||||
@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev,
|
||||
struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
|
||||
void __iomem *regs,
|
||||
const struct regmap_config *config);
|
||||
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config);
|
||||
|
||||
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
|
||||
|
||||
/**
|
||||
* regmap_init_mmio(): Initialise register map
|
||||
|
Loading…
Reference in New Issue
Block a user