diff options
-rw-r--r-- | drivers/base/regmap/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/regmap/internal.h | 69 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 209 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-i2c.c | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-spi.c | 4 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 162 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 3 | ||||
-rw-r--r-- | drivers/mfd/wm831x-core.c | 424 | ||||
-rw-r--r-- | drivers/mfd/wm831x-i2c.c | 68 | ||||
-rw-r--r-- | drivers/mfd/wm831x-spi.c | 196 | ||||
-rw-r--r-- | drivers/mfd/wm8400-core.c | 106 | ||||
-rw-r--r-- | drivers/mfd/wm8994-core.c | 178 | ||||
-rw-r--r-- | include/linux/mfd/wm831x/core.h | 9 | ||||
-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 | 7 | ||||
-rw-r--r-- | include/trace/events/regmap.h | 112 |
17 files changed, 998 insertions, 569 deletions
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index f476f457129..057c13f66a6 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -1,3 +1,4 @@ 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/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h new file mode 100644 index 00000000000..a98493cde5c --- /dev/null +++ b/drivers/base/regmap/internal.h @@ -0,0 +1,69 @@ +/* + * Register map access API internal header + * + * Copyright 2011 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * 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 <linux/regmap.h> +#include <linux/fs.h> + +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); + + u8 read_flag_mask; + u8 write_flag_mask; +}; + +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 +static inline void regmap_debugfs_initcall(void) { } +static inline void regmap_debugfs_init(struct regmap *map) { } +static inline void regmap_debugfs_exit(struct regmap *map) { } +#endif + +#endif diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c new file mode 100644 index 00000000000..6f397476e27 --- /dev/null +++ b/drivers/base/regmap/regmap-debugfs.c @@ -0,0 +1,209 @@ +/* + * Register map access API - debugfs + * + * Copyright 2011 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * 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 <linux/slab.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> + +#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 + 1; 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 + 1; 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/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index c2231ff06cb..38621ec87c0 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -90,11 +90,9 @@ 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, - .owner = THIS_MODULE, }; /** @@ -113,3 +111,4 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c, } EXPORT_SYMBOL_GPL(regmap_init_i2c); +MODULE_LICENSE("GPL"); diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 4deba0621bc..14132b82906 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -47,11 +47,9 @@ 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, - .owner = THIS_MODULE, .read_flag_mask = 0x80, }; @@ -70,3 +68,5 @@ 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/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 2fa55c56897..e7adfe70e42 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -15,34 +15,54 @@ #include <linux/mutex.h> #include <linux/err.h> -#include <linux/regmap.h> - -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); -}; +#define CREATE_TRACE_POINTS +#include <trace/events/regmap.h> + +#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; +} static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val) @@ -125,6 +145,14 @@ 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; + + if (config->read_flag_mask || config->write_flag_mask) { + map->read_flag_mask = config->read_flag_mask; + map->write_flag_mask = config->write_flag_mask; + } else { + map->read_flag_mask = bus->read_flag_mask; + } switch (config->reg_bits) { case 4: @@ -177,13 +205,13 @@ struct regmap *regmap_init(struct device *dev, map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; - goto err_bus; + goto err_map; } + regmap_debugfs_init(map); + return map; -err_bus: - module_put(map->bus->owner); err_map: kfree(map); err: @@ -196,8 +224,8 @@ 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); } EXPORT_SYMBOL_GPL(regmap_exit); @@ -205,19 +233,38 @@ EXPORT_SYMBOL_GPL(regmap_exit); static int _regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { + u8 *u8 = map->work_buf; 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); - /* Try to do a gather write if we can */ - if (map->bus->gather_write) + u8[0] |= map->write_flag_mask; + + 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) ret = map->bus->gather_write(map->dev, map->work_buf, map->format.reg_bytes, val, val_len); - /* Otherwise fall back on linearising by hand. */ + /* If that didn't work fall back on linearising by hand. */ if (ret == -ENOTSUPP) { len = map->format.reg_bytes + val_len; buf = kmalloc(len, GFP_KERNEL); @@ -231,19 +278,31 @@ 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); - return map->bus->write(map->dev, map->work_buf, - map->format.buf_size); + 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; } else { map->format.format_val(map->work_buf + map->format.reg_bytes, val); @@ -317,20 +376,23 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, map->format.format_reg(map->work_buf, reg); /* - * Some buses flag reads by setting the high bits in the + * Some buses or devices flag reads by setting the high bits in the * register addresss; since it's always the high bits for all * current formats we can do this here rather than in * formatting. This may break if we get interesting formats. */ - if (map->bus->read_flag_mask) - u8[0] |= map->bus->read_flag_mask; + u8[0] |= map->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, map->format.val_bytes); - if (ret != 0) - return ret; + val, val_len); - return 0; + trace_regmap_hw_read_done(map->dev, reg, + val_len / map->format.val_bytes); + + return ret; } static int _regmap_read(struct regmap *map, unsigned int reg, @@ -342,8 +404,10 @@ 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; } @@ -462,3 +526,11 @@ out: 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/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 21574bdf485..a67adcbd0fa 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -404,6 +404,7 @@ config MFD_WM831X_I2C bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" select MFD_CORE select MFD_WM831X + select REGMAP_I2C depends on I2C=y && GENERIC_HARDIRQS help Support for the Wolfson Microelecronics WM831x and WM832x PMICs @@ -415,6 +416,7 @@ config MFD_WM831X_SPI bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" select MFD_CORE select MFD_WM831X + select REGMAP_SPI depends on SPI_MASTER && GENERIC_HARDIRQS help Support for the Wolfson Microelecronics WM831x and WM832x PMICs @@ -488,6 +490,7 @@ config MFD_WM8350_I2C config MFD_WM8994 bool "Support Wolfson Microelectronics WM8994" select MFD_CORE + select REGMAP_I2C depends on I2C=y && GENERIC_HARDIRQS help The WM8994 is a highly integrated hi-fi CODEC designed for diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 282e76ab678..9338f8dcbb8 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/mfd/core.h> #include <linux/slab.h> +#include <linux/err.h> #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> @@ -160,27 +161,350 @@ int wm831x_reg_unlock(struct wm831x *wm831x) } EXPORT_SYMBOL_GPL(wm831x_reg_unlock); -static int wm831x_read(struct wm831x *wm831x, unsigned short reg, - int bytes, void *dest) +static bool wm831x_reg_readable(struct device *dev, unsigned int reg) { - int ret, i; - u16 *buf = dest; - - BUG_ON(bytes % 2); - BUG_ON(bytes <= 0); + switch (reg) { + case WM831X_RESET_ID: + case WM831X_REVISION: + case WM831X_PARENT_ID: + case WM831X_SYSVDD_CONTROL: + case WM831X_THERMAL_MONITORING: + case WM831X_POWER_STATE: + case WM831X_WATCHDOG: + case WM831X_ON_PIN_CONTROL: + case WM831X_RESET_CONTROL: + case WM831X_CONTROL_INTERFACE: + case WM831X_SECURITY_KEY: + case WM831X_SOFTWARE_SCRATCH: + case WM831X_OTP_CONTROL: + case WM831X_GPIO_LEVEL: + case WM831X_SYSTEM_STATUS: + case WM831X_ON_SOURCE: + case WM831X_OFF_SOURCE: + case WM831X_SYSTEM_INTERRUPTS: + case WM831X_INTERRUPT_STATUS_1: + case WM831X_INTERRUPT_STATUS_2: + case WM831X_INTERRUPT_STATUS_3: + case WM831X_INTERRUPT_STATUS_4: + case WM831X_INTERRUPT_STATUS_5: + case WM831X_IRQ_CONFIG: + case WM831X_SYSTEM_INTERRUPTS_MASK: + case WM831X_INTERRUPT_STATUS_1_MASK: + case WM831X_INTERRUPT_STATUS_2_MASK: + case WM831X_INTERRUPT_STATUS_3_MASK: + case WM831X_INTERRUPT_STATUS_4_MASK: + case WM831X_INTERRUPT_STATUS_5_MASK: + case WM831X_RTC_WRITE_COUNTER: + case WM831X_RTC_TIME_1: + case WM831X_RTC_TIME_2: + case WM831X_RTC_ALARM_1: + case WM831X_RTC_ALARM_2: + case WM831X_RTC_CONTROL: + case WM831X_RTC_TRIM: + case WM831X_TOUCH_CONTROL_1: + case WM831X_TOUCH_CONTROL_2: + case WM831X_TOUCH_DATA_X: + case WM831X_TOUCH_DATA_Y: + case WM831X_TOUCH_DATA_Z: + case WM831X_AUXADC_DATA: + case WM831X_AUXADC_CONTROL: + case WM831X_AUXADC_SOURCE: + case WM831X_COMPARATOR_CONTROL: + case WM831X_COMPARATOR_1: + case WM831X_COMPARATOR_2: + case WM831X_COMPARATOR_3: + case WM831X_COMPARATOR_4: + case WM831X_GPIO1_CONTROL: + case WM831X_GPIO2_CONTROL: + case WM831X_GPIO3_CONTROL: + case WM831X_GPIO4_CONTROL: + case WM831X_GPIO5_CONTROL: + case WM831X_GPIO6_CONTROL: + case WM831X_GPIO7_CONTROL: + case WM831X_GPIO8_CONTROL: + case WM831X_GPIO9_CONTROL: + case WM831X_GPIO10_CONTROL: + case WM831X_GPIO11_CONTROL: + case WM831X_GPIO12_CONTROL: + case WM831X_GPIO13_CONTROL: + case WM831X_GPIO14_CONTROL: + case WM831X_GPIO15_CONTROL: + case WM831X_GPIO16_CONTROL: + case WM831X_CHARGER_CONTROL_1: + case WM831X_CHARGER_CONTROL_2: + case WM831X_CHARGER_STATUS: + case WM831X_BACKUP_CHARGER_CONTROL: + case WM831X_STATUS_LED_1: + case WM831X_STATUS_LED_2: + case WM831X_CURRENT_SINK_1: + case WM831X_CURRENT_SINK_2: + case WM831X_DCDC_ENABLE: + case WM831X_LDO_ENABLE: + case WM831X_DCDC_STATUS: + case WM831X_LDO_STATUS: + case WM831X_DCDC_UV_STATUS: + case WM831X_LDO_UV_STATUS: + case WM831X_DC1_CONTROL_1: + case WM831X_DC1_CONTROL_2: + case WM831X_DC1_ON_CONFIG: + case WM831X_DC1_SLEEP_CONTROL: + case WM831X_DC1_DVS_CONTROL: + case WM831X_DC2_CONTROL_1: + case WM831X_DC2_CONTROL_2: + case WM831X_DC2_ON_CONFIG: + case WM831X_DC2_SLEEP_CONTROL: + case WM831X_DC2_DVS_CONTROL: + case WM831X_DC3_CONTROL_1: + case WM831X_DC3_CONTROL_2: + case WM831X_DC3_ON_CONFIG: + case WM831X_DC3_SLEEP_CONTROL: + case WM831X_DC4_CONTROL: + case WM831X_DC4_SLEEP_CONTROL: + case WM831X_EPE1_CONTROL: + case WM831X_EPE2_CONTROL: + case WM831X_LDO1_CONTROL: + case WM831X_LDO1_ON_CONTROL: + case WM831X_LDO1_SLEEP_CONTROL: + case WM831X_LDO2_CONTROL: + case WM831X_LDO2_ON_CONTROL: + case WM831X_LDO2_SLEEP_CONTROL: + case WM831X_LDO3_CONTROL: + case WM831X_LDO3_ON_CONTROL: + case WM831X_LDO3_SLEEP_CONTROL: + case WM831X_LDO4_CONTROL: + case WM831X_LDO4_ON_CONTROL: + case WM831X_LDO4_SLEEP_CONTROL: + case WM831X_LDO5_CONTROL: + case WM831X_LDO5_ON_CONTROL: + case WM831X_LDO5_SLEEP_CONTROL: + case WM831X_LDO6_CONTROL: + case WM831X_LDO6_ON_CONTROL: + case WM831X_LDO6_SLEEP_CONTROL: + case WM831X_LDO7_CONTROL: + case WM831X_LDO7_ON_CONTROL: + case WM831X_LDO7_SLEEP_CONTROL: + case WM831X_LDO8_CONTROL: + case WM831X_LDO8_ON_CONTROL: + case WM831X_LDO8_SLEEP_CONTROL: + case WM831X_LDO9_CONTROL: + case WM831X_LDO9_ON_CONTROL: + case WM831X_LDO9_SLEEP_CONTROL: + case WM831X_LDO10_CONTROL: + case WM831X_LDO10_ON_CONTROL: + case WM831X_LDO10_SLEEP_CONTROL: + case WM831X_LDO11_ON_CONTROL: + case WM831X_LDO11_SLEEP_CONTROL: + case WM831X_POWER_GOOD_SOURCE_1: + case WM831X_POWER_GOOD_SOURCE_2: + case WM831X_CLOCK_CONTROL_1: + case WM831X_CLOCK_CONTROL_2: + case WM831X_FLL_CONTROL_1: + case WM831X_FLL_CONTROL_2: + case WM831X_FLL_CONTROL_3: + case WM831X_FLL_CONTROL_4: + case WM831X_FLL_CONTROL_5: + case WM831X_UNIQUE_ID_1: + case WM831X_UNIQUE_ID_2: + case WM831X_UNIQUE_ID_3: + case WM831X_UNIQUE_ID_4: + case WM831X_UNIQUE_ID_5: + case WM831X_UNIQUE_ID_6: + case WM831X_UNIQUE_ID_7: + case WM831X_UNIQUE_ID_8: + case WM831X_FACTORY_OTP_ID: + case WM831X_FACTORY_OTP_1: + case WM831X_FACTORY_OTP_2: + case WM831X_FACTORY_OTP_3: + case WM831X_FACTORY_OTP_4: + case WM831X_FACTORY_OTP_5: + case WM831X_CUSTOMER_OTP_ID: + case WM831X_DC1_OTP_CONTROL: + case WM831X_DC2_OTP_CONTROL: + case WM831X_DC3_OTP_CONTROL: + case WM831X_LDO1_2_OTP_CONTROL: + case WM831X_LDO3_4_OTP_CONTROL: + case WM831X_LDO5_6_OTP_CONTROL: + case WM831X_LDO7_8_OTP_CONTROL: + case WM831X_LDO9_10_OTP_CONTROL: + case WM831X_LDO11_EPE_CONTROL: + case WM831X_GPIO1_OTP_CONTROL: + case WM831X_GPIO2_OTP_CONTROL: + case WM831X_GPIO3_OTP_CONTROL: + case WM831X_GPIO4_OTP_CONTROL: + case WM831X_GPIO5_OTP_CONTROL: + case WM831X_GPIO6_OTP_CONTROL: + case WM831X_DBE_CHECK_DATA: + return true; + default: + return false; + } +} - ret = wm831x->read_dev(wm831x, reg, bytes, dest); - if (ret < 0) - return ret; +static bool wm831x_reg_writeable(struct device *dev, unsigned int reg) +{ + struct wm831x *wm831x = dev_get_drvdata(dev); - for (i = 0; i < bytes / 2; i++) { - buf[i] = be16_to_cpu(buf[i]); + if (wm831x_reg_locked(wm831x, reg)) + return false; - dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n", - buf[i], reg + i, reg + i); + switch (reg) { + case WM831X_SYSVDD_CONTROL: + case WM831X_THERMAL_MONITORING: + case WM831X_POWER_STATE: + case WM831X_WATCHDOG: + case WM831X_ON_PIN_CONTROL: + case WM831X_RESET_CONTROL: + case WM831X_CONTROL_INTERFACE: + case WM831X_SECURITY_KEY: + case WM831X_SOFTWARE_SCRATCH: + case WM831X_OTP_CONTROL: + case WM831X_GPIO_LEVEL: + case WM831X_INTERRUPT_STATUS_1: + case WM831X_INTERRUPT_STATUS_2: + case WM831X_INTERRUPT_STATUS_3: + case WM831X_INTERRUPT_STATUS_4: + case WM831X_INTERRUPT_STATUS_5: + case WM831X_IRQ_CONFIG: + case WM831X_SYSTEM_INTERRUPTS_MASK: + case WM831X_INTERRUPT_STATUS_1_MASK: + case WM831X_INTERRUPT_STATUS_2_MASK: + case WM831X_INTERRUPT_STATUS_3_MASK: + case WM831X_INTERRUPT_STATUS_4_MASK: + case WM831X_INTERRUPT_STATUS_5_MASK: + case WM831X_RTC_TIME_1: + case WM831X_RTC_TIME_2: + case WM831X_RTC_ALARM_1: + case WM831X_RTC_ALARM_2: + case WM831X_RTC_CONTROL: + case WM831X_RTC_TRIM: + case WM831X_TOUCH_CONTROL_1: + case WM831X_TOUCH_CONTROL_2: + case WM831X_AUXADC_CONTROL: + case WM831X_AUXADC_SOURCE: + case WM831X_COMPARATOR_CONTROL: + case WM831X_COMPARATOR_1: + case WM831X_COMPARATOR_2: + case WM831X_COMPARATOR_3: + case WM831X_COMPARATOR_4: + case WM831X_GPIO1_CONTROL: + case WM831X_GPIO2_CONTROL: + case WM831X_GPIO3_CONTROL: + case WM831X_GPIO4_CONTROL: + case WM831X_GPIO5_CONTROL: + case WM831X_GPIO6_CONTROL: + case WM831X_GPIO7_CONTROL: + case WM831X_GPIO8_CONTROL: + case WM831X_GPIO9_CONTROL: + case WM831X_GPIO10_CONTROL: + case WM831X_GPIO11_CONTROL: + case WM831X_GPIO12_CONTROL: + case WM831X_GPIO13_CONTROL: + case WM831X_GPIO14_CONTROL: + case WM831X_GPIO15_CONTROL: + case WM831X_GPIO16_CONTROL: + case WM831X_CHARGER_CONTROL_1: + case WM831X_CHARGER_CONTROL_2: + case WM831X_CHARGER_STATUS: + case WM831X_BACKUP_CHARGER_CONTROL: + case WM831X_STATUS_LED_1: + case WM831X_STATUS_LED_2: + case WM831X_CURRENT_SINK_1: + case WM831X_CURRENT_SINK_2: + case WM831X_DCDC_ENABLE: + case WM831X_LDO_ENABLE: + case WM831X_DC1_CONTROL_1: + case WM831X_DC1_CONTROL_2: + case WM831X_DC1_ON_CONFIG: + case WM831X_DC1_SLEEP_CONTROL: + case WM831X_DC1_DVS_CONTROL: + case WM831X_DC2_CONTROL_1: + case WM831X_DC2_CONTROL_2: + case WM831X_DC2_ON_CONFIG: + case WM831X_DC2_SLEEP_CONTROL: + case WM831X_DC2_DVS_CONTROL: + case WM831X_DC3_CONTROL_1: + case WM831X_DC3_CONTROL_2: + case WM831X_DC3_ON_CONFIG: + case WM831X_DC3_SLEEP_CONTROL: + case WM831X_DC4_CONTROL: + case WM831X_DC4_SLEEP_CONTROL: + case WM831X_EPE1_CONTROL: + case WM831X_EPE2_CONTROL: + case WM831X_LDO1_CONTROL: + case WM831X_LDO1_ON_CONTROL: + case WM831X_LDO1_SLEEP_CONTROL: + case WM831X_LDO2_CONTROL: + case WM831X_LDO2_ON_CONTROL: + case WM831X_LDO2_SLEEP_CONTROL: + case WM831X_LDO3_CONTROL: + case WM831X_LDO3_ON_CONTROL: + case WM831X_LDO3_SLEEP_CONTROL: + case WM831X_LDO4_CONTROL: + case WM831X_LDO4_ON_CONTROL: + case WM831X_LDO4_SLEEP_CONTROL: + case WM831X_LDO5_CONTROL: + case WM831X_LDO5_ON_CONTROL: + case WM831X_LDO5_SLEEP_CONTROL: + case WM831X_LDO6_CONTROL: + case WM831X_LDO6_ON_CONTROL: + case WM831X_LDO6_SLEEP_CONTROL: + case WM831X_LDO7_CONTROL: + case WM831X_LDO7_ON_CONTROL: + case WM831X_LDO7_SLEEP_CONTROL: + case WM831X_LDO8_CONTROL: + case WM831X_LDO8_ON_CONTROL: + case WM831X_LDO8_SLEEP_CONTROL: + case WM831X_LDO9_CONTROL: + case WM831X_LDO9_ON_CONTROL: + case WM831X_LDO9_SLEEP_CONTROL: + case WM831X_LDO10_CONTROL: + case WM831X_LDO10_ON_CONTROL: + case WM831X_LDO10_SLEEP_CONTROL: + case WM831X_LDO11_ON_CONTROL: + case WM831X_LDO11_SLEEP_CONTROL: + case WM831X_POWER_GOOD_SOURCE_1: + case WM831X_POWER_GOOD_SOURCE_2: + case WM831X_CLOCK_CONTROL_1: + case WM831X_CLOCK_CONTROL_2: + case WM831X_FLL_CONTROL_1: + case WM831X_FLL_CONTROL_2: + case WM831X_FLL_CONTROL_3: + case WM831X_FLL_CONTROL_4: + case WM831X_FLL_CONTROL_5: + return true; + default: + return false; } +} - return 0; +static bool wm831x_reg_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM831X_SYSTEM_STATUS: + case WM831X_ON_SOURCE: + case WM831X_OFF_SOURCE: + case WM831X_GPIO_LEVEL: + case WM831X_SYSTEM_INTERRUPTS: + case WM831X_INTERRUPT_STATUS_1: + case WM831X_INTERRUPT_STATUS_2: + case WM831X_INTERRUPT_STATUS_3: + case WM831X_INTERRUPT_STATUS_4: + case WM831X_INTERRUPT_STATUS_5: + case WM831X_RTC_TIME_1: + case WM831X_RTC_TIME_2: + case WM831X_TOUCH_DATA_X: + case WM831X_TOUCH_DATA_Y: + case WM831X_TOUCH_DATA_Z: + case WM831X_AUXADC_DATA: + case WM831X_CHARGER_STATUS: + case WM831X_DCDC_STATUS: + case WM831X_LDO_STATUS: + case WM831X_DCDC_UV_STATUS: + case WM831X_LDO_UV_STATUS: + return true; + default: + return false; + } } /** @@ -191,14 +515,10 @@ static int wm831x_read(struct wm831x *wm831x, unsigned short reg, */ int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg) { - unsigned short val; + unsigned int val; int ret; - mutex_lock(&wm831x->io_lock); - - ret = wm831x_read(wm831x, reg, 2, &val); - - mutex_unlock(&wm831x->io_lock); + ret = regmap_read(wm831x->regmap, reg, &val); if (ret < 0) return ret; @@ -218,15 +538,7 @@ EXPORT_SYMBOL_GPL(wm831x_reg_read); int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg, int count, u16 *buf) { - int ret; - - mutex_lock(&wm831x->io_lock); - - ret = wm831x_read(wm831x, reg, count * 2, buf); - - mutex_unlock(&wm831x->io_lock); - - return ret; + return regmap_bulk_read(wm831x->regmap, reg, buf, count); } EXPORT_SYMBOL_GPL(wm831x_bulk_read); @@ -234,7 +546,7 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { u16 *buf = src; - int i; + int i, ret; BUG_ON(bytes % 2); BUG_ON(bytes <= 0); @@ -245,11 +557,10 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n", buf[i], reg + i, reg + i); - - buf[i] = cpu_to_be16(buf[i]); + ret = regmap_write(wm831x->regmap, reg + i, buf[i]); } - return wm831x->write_dev(wm831x, reg, bytes, src); + return 0; } /** @@ -286,20 +597,14 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, unsigned short mask, unsigned short val) { int ret; - u16 r; mutex_lock(&wm831x->io_lock); - ret = wm831x_read(wm831x, reg, 2, &r); - if (ret < 0) - goto out; - - r &= ~mask; - r |= val & mask; - - ret = wm831x_write(wm831x, reg, 2, &r); + if (!wm831x_reg_locked(wm831x, reg)) + ret = regmap_update_bits(wm831x->regmap, reg, mask, val); + else + ret = -EPERM; -out: mutex_unlock(&wm831x->io_lock); return ret; @@ -1292,6 +1597,17 @@ static struct mfd_cell backlight_devs[] = { }, }; +struct regmap_config wm831x_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + + .max_register = WM831X_DBE_CHECK_DATA, + .readable_reg = wm831x_reg_readable, + .writeable_reg = wm831x_reg_writeable, + .volatile_reg = wm831x_reg_volatile, +}; +EXPORT_SYMBOL_GPL(wm831x_regmap_config); + /* * Instantiate the generic non-control parts of the device. */ @@ -1309,7 +1625,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); if (ret < 0) { dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret); - goto err; + goto err_regmap; } switch (ret) { case 0x6204: @@ -1318,20 +1634,20 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) default: dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret); ret = -EINVAL; - goto err; + goto err_regmap; } ret = wm831x_reg_read(wm831x, WM831X_REVISION); if (ret < 0) { dev_err(wm831x->dev, "Failed to read revision: %d\n", ret); - goto err; + goto err_regmap; } rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT; ret = wm831x_reg_read(wm831x, WM831X_RESET_ID); if (ret < 0) { dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret); - goto err; + goto err_regmap; } /* Some engineering samples do not have the ID set, rely on @@ -1406,7 +1722,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) default: dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); ret = -EINVAL; - goto err; + goto err_regmap; } /* This will need revisiting in future but is OK for all @@ -1420,7 +1736,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY); if (ret < 0) { dev_err(wm831x->dev, "Failed to read security key: %d\n", ret); - goto err; + goto err_regmap; } if (ret != 0) { dev_warn(wm831x->dev, "Security key had non-zero value %x\n", @@ -1433,7 +1749,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = pdata->pre_init(wm831x); if (ret != 0) { dev_err(wm831x->dev, "pre_init() failed: %d\n", ret); - goto err; + goto err_regmap; } } @@ -1456,7 +1772,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = wm831x_irq_init(wm831x, irq); if (ret != 0) - goto err; + goto err_regmap; wm831x_auxadc_init(wm831x); @@ -1552,8 +1868,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) err_irq: wm831x_irq_exit(wm831x); -err: +err_regmap: mfd_remove_devices(wm831x->dev); + regmap_exit(wm831x->regmap); kfree(wm831x); return ret; } @@ -1565,6 +1882,7 @@ void wm831x_device_exit(struct wm831x *wm831x) if (wm831x->irq_base) free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x); wm831x_irq_exit(wm831x); + regmap_exit(wm831x->regmap); kfree(wm831x); } diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index a06cbc73971..3ec6085d5fc 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -18,67 +18,17 @@ #include <linux/delay.h> #include <linux/mfd/core.h> #include <linux/slab.h> +#include <linux/err.h> +#include <linux/regmap.h> #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> -static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, - int bytes, void *dest) -{ - struct i2c_client *i2c = wm831x->control_data; - int ret; - u16 r = cpu_to_be16(reg); - - ret = i2c_master_send(i2c, (unsigned char *)&r, 2); - if (ret < 0) - return ret; - if (ret != 2) - return -EIO; - - ret = i2c_master_recv(i2c, dest, bytes); - if (ret < 0) - return ret; - if (ret != bytes) - return -EIO; - return 0; -} - -/* Currently we allocate the write buffer on the stack; this is OK for - * small writes - if we need to do large writes this will need to be - * revised. - */ -static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, - int bytes, void *src) -{ - struct i2c_client *i2c = wm831x->control_data; - struct i2c_msg xfer[2]; - int ret; - - reg = cpu_to_be16(reg); - - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = (char *)® - - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_NOSTART; - xfer[1].len = bytes; - xfer[1].buf = (char *)src; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret < 0) - return ret; - if (ret != 2) - return -EIO; - - return 0; -} - static int wm831x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm831x *wm831x; + int ret; wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) @@ -86,9 +36,15 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm831x); wm831x->dev = &i2c->dev; - wm831x->control_data = i2c; - wm831x->read_dev = wm831x_i2c_read_device; - wm831x->write_dev = wm831x_i2c_write_device; + + wm831x->regmap = regmap_init_i2c(i2c, &wm831x_regmap_config); + if (IS_ERR(wm831x->regmap)) { + ret = PTR_ERR(wm831x->regmap); + dev_err(wm831x->dev, "Failed to allocate register map: %d\n", + ret); + kfree(wm831x); + return ret; + } return wm831x_device_init(wm831x, id->driver_data, i2c->irq); } diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index eed8e4f7a5a..5ea60cd860f 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -16,78 +16,19 @@ #include <linux/module.h> #include <linux/pm.h> #include <linux/spi/spi.h> +#include <linux/regmap.h> +#include <linux/err.h> #include <linux/mfd/wm831x/core.h> -static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg, - int bytes, void *dest) -{ - u16 tx_val; - u16 *d = dest; - int r, ret; - - /* Go register at a time */ - for (r = reg; r < reg + (bytes / 2); r++) { - tx_val = r | 0x8000; - - ret = spi_write_then_read(wm831x->control_data, - (u8 *)&tx_val, 2, (u8 *)d, 2); - if (ret != 0) - return ret; - - *d = be16_to_cpu(*d); - - d++; - } - - return 0; -} - -static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg, - int bytes, void *src) -{ - struct spi_device *spi = wm831x->control_data; - u16 *s = src; - u16 data[2]; - int ret, r; - - /* Go register at a time */ - for (r = reg; r < reg + (bytes / 2); r++) { - data[0] = r; - data[1] = *s++; - - ret = spi_write(spi, (char *)&data, sizeof(data)); - if (ret != 0) - return ret; - } - - return 0; -} - static int __devinit wm831x_spi_probe(struct spi_device *spi) { + const struct spi_device_id *id = spi_get_device_id(spi); struct wm831x *wm831x; enum wm831x_parent type; + int ret; - /* Currently SPI support for ID tables is unmerged, we're faking it */ - if (strcmp(spi->modalias, "wm8310") == 0) - type = WM8310; - else if (strcmp(spi->modalias, "wm8311") == 0) - type = WM8311; - else if (strcmp(spi->modalias, "wm8312") == 0) - type = WM8312; - else if (strcmp(spi->modalias, "wm8320") == 0) - type = WM8320; - else if (strcmp(spi->modalias, "wm8321") == 0) - type = WM8321; - else if (strcmp(spi->modalias, "wm8325") == 0) - type = WM8325; - else if (strcmp(spi->modalias, "wm8326") == 0) - type = WM8326; - else { - dev_err(&spi->dev, "Unknown device type\n"); - return -EINVAL; - } + type = (enum wm831x_parent)id->driver_data; wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) @@ -98,9 +39,15 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) dev_set_drvdata(&spi->dev, wm831x); wm831x->dev = &spi->dev; - wm831x->control_data = spi; - wm831x->read_dev = wm831x_spi_read_device; - wm831x->write_dev = wm831x_spi_write_device; + + wm831x->regmap = regmap_init_spi(spi, &wm831x_regmap_config); + if (IS_ERR(wm831x->regmap)) { + ret = PTR_ERR(wm831x->regmap); + dev_err(wm831x->dev, "Failed to allocate register map: %d\n", + ret); + kfree(wm831x); + return ret; + } return wm831x_device_init(wm831x, type, spi->irq); } @@ -126,79 +73,26 @@ static const struct dev_pm_ops wm831x_spi_pm = { .suspend = wm831x_spi_suspend, }; -static struct spi_driver wm8310_spi_driver = { - .driver = { - .name = "wm8310", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - .pm = &wm831x_spi_pm, - }, - .probe = wm831x_spi_probe, - .remove = __devexit_p(wm831x_spi_remove), -}; - -static struct spi_driver wm8311_spi_driver = { - .driver = { - .name = "wm8311", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - .pm = &wm831x_spi_pm, - }, - .probe = wm831x_spi_probe, - .remove = __devexit_p(wm831x_spi_remove), -}; - -static struct spi_driver wm8312_spi_driver = { - .driver = { - .name = "wm8312", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - .pm = &wm831x_spi_pm, - }, - .probe = wm831x_spi_probe, - .remove = __devexit_p(wm831x_spi_remove), -}; - -static struct spi_driver wm8320_spi_driver = { - .driver = { - .name = "wm8320", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - .pm = &wm831x_spi_pm, - }, - .probe = wm831x_spi_probe, - .remove = __devexit_p(wm831x_spi_remove), -}; - -static struct spi_driver wm8321_spi_driver = { - .driver = { - .name = "wm8321", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - .pm = &wm831x_spi_pm, - }, - .probe = wm831x_spi_probe, - .remove = __devexit_p(wm831x_spi_remove), +static const struct spi_device_id wm831x_spi_ids[] = { + { "wm8310", WM8310 }, + { "wm8311", WM8311 }, + { "wm8312", WM8312 }, + { "wm8320", WM8320 }, + { "wm8321", WM8321 }, + { "wm8325", WM8325 }, + { "wm8326", WM8326 }, + { }, }; +MODULE_DEVICE_TABLE(spi, wm831x_spi_id); -static struct spi_driver wm8325_spi_driver = { +static struct spi_driver wm831x_spi_driver = { .driver = { - .name = "wm8325", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - .pm = &wm831x_spi_pm, - }, - .probe = wm831x_spi_probe, - .remove = __devexit_p(wm831x_spi_remove), -}; - -static struct spi_driver wm8326_spi_driver = { - .driver = { - .name = "wm8326", + .name = "wm831x", .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, + .id_table = wm831x_spi_ids, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), }; @@ -207,33 +101,9 @@ static int __init wm831x_spi_init(void) { int ret; - ret = spi_register_driver(&wm8310_spi_driver); - if (ret != 0) - pr_err("Failed to register WM8310 SPI driver: %d\n", ret); - - ret = spi_register_driver(&wm8311_spi_driver); - if (ret != 0) - pr_err("Failed to register WM8311 SPI driver: %d\n", ret); - - ret = spi_register_driver(&wm8312_spi_driver); - if (ret != 0) - pr_err("Failed to register WM8312 SPI driver: %d\n", ret); - - ret = spi_register_driver(&wm8320_spi_driver); - if (ret != 0) - pr_err("Failed to register WM8320 SPI driver: %d\n", ret); - - ret = spi_register_driver(&wm8321_spi_driver); - if (ret != 0) - pr_err("Failed to register WM8321 SPI driver: %d\n", ret); - - ret = spi_register_driver(&wm8325_spi_driver); - if (ret != 0) - pr_err("Failed to register WM8325 SPI driver: %d\n", ret); - - ret = spi_register_driver(&wm8326_spi_driver); + ret = spi_register_driver(&wm831x_spi_driver); if (ret != 0) - pr_err("Failed to register WM8326 SPI driver: %d\n", ret); + pr_err("Failed to register WM831x SPI driver: %d\n", ret); return 0; } @@ -241,13 +111,7 @@ subsys_initcall(wm831x_spi_init); static void __exit wm831x_spi_exit(void) { - spi_unregister_driver(&wm8326_spi_driver); - spi_unregister_driver(&wm8325_spi_driver); - spi_unregister_driver(&wm8321_spi_driver); - spi_unregister_driver(&wm8320_spi_driver); - spi_unregister_driver(&wm8312_spi_driver); - spi_unregister_driver(&wm8311_spi_driver); - spi_unregister_driver(&wm8310_spi_driver); + spi_unregister_driver(&wm831x_spi_driver); } module_exit(wm831x_spi_exit); diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 597f82edaca..e06ba9440cd 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -13,11 +13,13 @@ */ #include <linux/bug.h> +#include <linux/err.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/mfd/core.h> #include <linux/mfd/wm8400-private.h> #include <linux/mfd/wm8400-audio.h> +#include <linux/regmap.h> #include <linux/slab.h> static struct { @@ -123,14 +125,9 @@ static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest) /* If there are any volatile reads then read back the entire block */ for (i = reg; i < reg + num_regs; i++) if (reg_data[i].vol) { - ret = wm8400->read_dev(wm8400->io_data, reg, - num_regs, dest); - if (ret != 0) - return ret; - for (i = 0; i < num_regs; i++) - dest[i] = be16_to_cpu(dest[i]); - - return 0; + ret = regmap_bulk_read(wm8400->regmap, reg, dest, + num_regs); + return ret; } /* Otherwise use the cache */ @@ -149,14 +146,11 @@ static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs, for (i = 0; i < num_regs; i++) { BUG_ON(!reg_data[reg + i].writable); wm8400->reg_cache[reg + i] = src[i]; - src[i] = cpu_to_be16(src[i]); + ret = regmap_write(wm8400->regmap, reg, src[i]); + if (ret != 0) + return ret; } - /* Do the actual I/O */ - ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src); - if (ret != 0) - return -EIO; - return 0; } @@ -270,14 +264,14 @@ static int wm8400_init(struct wm8400 *wm8400, dev_set_drvdata(wm8400->dev, wm8400); /* Check that this is actually a WM8400 */ - ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, ®); + ret = regmap_read(wm8400->regmap, WM8400_RESET_ID, &i); if (ret != 0) { dev_err(wm8400->dev, "Chip ID register read failed\n"); return -EIO; } - if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) { + if (i != reg_data[WM8400_RESET_ID].default_val) { dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", - be16_to_cpu(reg)); + reg); return -ENODEV; } @@ -285,9 +279,8 @@ static int wm8400_init(struct wm8400 *wm8400, * is a PMIC we can't reset it safely so initialise the register * cache from the hardware. */ - ret = wm8400->read_dev(wm8400->io_data, 0, - ARRAY_SIZE(wm8400->reg_cache), - wm8400->reg_cache); + ret = regmap_raw_read(wm8400->regmap, 0, wm8400->reg_cache, + ARRAY_SIZE(wm8400->reg_cache)); if (ret != 0) { dev_err(wm8400->dev, "Register cache read failed\n"); return -EIO; @@ -337,60 +330,13 @@ static void wm8400_release(struct wm8400 *wm8400) mfd_remove_devices(wm8400->dev); } -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest) -{ - struct i2c_client *i2c = io_data; - struct i2c_msg xfer[2]; - int ret; - - /* Write register */ - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = count * sizeof(u16); - xfer[1].buf = (u8 *)dest; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret == 2) - ret = 0; - else if (ret >= 0) - ret = -EIO; - - return ret; -} - -static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src) -{ - struct i2c_client *i2c = io_data; - u8 *msg; - int ret; - - /* We add 1 byte for device register - ideally I2C would gather. */ - msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL); - if (msg == NULL) - return -ENOMEM; - - msg[0] = reg; - memcpy(&msg[1], src, count * sizeof(u16)); - - ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1); - - if (ret == (count * 2) + 1) - ret = 0; - else if (ret >= 0) - ret = -EIO; - - kfree(msg); - - return ret; -} +static const struct regmap_config wm8400_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = WM8400_REGISTER_COUNT - 1, +}; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static int wm8400_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -403,18 +349,23 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, goto err; } - wm8400->io_data = i2c; - wm8400->read_dev = wm8400_i2c_read; - wm8400->write_dev = wm8400_i2c_write; + wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config); + if (IS_ERR(wm8400->regmap)) { + ret = PTR_ERR(wm8400->regmap); + goto struct_err; + } + wm8400->dev = &i2c->dev; i2c_set_clientdata(i2c, wm8400); ret = wm8400_init(wm8400, i2c->dev.platform_data); if (ret != 0) - goto struct_err; + goto map_err; return 0; +map_err: + regmap_exit(wm8400->regmap); struct_err: kfree(wm8400); err: @@ -426,6 +377,7 @@ static int wm8400_i2c_remove(struct i2c_client *i2c) struct wm8400 *wm8400 = i2c_get_clientdata(i2c); wm8400_release(wm8400); + regmap_exit(wm8400->regmap); kfree(wm8400); return 0; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 96479c9b172..bfde4e8ec63 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -16,9 +16,11 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/err.h> #include <linux/delay.h> #include <linux/mfd/core.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/regulator/machine.h> @@ -29,22 +31,7 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, int bytes, void *dest) { - int ret, i; - u16 *buf = dest; - - BUG_ON(bytes % 2); - BUG_ON(bytes <= 0); - - ret = wm8994->read_dev(wm8994, reg, bytes, dest); - if (ret < 0) - return ret; - - for (i = 0; i < bytes / 2; i++) { - dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", - be16_to_cpu(buf[i]), reg + i, reg + i); - } - - return 0; + return regmap_raw_read(wm8994->regmap, reg, dest, bytes); } /** @@ -55,19 +42,15 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, */ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) { - unsigned short val; + unsigned int val; int ret; - mutex_lock(&wm8994->io_lock); - - ret = wm8994_read(wm8994, reg, 2, &val); - - mutex_unlock(&wm8994->io_lock); + ret = regmap_read(wm8994->regmap, reg, &val); if (ret < 0) return ret; else - return be16_to_cpu(val); + return val; } EXPORT_SYMBOL_GPL(wm8994_reg_read); @@ -82,33 +65,13 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read); int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, int count, u16 *buf) { - int ret; - - mutex_lock(&wm8994->io_lock); - - ret = wm8994_read(wm8994, reg, count * 2, buf); - - mutex_unlock(&wm8994->io_lock); - - return ret; + return regmap_bulk_read(wm8994->regmap, reg, buf, count); } -EXPORT_SYMBOL_GPL(wm8994_bulk_read); static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, int bytes, const void *src) { - const u16 *buf = src; - int i; - - BUG_ON(bytes % 2); - BUG_ON(bytes <= 0); - - for (i = 0; i < bytes / 2; i++) { - dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", - be16_to_cpu(buf[i]), reg + i, reg + i); - } - - return wm8994->write_dev(wm8994, reg, bytes, src); + return regmap_raw_write(wm8994->regmap, reg, src, bytes); } /** @@ -121,17 +84,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, unsigned short val) { - int ret; - - val = cpu_to_be16(val); - - mutex_lock(&wm8994->io_lock); - - ret = wm8994_write(wm8994, reg, 2, &val); - - mutex_unlock(&wm8994->io_lock); - - return ret; + return regmap_write(wm8994->regmap, reg, val); } EXPORT_SYMBOL_GPL(wm8994_reg_write); @@ -146,15 +99,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_write); int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, int count, const u16 *buf) { - int ret; - - mutex_lock(&wm8994->io_lock); - - ret = wm8994_write(wm8994, reg, count * 2, buf); - - mutex_unlock(&wm8994->io_lock); - - return ret; + return regmap_raw_write(wm8994->regmap, reg, buf, count * sizeof(u16)); } EXPORT_SYMBOL_GPL(wm8994_bulk_write); @@ -169,28 +114,7 @@ EXPORT_SYMBOL_GPL(wm8994_bulk_write); int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, unsigned short mask, unsigned short val) { - int ret; - u16 r; - - mutex_lock(&wm8994->io_lock); - - ret = wm8994_read(wm8994, reg, 2, &r); - if (ret < 0) - goto out; - - r = be16_to_cpu(r); - - r &= ~mask; - r |= val; - - r = cpu_to_be16(r); - - ret = wm8994_write(wm8994, reg, 2, &r); - -out: - mutex_unlock(&wm8994->io_lock); - - return ret; + return regmap_update_bits(wm8994->regmap, reg, mask, val); } EXPORT_SYMBOL_GPL(wm8994_set_bits); @@ -378,6 +302,11 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) } #endif +static struct regmap_config wm8994_regmap_config = { + .reg_bits = 16, + .val_bits = 16, +}; + /* * Instantiate the generic non-control parts of the device. */ @@ -387,7 +316,6 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) const char *devname; int ret, i; - mutex_init(&wm8994->io_lock); dev_set_drvdata(wm8994->dev, wm8994); /* Add the on-chip regulators first for bootstrapping */ @@ -397,7 +325,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) NULL, 0); if (ret != 0) { dev_err(wm8994->dev, "Failed to add children: %d\n", ret); - goto err; + goto err_regmap; } switch (wm8994->type) { @@ -409,7 +337,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) break; default: BUG(); - goto err; + goto err_regmap; } wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * @@ -417,7 +345,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) GFP_KERNEL); if (!wm8994->supplies) { ret = -ENOMEM; - goto err; + goto err_regmap; } switch (wm8994->type) { @@ -431,7 +359,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) break; default: BUG(); - goto err; + goto err_regmap; } ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, @@ -554,7 +482,8 @@ err_get: regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); err_supplies: kfree(wm8994->supplies); -err: +err_regmap: + regmap_exit(wm8994->regmap); mfd_remove_devices(wm8994->dev); kfree(wm8994); return ret; @@ -569,62 +498,15 @@ static void wm8994_device_exit(struct wm8994 *wm8994) wm8994->supplies); regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); kfree(wm8994->supplies); + regmap_exit(wm8994->regmap); kfree(wm8994); } -static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg, - int bytes, void *dest) -{ - struct i2c_client *i2c = wm8994->control_data; - int ret; - u16 r = cpu_to_be16(reg); - - ret = i2c_master_send(i2c, (unsigned char *)&r, 2); - if (ret < 0) - return ret; - if (ret != 2) - return -EIO; - - ret = i2c_master_recv(i2c, dest, bytes); - if (ret < 0) - return ret; - if (ret != bytes) - return -EIO; - return 0; -} - -static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, - int bytes, const void *src) -{ - struct i2c_client *i2c = wm8994->control_data; - struct i2c_msg xfer[2]; - int ret; - - reg = cpu_to_be16(reg); - - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = (char *)® - - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_NOSTART; - xfer[1].len = bytes; - xfer[1].buf = (char *)src; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret < 0) - return ret; - if (ret != 2) - return -EIO; - - return 0; -} - static int wm8994_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8994 *wm8994; + int ret; wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL); if (wm8994 == NULL) @@ -632,12 +514,18 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8994); wm8994->dev = &i2c->dev; - wm8994->control_data = i2c; - wm8994->read_dev = wm8994_i2c_read_device; - wm8994->write_dev = wm8994_i2c_write_device; wm8994->irq = i2c->irq; wm8994->type = id->driver_data; + wm8994->regmap = regmap_init_i2c(i2c, &wm8994_regmap_config); + if (IS_ERR(wm8994->regmap)) { + ret = PTR_ERR(wm8994->regmap); + dev_err(wm8994->dev, "Failed to allocate register map: %d\n", + ret); + kfree(wm8994); + return ret; + } + return wm8994_device_init(wm8994, i2c->irq); } diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h index 8dda8ded5cd..44acdb25681 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; @@ -416,4 +413,6 @@ 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/wm8400-private.h b/include/linux/mfd/wm8400-private.h index 2aab4e93a5c..0147b696851 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 f0b69cdae41..45df450d869 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 003c05349ae..18d4afaac16 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -89,25 +89,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; }; diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h new file mode 100644 index 00000000000..e35e37c378c --- /dev/null +++ b/include/trace/events/regmap.h @@ -0,0 +1,112 @@ +#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) +); + +#endif /* _TRACE_REGMAP_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> |