diff --git a/[refs] b/[refs] index 19bcec48afc5..a2795b59ab70 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 449e38427fe57a6120fecd1051981c89ee862b3d +refs/heads/master: bd20eb541ebbb17a5e047cd20e74b9ccf19a4123 diff --git a/trunk/drivers/base/regmap/Makefile b/trunk/drivers/base/regmap/Makefile index 057c13f66a67..f476f4571295 100644 --- a/trunk/drivers/base/regmap/Makefile +++ b/trunk/drivers/base/regmap/Makefile @@ -1,4 +1,3 @@ obj-$(CONFIG_REGMAP) += regmap.o -obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o diff --git a/trunk/drivers/base/regmap/internal.h b/trunk/drivers/base/regmap/internal.h deleted file mode 100644 index 5ab3fefa4b05..000000000000 --- a/trunk/drivers/base/regmap/internal.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Register map access API internal header - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _REGMAP_INTERNAL_H -#define _REGMAP_INTERNAL_H - -#include -#include - -struct regmap; - -struct regmap_format { - size_t buf_size; - size_t reg_bytes; - size_t val_bytes; - void (*format_write)(struct regmap *map, - unsigned int reg, unsigned int val); - void (*format_reg)(void *buf, unsigned int reg); - void (*format_val)(void *buf, unsigned int val); - unsigned int (*parse_val)(void *buf); -}; - -struct regmap { - struct mutex lock; - - struct device *dev; /* Device we do I/O on */ - void *work_buf; /* Scratch buffer used to format I/O */ - struct regmap_format format; /* Buffer format */ - const struct regmap_bus *bus; - -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs; -#endif - - unsigned int max_register; - bool (*writeable_reg)(struct device *dev, unsigned int reg); - bool (*readable_reg)(struct device *dev, unsigned int reg); - bool (*volatile_reg)(struct device *dev, unsigned int reg); - bool (*precious_reg)(struct device *dev, unsigned int reg); -}; - -bool regmap_writeable(struct regmap *map, unsigned int reg); -bool regmap_readable(struct regmap *map, unsigned int reg); -bool regmap_volatile(struct regmap *map, unsigned int reg); -bool regmap_precious(struct regmap *map, unsigned int reg); - -#ifdef CONFIG_DEBUG_FS -extern void regmap_debugfs_initcall(void); -extern void regmap_debugfs_init(struct regmap *map); -extern void regmap_debugfs_exit(struct regmap *map); -#else -void regmap_debugfs_initcall(void) { } -void regmap_debugfs_init(struct regmap *map) { } -void regmap_debugfs_exit(struct regmap *map) { } -#endif - -#endif diff --git a/trunk/drivers/base/regmap/regmap-debugfs.c b/trunk/drivers/base/regmap/regmap-debugfs.c deleted file mode 100644 index 7a8d67537d3f..000000000000 --- a/trunk/drivers/base/regmap/regmap-debugfs.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Register map access API - debugfs - * - * Copyright 2011 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include "internal.h" - -static struct dentry *regmap_debugfs_root; - -/* Calculate the length of a fixed format */ -static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) -{ - snprintf(buf, buf_size, "%x", max_val); - return strlen(buf); -} - -static int regmap_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - int reg_len, val_len, tot_len; - size_t buf_pos = 0; - loff_t p = 0; - ssize_t ret; - int i; - struct regmap *map = file->private_data; - char *buf; - unsigned int val; - - if (*ppos < 0 || !count) - return -EINVAL; - - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Calculate the length of a fixed format */ - reg_len = regmap_calc_reg_len(map->max_register, buf, count); - val_len = 2 * map->format.val_bytes; - tot_len = reg_len + val_len + 3; /* : \n */ - - for (i = 0; i < map->max_register; i++) { - if (!regmap_readable(map, i)) - continue; - - if (regmap_precious(map, i)) - continue; - - /* If we're in the region the user is trying to read */ - if (p >= *ppos) { - /* ...but not beyond it */ - if (buf_pos >= count - 1 - tot_len) - break; - - /* Format the register */ - snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", - reg_len, i); - buf_pos += reg_len + 2; - - /* Format the value, write all X if we can't read */ - ret = regmap_read(map, i, &val); - if (ret == 0) - snprintf(buf + buf_pos, count - buf_pos, - "%.*x", val_len, val); - else - memset(buf + buf_pos, 'X', val_len); - buf_pos += 2 * map->format.val_bytes; - - buf[buf_pos++] = '\n'; - } - p += tot_len; - } - - ret = buf_pos; - - if (copy_to_user(user_buf, buf, buf_pos)) { - ret = -EFAULT; - goto out; - } - - *ppos += buf_pos; - -out: - kfree(buf); - return ret; -} - -static const struct file_operations regmap_map_fops = { - .open = regmap_open_file, - .read = regmap_map_read_file, - .llseek = default_llseek, -}; - -static ssize_t regmap_access_read_file(struct file *file, - char __user *user_buf, size_t count, - loff_t *ppos) -{ - int reg_len, tot_len; - size_t buf_pos = 0; - loff_t p = 0; - ssize_t ret; - int i; - struct regmap *map = file->private_data; - char *buf; - - if (*ppos < 0 || !count) - return -EINVAL; - - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Calculate the length of a fixed format */ - reg_len = regmap_calc_reg_len(map->max_register, buf, count); - tot_len = reg_len + 10; /* ': R W V P\n' */ - - for (i = 0; i < map->max_register; i++) { - /* Ignore registers which are neither readable nor writable */ - if (!regmap_readable(map, i) && !regmap_writeable(map, i)) - continue; - - /* If we're in the region the user is trying to read */ - if (p >= *ppos) { - /* ...but not beyond it */ - if (buf_pos >= count - 1 - tot_len) - break; - - /* Format the register */ - snprintf(buf + buf_pos, count - buf_pos, - "%.*x: %c %c %c %c\n", - reg_len, i, - regmap_readable(map, i) ? 'y' : 'n', - regmap_writeable(map, i) ? 'y' : 'n', - regmap_volatile(map, i) ? 'y' : 'n', - regmap_precious(map, i) ? 'y' : 'n'); - - buf_pos += tot_len; - } - p += tot_len; - } - - ret = buf_pos; - - if (copy_to_user(user_buf, buf, buf_pos)) { - ret = -EFAULT; - goto out; - } - - *ppos += buf_pos; - -out: - kfree(buf); - return ret; -} - -static const struct file_operations regmap_access_fops = { - .open = regmap_open_file, - .read = regmap_access_read_file, - .llseek = default_llseek, -}; - -void regmap_debugfs_init(struct regmap *map) -{ - map->debugfs = debugfs_create_dir(dev_name(map->dev), - regmap_debugfs_root); - if (!map->debugfs) { - dev_warn(map->dev, "Failed to create debugfs directory\n"); - return; - } - - if (map->max_register) { - debugfs_create_file("registers", 0400, map->debugfs, - map, ®map_map_fops); - debugfs_create_file("access", 0400, map->debugfs, - map, ®map_access_fops); - } -} - -void regmap_debugfs_exit(struct regmap *map) -{ - debugfs_remove_recursive(map->debugfs); -} - -void regmap_debugfs_initcall(void) -{ - regmap_debugfs_root = debugfs_create_dir("regmap", NULL); - if (!regmap_debugfs_root) { - pr_warn("regmap: Failed to create debugfs root\n"); - return; - } -} diff --git a/trunk/drivers/base/regmap/regmap-i2c.c b/trunk/drivers/base/regmap/regmap-i2c.c index e7d916d1b3ea..c2231ff06cbc 100644 --- a/trunk/drivers/base/regmap/regmap-i2c.c +++ b/trunk/drivers/base/regmap/regmap-i2c.c @@ -90,6 +90,7 @@ static int regmap_i2c_read(struct device *dev, } static struct regmap_bus regmap_i2c = { + .type = &i2c_bus_type, .write = regmap_i2c_write, .gather_write = regmap_i2c_gather_write, .read = regmap_i2c_read, @@ -112,4 +113,3 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c, } EXPORT_SYMBOL_GPL(regmap_init_i2c); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/base/regmap/regmap-spi.c b/trunk/drivers/base/regmap/regmap-spi.c index cc0f1164cf99..4deba0621bc7 100644 --- a/trunk/drivers/base/regmap/regmap-spi.c +++ b/trunk/drivers/base/regmap/regmap-spi.c @@ -47,6 +47,7 @@ static int regmap_spi_read(struct device *dev, } static struct regmap_bus regmap_spi = { + .type = &spi_bus_type, .write = regmap_spi_write, .gather_write = regmap_spi_gather_write, .read = regmap_spi_read, @@ -69,5 +70,3 @@ struct regmap *regmap_init_spi(struct spi_device *spi, return regmap_init(&spi->dev, ®map_spi, config); } EXPORT_SYMBOL_GPL(regmap_init_spi); - -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/base/regmap/regmap.c b/trunk/drivers/base/regmap/regmap.c index fa2bd896eb20..2fa55c56897a 100644 --- a/trunk/drivers/base/regmap/regmap.c +++ b/trunk/drivers/base/regmap/regmap.c @@ -15,54 +15,34 @@ #include #include -#define CREATE_TRACE_POINTS -#include - -#include "internal.h" - -bool regmap_writeable(struct regmap *map, unsigned int reg) -{ - if (map->max_register && reg > map->max_register) - return false; - - if (map->writeable_reg) - return map->writeable_reg(map->dev, reg); - - return true; -} - -bool regmap_readable(struct regmap *map, unsigned int reg) -{ - if (map->max_register && reg > map->max_register) - return false; - - if (map->readable_reg) - return map->readable_reg(map->dev, reg); - - return true; -} - -bool regmap_volatile(struct regmap *map, unsigned int reg) -{ - if (map->max_register && reg > map->max_register) - return false; - - if (map->volatile_reg) - return map->volatile_reg(map->dev, reg); - - return true; -} - -bool regmap_precious(struct regmap *map, unsigned int reg) -{ - if (map->max_register && reg > map->max_register) - return false; - - if (map->precious_reg) - return map->precious_reg(map->dev, reg); - - return false; -} +#include + +struct regmap; + +struct regmap_format { + size_t buf_size; + size_t reg_bytes; + size_t val_bytes; + void (*format_write)(struct regmap *map, + unsigned int reg, unsigned int val); + void (*format_reg)(void *buf, unsigned int reg); + void (*format_val)(void *buf, unsigned int val); + unsigned int (*parse_val)(void *buf); +}; + +struct regmap { + struct mutex lock; + + struct device *dev; /* Device we do I/O on */ + void *work_buf; /* Scratch buffer used to format I/O */ + struct regmap_format format; /* Buffer format */ + const struct regmap_bus *bus; + + unsigned int max_register; + bool (*writeable_reg)(struct device *dev, unsigned int reg); + bool (*readable_reg)(struct device *dev, unsigned int reg); + bool (*volatile_reg)(struct device *dev, unsigned int reg); +}; static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val) @@ -145,7 +125,6 @@ struct regmap *regmap_init(struct device *dev, map->writeable_reg = config->writeable_reg; map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; - map->precious_reg = config->precious_reg; switch (config->reg_bits) { case 4: @@ -201,8 +180,6 @@ struct regmap *regmap_init(struct device *dev, goto err_bus; } - regmap_debugfs_init(map); - return map; err_bus: @@ -219,7 +196,6 @@ EXPORT_SYMBOL_GPL(regmap_init); */ void regmap_exit(struct regmap *map) { - regmap_debugfs_exit(map); kfree(map->work_buf); module_put(map->bus->owner); kfree(map); @@ -232,32 +208,16 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, void *buf; int ret = -ENOTSUPP; size_t len; - int i; - - /* Check for unwritable registers before we start */ - if (map->writeable_reg) - for (i = 0; i < val_len / map->format.val_bytes; i++) - if (!map->writeable_reg(map->dev, reg + i)) - return -EINVAL; map->format.format_reg(map->work_buf, reg); - trace_regmap_hw_write_start(map->dev, reg, - val_len / map->format.val_bytes); - - /* If we're doing a single register write we can probably just - * send the work_buf directly, otherwise try to do a gather - * write. - */ - if (val == map->work_buf + map->format.reg_bytes) - ret = map->bus->write(map->dev, map->work_buf, - map->format.reg_bytes + val_len); - else if (map->bus->gather_write) + /* Try to do a gather write if we can */ + if (map->bus->gather_write) ret = map->bus->gather_write(map->dev, map->work_buf, map->format.reg_bytes, val, val_len); - /* If that didn't work fall back on linearising by hand. */ + /* Otherwise fall back on linearising by hand. */ if (ret == -ENOTSUPP) { len = map->format.reg_bytes + val_len; buf = kmalloc(len, GFP_KERNEL); @@ -271,31 +231,19 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, kfree(buf); } - trace_regmap_hw_write_done(map->dev, reg, - val_len / map->format.val_bytes); - return ret; } static int _regmap_write(struct regmap *map, unsigned int reg, unsigned int val) { - int ret; BUG_ON(!map->format.format_write && !map->format.format_val); - trace_regmap_reg_write(map->dev, reg, val); - if (map->format.format_write) { map->format.format_write(map, reg, val); - trace_regmap_hw_write_start(map->dev, reg, 1); - - ret = map->bus->write(map->dev, map->work_buf, - map->format.buf_size); - - trace_regmap_hw_write_done(map->dev, reg, 1); - - return ret; + return map->bus->write(map->dev, map->work_buf, + map->format.buf_size); } else { map->format.format_val(map->work_buf + map->format.reg_bytes, val); @@ -377,16 +325,12 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, if (map->bus->read_flag_mask) u8[0] |= map->bus->read_flag_mask; - trace_regmap_hw_read_start(map->dev, reg, - val_len / map->format.val_bytes); - ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes, - val, val_len); - - trace_regmap_hw_read_done(map->dev, reg, - val_len / map->format.val_bytes); + val, map->format.val_bytes); + if (ret != 0) + return ret; - return ret; + return 0; } static int _regmap_read(struct regmap *map, unsigned int reg, @@ -398,10 +342,8 @@ static int _regmap_read(struct regmap *map, unsigned int reg, return -EINVAL; ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); - if (ret == 0) { + if (ret == 0) *val = map->format.parse_val(map->work_buf); - trace_regmap_reg_read(map->dev, reg, *val); - } return ret; } @@ -520,11 +462,3 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, return ret; } EXPORT_SYMBOL_GPL(regmap_update_bits); - -static int __init regmap_initcall(void) -{ - regmap_debugfs_initcall(); - - return 0; -} -postcore_initcall(regmap_initcall); diff --git a/trunk/include/linux/regmap.h b/trunk/include/linux/regmap.h index 20a8fbf19d44..e2200f21c602 100644 --- a/trunk/include/linux/regmap.h +++ b/trunk/include/linux/regmap.h @@ -20,13 +20,25 @@ struct i2c_client; struct spi_device; +/** + * Default value for a register. We use an array of structs rather + * than a simple array as many modern devices have very sparse + * register maps. + * + * @reg: Register address. + * @def: Register default value. + */ +struct reg_default { + unsigned int reg; + unsigned int def; +}; + /** * Configuration for the register map of a device. * * @reg_bits: Number of bits in a register address, mandatory. * @val_bits: Number of bits in a register value, mandatory. * - * @max_register: Optional, specifies the maximum valid register index. * @writeable_reg: Optional callback returning true if the register * can be written to. * @readable_reg: Optional callback returning true if the register @@ -36,16 +48,24 @@ struct spi_device; * @precious_reg: Optional callback returning true if the rgister * should not be read outside of a call from the driver * (eg, a clear on read interrupt status register). + * + * @max_register: Optional, specifies the maximum valid register index. + * @reg_defaults: Power on reset values for registers (for use with + * register cache support). + * @num_reg_defaults: Number of elements in reg_defaults. */ struct regmap_config { int reg_bits; int val_bits; - unsigned int max_register; bool (*writeable_reg)(struct device *dev, unsigned int reg); bool (*readable_reg)(struct device *dev, unsigned int reg); bool (*volatile_reg)(struct device *dev, unsigned int reg); bool (*precious_reg)(struct device *dev, unsigned int reg); + + unsigned int max_register; + struct reg_default *reg_defaults; + int num_reg_defaults; }; typedef int (*regmap_hw_write)(struct device *dev, const void *data, @@ -60,6 +80,8 @@ typedef int (*regmap_hw_read)(struct device *dev, /** * Description of a hardware bus for the register map infrastructure. * + * @list: Internal use. + * @type: Bus type, used to identify bus to be used for a device. * @write: Write operation. * @gather_write: Write operation with split register/value, return -ENOTSUPP * if not implemented on a given device. @@ -71,6 +93,8 @@ typedef int (*regmap_hw_read)(struct device *dev, * a read. */ struct regmap_bus { + struct list_head list; + struct bus_type *type; regmap_hw_write write; regmap_hw_gather_write gather_write; regmap_hw_read read; diff --git a/trunk/include/trace/events/regmap.h b/trunk/include/trace/events/regmap.h deleted file mode 100644 index e35e37c378c6..000000000000 --- a/trunk/include/trace/events/regmap.h +++ /dev/null @@ -1,112 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM regmap - -#if !defined(_TRACE_REGMAP_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_REGMAP_H - -#include -#include -#include - -struct regmap; - -/* - * Log register events - */ -DECLARE_EVENT_CLASS(regmap_reg, - - TP_PROTO(struct device *dev, unsigned int reg, - unsigned int val), - - TP_ARGS(dev, reg, val), - - TP_STRUCT__entry( - __string( name, dev_name(dev) ) - __field( unsigned int, reg ) - __field( unsigned int, val ) - ), - - TP_fast_assign( - __assign_str(name, dev_name(dev)); - __entry->reg = reg; - __entry->val = val; - ), - - TP_printk("%s reg=%x val=%x", __get_str(name), - (unsigned int)__entry->reg, - (unsigned int)__entry->val) -); - -DEFINE_EVENT(regmap_reg, regmap_reg_write, - - TP_PROTO(struct device *dev, unsigned int reg, - unsigned int val), - - TP_ARGS(dev, reg, val) - -); - -DEFINE_EVENT(regmap_reg, regmap_reg_read, - - TP_PROTO(struct device *dev, unsigned int reg, - unsigned int val), - - TP_ARGS(dev, reg, val) - -); - -DECLARE_EVENT_CLASS(regmap_block, - - TP_PROTO(struct device *dev, unsigned int reg, int count), - - TP_ARGS(dev, reg, count), - - TP_STRUCT__entry( - __string( name, dev_name(dev) ) - __field( unsigned int, reg ) - __field( int, count ) - ), - - TP_fast_assign( - __assign_str(name, dev_name(dev)); - __entry->reg = reg; - __entry->count = count; - ), - - TP_printk("%s reg=%x count=%d", __get_str(name), - (unsigned int)__entry->reg, - (int)__entry->count) -); - -DEFINE_EVENT(regmap_block, regmap_hw_read_start, - - TP_PROTO(struct device *dev, unsigned int reg, int count), - - TP_ARGS(dev, reg, count) -); - -DEFINE_EVENT(regmap_block, regmap_hw_read_done, - - TP_PROTO(struct device *dev, unsigned int reg, int count), - - TP_ARGS(dev, reg, count) -); - -DEFINE_EVENT(regmap_block, regmap_hw_write_start, - - TP_PROTO(struct device *dev, unsigned int reg, int count), - - TP_ARGS(dev, reg, count) -); - -DEFINE_EVENT(regmap_block, regmap_hw_write_done, - - TP_PROTO(struct device *dev, unsigned int reg, int count), - - TP_ARGS(dev, reg, count) -); - -#endif /* _TRACE_REGMAP_H */ - -/* This part must be outside protection */ -#include