diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 13:57:45 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 13:57:45 +0200 |
commit | 4e7e2a2008f5d8c49791c412849d5b0232d39bb3 (patch) | |
tree | 32c3fa2d5cefb388689cb795225022769bf7b413 /include | |
parent | 8a9ea3237e7eb5c25f09e429ad242ae5a3d5ea22 (diff) | |
parent | 7cccbdc84487616c3dbe493b04bfa1f362f4bc56 (diff) |
Merge branch 'for-linus' of git://opensource.wolfsonmicro.com/regmap
* 'for-linus' of git://opensource.wolfsonmicro.com/regmap: (62 commits)
mfd: Enable rbtree cache for wm831x devices
regmap: Support some block operations on cached devices
regmap: Allow caches for devices with no defaults
regmap: Ensure rbtree syncs registers set to zero properly
regmap: Allow rbtree to cache zero default values
regmap: Warn on raw I/O as well as bulk reads that bypass cache
regmap: Return a sensible error code if we fail to read the cache
regmap: Use bsearch() to search the register defaults
regmap: Fix doc comment
regmap: Optimize the lookup path to use binary search
regmap: Ensure we scream if we enable cache bypass/only at the same time
regmap: Implement regcache_cache_bypass helper function
regmap: Save/restore the bypass state upon syncing
regmap: Lock the sync path, ensure we use the lockless _regmap_write()
regmap: Fix apostrophe usage
regmap: Make _regmap_write() global
regmap: Fix lock used for regcache_cache_only()
regmap: Grab the lock in regcache_cache_only()
regmap: Modify map->cache_bypass directly
regmap: Fix regcache_sync generic implementation
...
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/mfd/wm831x/core.h | 12 | ||||
-rw-r--r-- | include/linux/mfd/wm831x/pdata.h | 3 | ||||
-rw-r--r-- | include/linux/mfd/wm8400-private.h | 7 | ||||
-rw-r--r-- | include/linux/mfd/wm8994/core.h | 9 | ||||
-rw-r--r-- | include/linux/regmap.h | 79 | ||||
-rw-r--r-- | include/trace/events/regmap.h | 136 |
6 files changed, 223 insertions, 23 deletions
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h index 8dda8ded5cda..ed8fe0d04097 100644 --- a/include/linux/mfd/wm831x/core.h +++ b/include/linux/mfd/wm831x/core.h @@ -18,6 +18,7 @@ #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/list.h> +#include <linux/regmap.h> /* * Register values. @@ -361,12 +362,8 @@ struct wm831x { struct mutex io_lock; struct device *dev; - int (*read_dev)(struct wm831x *wm831x, unsigned short reg, - int bytes, void *dest); - int (*write_dev)(struct wm831x *wm831x, unsigned short reg, - int bytes, void *src); - void *control_data; + struct regmap *regmap; int irq; /* Our chip IRQ */ struct mutex irq_lock; @@ -374,6 +371,8 @@ struct wm831x { int irq_masks_cur[WM831X_NUM_IRQ_REGS]; /* Currently active value */ int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */ + bool soft_shutdown; + /* Chip revision based flags */ unsigned has_gpio_ena:1; /* Has GPIO enable bit */ unsigned has_cs_sts:1; /* Has current sink status bit */ @@ -412,8 +411,11 @@ int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg, int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq); void wm831x_device_exit(struct wm831x *wm831x); int wm831x_device_suspend(struct wm831x *wm831x); +void wm831x_device_shutdown(struct wm831x *wm831x); int wm831x_irq_init(struct wm831x *wm831x, int irq); void wm831x_irq_exit(struct wm831x *wm831x); void wm831x_auxadc_init(struct wm831x *wm831x); +extern struct regmap_config wm831x_regmap_config; + #endif diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index 0ba24599fe51..1d7a3f7b3b5d 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -123,6 +123,9 @@ struct wm831x_pdata { /** Disable the touchscreen */ bool disable_touch; + /** The driver should initiate a power off sequence during shutdown */ + bool soft_shutdown; + int irq_base; int gpio_base; int gpio_defaults[WM831X_GPIO_NUM]; diff --git a/include/linux/mfd/wm8400-private.h b/include/linux/mfd/wm8400-private.h index 2aab4e93a5c9..0147b6968510 100644 --- a/include/linux/mfd/wm8400-private.h +++ b/include/linux/mfd/wm8400-private.h @@ -25,16 +25,15 @@ #include <linux/mutex.h> #include <linux/platform_device.h> +struct regmap; + #define WM8400_REGISTER_COUNT 0x55 struct wm8400 { struct device *dev; - int (*read_dev)(void *data, char reg, int count, u16 *dst); - int (*write_dev)(void *data, char reg, int count, const u16 *src); - struct mutex io_lock; - void *io_data; + struct regmap *regmap; u16 reg_cache[WM8400_REGISTER_COUNT]; diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h index f0b69cdae41c..45df450d869f 100644 --- a/include/linux/mfd/wm8994/core.h +++ b/include/linux/mfd/wm8994/core.h @@ -24,6 +24,7 @@ enum wm8994_type { struct regulator_dev; struct regulator_bulk_data; +struct regmap; #define WM8994_NUM_GPIO_REGS 11 #define WM8994_NUM_LDO_REGS 2 @@ -50,18 +51,12 @@ struct regulator_bulk_data; #define WM8994_IRQ_GPIO(x) (x + WM8994_IRQ_TEMP_WARN) struct wm8994 { - struct mutex io_lock; struct mutex irq_lock; enum wm8994_type type; struct device *dev; - int (*read_dev)(struct wm8994 *wm8994, unsigned short reg, - int bytes, void *dest); - int (*write_dev)(struct wm8994 *wm8994, unsigned short reg, - int bytes, const void *src); - - void *control_data; + struct regmap *regmap; int gpio_base; int irq_base; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 60a65cd7e1a0..3daac2d8dc37 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -20,9 +20,77 @@ struct i2c_client; struct spi_device; +/* An enum of all the supported cache types */ +enum regcache_type { + REGCACHE_NONE, + REGCACHE_INDEXED, + REGCACHE_RBTREE, + REGCACHE_LZO +}; + +/** + * 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. + * + * @writeable_reg: Optional callback returning true if the register + * can be written to. + * @readable_reg: Optional callback returning true if the register + * can be read from. + * @volatile_reg: Optional callback returning true if the register + * value can't be cached. + * @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. + * + * @read_flag_mask: Mask to be set in the top byte of the register when doing + * a read. + * @write_flag_mask: Mask to be set in the top byte of the register when doing + * a write. If both read_flag_mask and write_flag_mask are + * empty the regmap_bus default masks are used. + * + * @cache_type: The actual cache type. + * @reg_defaults_raw: Power on reset values for registers (for use with + * register cache support). + * @num_reg_defaults_raw: Number of elements in reg_defaults_raw. + */ struct regmap_config { int reg_bits; int val_bits; + + 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; + unsigned int num_reg_defaults; + enum regcache_type cache_type; + const void *reg_defaults_raw; + unsigned int num_reg_defaults_raw; + + u8 read_flag_mask; + u8 write_flag_mask; }; typedef int (*regmap_hw_write)(struct device *dev, const void *data, @@ -37,25 +105,18 @@ 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. * @read: Read operation. Data is returned in the buffer used to transmit * data. - * @owner: Module with the bus implementation, used to pin the implementation - * in memory. * @read_flag_mask: Mask to be set in the top byte of the register when doing * 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; - struct module *owner; u8 read_flag_mask; }; @@ -79,4 +140,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regcache_sync(struct regmap *map); +void regcache_cache_only(struct regmap *map, bool enable); +void regcache_cache_bypass(struct regmap *map, bool enable); + #endif diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h new file mode 100644 index 000000000000..1e3193b8fcc8 --- /dev/null +++ b/include/trace/events/regmap.h @@ -0,0 +1,136 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM regmap + +#if !defined(_TRACE_REGMAP_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_REGMAP_H + +#include <linux/device.h> +#include <linux/ktime.h> +#include <linux/tracepoint.h> + +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) +); + +TRACE_EVENT(regcache_sync, + + TP_PROTO(struct device *dev, const char *type, + const char *status), + + TP_ARGS(dev, type, status), + + TP_STRUCT__entry( + __string( name, dev_name(dev) ) + __string( status, status ) + __string( type, type ) + __field( int, type ) + ), + + TP_fast_assign( + __assign_str(name, dev_name(dev)); + __assign_str(status, status); + __assign_str(type, type); + ), + + TP_printk("%s type=%s status=%s", __get_str(name), + __get_str(type), __get_str(status)) +); + +#endif /* _TRACE_REGMAP_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> |