Commit de740386 authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 177808cd a63b8783
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
# subsystems should select the appropriate symbols. # subsystems should select the appropriate symbols.
config REGMAP 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_COMPRESS
select LZO_DECOMPRESS select LZO_DECOMPRESS
select IRQ_DOMAIN if REGMAP_IRQ select IRQ_DOMAIN if REGMAP_IRQ
bool bool
config REGMAP_AC97
tristate
config REGMAP_I2C config REGMAP_I2C
tristate tristate
depends on I2C depends on I2C
......
obj-$(CONFIG_REGMAP) += regmap.o regcache.o obj-$(CONFIG_REGMAP) += regmap.o regcache.o
obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.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_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/slab.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h>
#include "internal.h" #include "internal.h"
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/slab.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/lzo.h> #include <linux/lzo.h>
#include <linux/slab.h>
#include "internal.h" #include "internal.h"
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h>
#include "internal.h" #include "internal.h"
......
...@@ -10,12 +10,12 @@ ...@@ -10,12 +10,12 @@
* published by the Free Software Foundation. * 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/bsearch.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <trace/events/regmap.h>
#include "internal.h" #include "internal.h"
...@@ -36,6 +36,23 @@ static int regcache_hw_init(struct regmap *map) ...@@ -36,6 +36,23 @@ static int regcache_hw_init(struct regmap *map)
if (!map->num_reg_defaults_raw) if (!map->num_reg_defaults_raw)
return -EINVAL; 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) { if (!map->reg_defaults_raw) {
u32 cache_bypass = map->cache_bypass; u32 cache_bypass = map->cache_bypass;
dev_warn(map->dev, "No cache defaults, reading back from HW\n"); dev_warn(map->dev, "No cache defaults, reading back from HW\n");
...@@ -43,40 +60,25 @@ static int regcache_hw_init(struct regmap *map) ...@@ -43,40 +60,25 @@ static int regcache_hw_init(struct regmap *map)
/* Bypass the cache access till data read from HW*/ /* Bypass the cache access till data read from HW*/
map->cache_bypass = 1; map->cache_bypass = 1;
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
if (!tmp_buf) if (!tmp_buf) {
return -EINVAL; ret = -ENOMEM;
goto err_free;
}
ret = regmap_raw_read(map, 0, tmp_buf, ret = regmap_raw_read(map, 0, tmp_buf,
map->num_reg_defaults_raw); map->num_reg_defaults_raw);
map->cache_bypass = cache_bypass; map->cache_bypass = cache_bypass;
if (ret < 0) { if (ret < 0)
kfree(tmp_buf); goto err_cache_free;
return ret;
}
map->reg_defaults_raw = tmp_buf; map->reg_defaults_raw = tmp_buf;
map->cache_free = 1; 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 */ /* fill the reg_defaults */
map->num_reg_defaults = count;
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { 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)) if (regmap_volatile(map, i * map->reg_stride))
continue; continue;
val = regcache_get_val(map, map->reg_defaults_raw, i);
map->reg_defaults[j].reg = i * map->reg_stride; map->reg_defaults[j].reg = i * map->reg_stride;
map->reg_defaults[j].def = val; map->reg_defaults[j].def = val;
j++; j++;
...@@ -84,9 +86,10 @@ static int regcache_hw_init(struct regmap *map) ...@@ -84,9 +86,10 @@ static int regcache_hw_init(struct regmap *map)
return 0; return 0;
err_cache_free:
kfree(tmp_buf);
err_free: err_free:
if (map->cache_free) kfree(map->reg_defaults);
kfree(map->reg_defaults_raw);
return ret; return ret;
} }
...@@ -150,6 +153,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) ...@@ -150,6 +153,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
ret = regcache_hw_init(map); ret = regcache_hw_init(map);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (map->cache_bypass)
return 0;
} }
if (!map->max_register) if (!map->max_register)
......
/*
* 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; ...@@ -27,6 +27,7 @@ struct spmi_device;
struct regmap; struct regmap;
struct regmap_range_cfg; struct regmap_range_cfg;
struct regmap_field; struct regmap_field;
struct snd_ac97;
/* An enum of all the supported cache types */ /* An enum of all the supported cache types */
enum regcache_type { enum regcache_type {
...@@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev, ...@@ -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, struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs, void __iomem *regs,
const struct regmap_config *config); 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, struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
...@@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev, ...@@ -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, struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs, void __iomem *regs,
const struct regmap_config *config); 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 * regmap_init_mmio(): Initialise register map
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment