diff options
Diffstat (limited to 'drivers')
146 files changed, 8080 insertions, 5705 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index dcb8a6e4869..4b01ab3d2c2 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -24,6 +24,7 @@ #include <linux/wait.h> #include <linux/async.h> #include <linux/pm_runtime.h> +#include <scsi/scsi_scan.h> #include "base.h" #include "power/power.h" @@ -332,6 +333,7 @@ void wait_for_device_probe(void) /* wait for the known devices to complete their probing */ wait_event(probe_waitqueue, atomic_read(&probe_count) == 0); async_synchronize_full(); + scsi_complete_async_scans(); } EXPORT_SYMBOL_GPL(wait_for_device_probe); diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index b986b8660b0..80f9ab9c3aa 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -95,6 +95,9 @@ struct regmap { /* if set, converts bulk rw to single rw */ bool use_single_rw; + + struct rb_root range_tree; + void *selector_work_buf; /* Scratch buffer used for selector */ }; struct regcache_ops { @@ -115,6 +118,20 @@ bool regmap_precious(struct regmap *map, unsigned int reg); int _regmap_write(struct regmap *map, unsigned int reg, unsigned int val); +struct regmap_range_node { + struct rb_node node; + + unsigned int range_min; + unsigned int range_max; + + unsigned int selector_reg; + unsigned int selector_mask; + int selector_shift; + + unsigned int window_start; + unsigned int window_len; +}; + #ifdef CONFIG_DEBUG_FS extern void regmap_debugfs_initcall(void); extern void regmap_debugfs_init(struct regmap *map, const char *name); diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 4fac4b9be88..a89734621e5 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -24,14 +24,18 @@ struct regmap_irq_chip_data { struct mutex lock; struct regmap *map; - struct regmap_irq_chip *chip; + const struct regmap_irq_chip *chip; int irq_base; struct irq_domain *domain; + int irq; + int wake_count; + unsigned int *status_buf; unsigned int *mask_buf; unsigned int *mask_buf_def; + unsigned int *wake_buf; unsigned int irq_reg_stride; }; @@ -71,6 +75,16 @@ static void regmap_irq_sync_unlock(struct irq_data *data) d->chip->mask_base + (i * map->reg_stride)); } + /* If we've changed our wakeup count propagate it to the parent */ + if (d->wake_count < 0) + for (i = d->wake_count; i < 0; i++) + irq_set_irq_wake(d->irq, 0); + else if (d->wake_count > 0) + for (i = 0; i < d->wake_count; i++) + irq_set_irq_wake(d->irq, 1); + + d->wake_count = 0; + mutex_unlock(&d->lock); } @@ -92,18 +106,41 @@ static void regmap_irq_disable(struct irq_data *data) d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; } +static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); + struct regmap *map = d->map; + const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); + + if (!d->chip->wake_base) + return -EINVAL; + + if (on) { + d->wake_buf[irq_data->reg_offset / map->reg_stride] + &= ~irq_data->mask; + d->wake_count++; + } else { + d->wake_buf[irq_data->reg_offset / map->reg_stride] + |= irq_data->mask; + d->wake_count--; + } + + return 0; +} + static struct irq_chip regmap_irq_chip = { .name = "regmap", .irq_bus_lock = regmap_irq_lock, .irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_disable = regmap_irq_disable, .irq_enable = regmap_irq_enable, + .irq_set_wake = regmap_irq_set_wake, }; static irqreturn_t regmap_irq_thread(int irq, void *d) { struct regmap_irq_chip_data *data = d; - struct regmap_irq_chip *chip = data->chip; + const struct regmap_irq_chip *chip = data->chip; struct regmap *map = data->map; int ret, i; bool handled = false; @@ -195,7 +232,7 @@ static struct irq_domain_ops regmap_domain_ops = { * register values used by the IRQ controller over suspend and resume. */ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, - int irq_base, struct regmap_irq_chip *chip, + int irq_base, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data) { struct regmap_irq_chip_data *d; @@ -240,6 +277,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, if (!d->mask_buf_def) goto err_alloc; + if (chip->wake_base) { + d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, + GFP_KERNEL); + if (!d->wake_buf) + goto err_alloc; + } + + d->irq = irq; d->map = map; d->chip = chip; d->irq_base = irq_base; @@ -294,6 +339,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, err_domain: /* Should really dispose of the domain but... */ err_alloc: + kfree(d->wake_buf); kfree(d->mask_buf_def); kfree(d->mask_buf); kfree(d->status_buf); @@ -315,6 +361,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) free_irq(irq, d); /* We should unmap the domain but... */ + kfree(d->wake_buf); kfree(d->mask_buf_def); kfree(d->mask_buf); kfree(d->status_buf); @@ -346,6 +393,10 @@ EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); */ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) { + /* Handle holes in the IRQ list */ + if (!data->chip->irqs[irq].mask) + return -EINVAL; + return irq_create_mapping(data->domain, irq); } EXPORT_SYMBOL_GPL(regmap_irq_get_virq); diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index febd6de6c8a..f05fc74dd84 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -37,7 +37,7 @@ static int regmap_mmio_gather_write(void *context, BUG_ON(reg_size != 4); - offset = be32_to_cpup(reg); + offset = *(u32 *)reg; while (val_size) { switch (ctx->val_bytes) { @@ -45,14 +45,14 @@ static int regmap_mmio_gather_write(void *context, writeb(*(u8 *)val, ctx->regs + offset); break; case 2: - writew(be16_to_cpup(val), ctx->regs + offset); + writew(*(u16 *)val, ctx->regs + offset); break; case 4: - writel(be32_to_cpup(val), ctx->regs + offset); + writel(*(u32 *)val, ctx->regs + offset); break; #ifdef CONFIG_64BIT case 8: - writeq(be64_to_cpup(val), ctx->regs + offset); + writeq(*(u64 *)val, ctx->regs + offset); break; #endif default: @@ -83,7 +83,7 @@ static int regmap_mmio_read(void *context, BUG_ON(reg_size != 4); - offset = be32_to_cpup(reg); + offset = *(u32 *)reg; while (val_size) { switch (ctx->val_bytes) { @@ -91,14 +91,14 @@ static int regmap_mmio_read(void *context, *(u8 *)val = readb(ctx->regs + offset); break; case 2: - *(u16 *)val = cpu_to_be16(readw(ctx->regs + offset)); + *(u16 *)val = readw(ctx->regs + offset); break; case 4: - *(u32 *)val = cpu_to_be32(readl(ctx->regs + offset)); + *(u32 *)val = readl(ctx->regs + offset); break; #ifdef CONFIG_64BIT case 8: - *(u64 *)val = cpu_to_be32(readq(ctx->regs + offset)); + *(u64 *)val = readq(ctx->regs + offset); break; #endif default: @@ -124,9 +124,11 @@ static struct regmap_bus regmap_mmio = { .gather_write = regmap_mmio_gather_write, .read = regmap_mmio_read, .free_context = regmap_mmio_free_context, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, }; -struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, +static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, const struct regmap_config *config) { struct regmap_mmio_context *ctx; @@ -162,7 +164,15 @@ struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, if (config->reg_stride < min_stride) return ERR_PTR(-EINVAL); - ctx = kzalloc(GFP_KERNEL, sizeof(*ctx)); + switch (config->reg_format_endian) { + case REGMAP_ENDIAN_DEFAULT: + case REGMAP_ENDIAN_NATIVE: + break; + default: + return ERR_PTR(-EINVAL); + } + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return ERR_PTR(-ENOMEM); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index c89aa01fb1d..c241ae2f2f1 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -15,12 +15,25 @@ #include <linux/export.h> #include <linux/mutex.h> #include <linux/err.h> +#include <linux/rbtree.h> #define CREATE_TRACE_POINTS #include <trace/events/regmap.h> #include "internal.h" +/* + * Sometimes for failures during very early init the trace + * infrastructure isn't available early enough to be used. For this + * sort of problem defining LOG_DEVICE will add printks for basic + * register I/O on a specific device. + */ +#undef LOG_DEVICE + +static int _regmap_update_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change); + bool regmap_writeable(struct regmap *map, unsigned int reg) { if (map->max_register && reg > map->max_register) @@ -119,13 +132,19 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift) b[0] = val << shift; } -static void regmap_format_16(void *buf, unsigned int val, unsigned int shift) +static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift) { __be16 *b = buf; b[0] = cpu_to_be16(val << shift); } +static void regmap_format_16_native(void *buf, unsigned int val, + unsigned int shift) +{ + *(u16 *)buf = val << shift; +} + static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) { u8 *b = buf; @@ -137,13 +156,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) b[2] = val; } -static void regmap_format_32(void *buf, unsigned int val, unsigned int shift) +static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) { __be32 *b = buf; b[0] = cpu_to_be32(val << shift); } +static void regmap_format_32_native(void *buf, unsigned int val, + unsigned int shift) +{ + *(u32 *)buf = val << shift; +} + static unsigned int regmap_parse_8(void *buf) { u8 *b = buf; @@ -151,7 +176,7 @@ static unsigned int regmap_parse_8(void *buf) return b[0]; } -static unsigned int regmap_parse_16(void *buf) +static unsigned int regmap_parse_16_be(void *buf) { __be16 *b = buf; @@ -160,6 +185,11 @@ static unsigned int regmap_parse_16(void *buf) return b[0]; } +static unsigned int regmap_parse_16_native(void *buf) +{ + return *(u16 *)buf; +} + static unsigned int regmap_parse_24(void *buf) { u8 *b = buf; @@ -170,7 +200,7 @@ static unsigned int regmap_parse_24(void *buf) return ret; } -static unsigned int regmap_parse_32(void *buf) +static unsigned int regmap_parse_32_be(void *buf) { __be32 *b = buf; @@ -179,6 +209,11 @@ static unsigned int regmap_parse_32(void *buf) return b[0]; } +static unsigned int regmap_parse_32_native(void *buf) +{ + return *(u32 *)buf; +} + static void regmap_lock_mutex(struct regmap *map) { mutex_lock(&map->mutex); @@ -208,6 +243,67 @@ static void dev_get_regmap_release(struct device *dev, void *res) */ } +static bool _regmap_range_add(struct regmap *map, + struct regmap_range_node *data) +{ + struct rb_root *root = &map->range_tree; + struct rb_node **new = &(root->rb_node), *parent = NULL; + + while (*new) { + struct regmap_range_node *this = + container_of(*new, struct regmap_range_node, node); + + parent = *new; + if (data->range_max < this->range_min) + new = &((*new)->rb_left); + else if (data->range_min > this->range_max) + new = &((*new)->rb_right); + else + return false; + } + + rb_link_node(&data->node, parent, new); + rb_insert_color(&data->node, root); + + return true; +} + +static struct regmap_range_node *_regmap_range_lookup(struct regmap *map, + unsigned int reg) +{ + struct rb_node *node = map->range_tree.rb_node; + + while (node) { + struct regmap_range_node *this = + container_of(node, struct regmap_range_node, node); + + if (reg < this->range_min) + node = node->rb_left; + else if (reg > this->range_max) + node = node->rb_right; + else + return this; + } + + return NULL; +} + +static void regmap_range_exit(struct regmap *map) +{ + struct rb_node *next; + struct regmap_range_node *range_node; + + next = rb_first(&map->range_tree); + while (next) { + range_node = rb_entry(next, struct regmap_range_node, node); + next = rb_next(&range_node->node); + rb_erase(&range_node->node, &map->range_tree); + kfree(range_node); + } + + kfree(map->selector_work_buf); +} + /** * regmap_init(): Initialise register map * @@ -227,6 +323,8 @@ struct regmap *regmap_init(struct device *dev, { struct regmap *map, **m; int ret = -EINVAL; + enum regmap_endian reg_endian, val_endian; + int i, j; if (!bus || !config) goto err; @@ -275,6 +373,18 @@ struct regmap *regmap_init(struct device *dev, map->read_flag_mask = bus->read_flag_mask; } + reg_endian = config->reg_format_endian; + if (reg_endian == REGMAP_ENDIAN_DEFAULT) + reg_endian = bus->reg_format_endian_default; + if (reg_endian == REGMAP_ENDIAN_DEFAULT) + reg_endian = REGMAP_ENDIAN_BIG; + + val_endian = config->val_format_endian; + if (val_endian == REGMAP_ENDIAN_DEFAULT) + val_endian = bus->val_format_endian_default; + if (val_endian == REGMAP_ENDIAN_DEFAULT) + val_endian = REGMAP_ENDIAN_BIG; + switch (config->reg_bits + map->reg_shift) { case 2: switch (config->val_bits) { @@ -321,11 +431,29 @@ struct regmap *regmap_init(struct device *dev, break; case 16: - map->format.format_reg = regmap_format_16; + switch (reg_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_reg = regmap_format_16_be; + break; + case REGMAP_ENDIAN_NATIVE: + map->format.format_reg = regmap_format_16_native; + break; + default: + goto err_map; + } break; case 32: - map->format.format_reg = regmap_format_32; + switch (reg_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_reg = regmap_format_32_be; + break; + case REGMAP_ENDIAN_NATIVE: + map->format.format_reg = regmap_format_32_native; + break; + default: + goto err_map; + } break; default: @@ -338,21 +466,47 @@ struct regmap *regmap_init(struct device *dev, map->format.parse_val = regmap_parse_8; break; case 16: - map->format.format_val = regmap_format_16; - map->format.parse_val = regmap_parse_16; + switch (val_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_val = regmap_format_16_be; + map->format.parse_val = regmap_parse_16_be; + break; + case REGMAP_ENDIAN_NATIVE: + map->format.format_val = regmap_format_16_native; + map->format.parse_val = regmap_parse_16_native; + break; + default: + goto err_map; + } break; case 24: + if (val_endian != REGMAP_ENDIAN_BIG) + goto err_map; map->format.format_val = regmap_format_24; map->format.parse_val = regmap_parse_24; break; case 32: - map->format.format_val = regmap_format_32; - map->format.parse_val = regmap_parse_32; + switch (val_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_val = regmap_format_32_be; + map->format.parse_val = regmap_parse_32_be; + break; + case REGMAP_ENDIAN_NATIVE: + map->format.format_val = regmap_format_32_native; + map->format.parse_val = regmap_parse_32_native; + break; + default: + goto err_map; + } break; } - if (map->format.format_write) + if (map->format.format_write) { + if ((reg_endian != REGMAP_ENDIAN_BIG) || + (val_endian != REGMAP_ENDIAN_BIG)) + goto err_map; map->use_single_rw = true; + } if (!map->format.format_write && !(map->format.format_reg && map->format.format_val)) @@ -364,27 +518,88 @@ struct regmap *regmap_init(struct device *dev, goto err_map; } - regmap_debugfs_init(map, config->name); + map->range_tree = RB_ROOT; + for (i = 0; i < config->n_ranges; i++) { + const struct regmap_range_cfg *range_cfg = &config->ranges[i]; + struct regmap_range_node *new; + + /* Sanity check */ + if (range_cfg->range_max < range_cfg->range_min || + range_cfg->range_max > map->max_register || + range_cfg->selector_reg > map->max_register || + range_cfg->window_len == 0) + goto err_range; + + /* Make sure, that this register range has no selector + or data window within its boundary */ + for (j = 0; j < config->n_ranges; j++) { + unsigned sel_reg = config->ranges[j].selector_reg; + unsigned win_min = config->ranges[j].window_start; + unsigned win_max = win_min + + config->ranges[j].window_len - 1; + + if (range_cfg->range_min <= sel_reg && + sel_reg <= range_cfg->range_max) { + goto err_range; + } + + if (!(win_max < range_cfg->range_min || + win_min > range_cfg->range_max)) { + goto err_range; + } + } + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (new == NULL) { + ret = -ENOMEM; + goto err_range; + } + + new->range_min = range_cfg->range_min; + new->range_max = range_cfg->range_max; + new->selector_reg = range_cfg->selector_reg; + new->selector_mask = range_cfg->selector_mask; + new->selector_shift = range_cfg->selector_shift; + new->window_start = range_cfg->window_start; + new->window_len = range_cfg->window_len; + + if (_regmap_range_add(map, new) == false) { + kfree(new); + goto err_range; + } + + if (map->selector_work_buf == NULL) { + map->selector_work_buf = + kzalloc(map->format.buf_size, GFP_KERNEL); + if (map->selector_work_buf == NULL) { + ret = -ENOMEM; + goto err_range; + } + } + } ret = regcache_init(map, config); if (ret < 0) - goto err_debugfs; + goto err_range; + + regmap_debugfs_init(map, config->name); /* Add a devres resource for dev_get_regmap() */ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); if (!m) { ret = -ENOMEM; - goto err_cache; + goto err_debugfs; } *m = map; devres_add(dev, m); return map; -err_cache: - regcache_exit(map); err_debugfs: regmap_debugfs_exit(map); + regcache_exit(map); +err_range: + regmap_range_exit(map); kfree(map->work_buf); err_map: kfree(map); @@ -481,6 +696,7 @@ void regmap_exit(struct regmap *map) { regcache_exit(map); regmap_debugfs_exit(map); + regmap_range_exit(map); if (map->bus->free_context) map->bus->free_context(map->bus_context); kfree(map->work_buf); @@ -526,6 +742,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) } EXPORT_SYMBOL_GPL(dev_get_regmap); +static int _regmap_select_page(struct regmap *map, unsigned int *reg, + unsigned int val_num) +{ + struct regmap_range_node *range; + void *orig_work_buf; + unsigned int win_offset; + unsigned int win_page; + bool page_chg; + int ret; + + range = _regmap_range_lookup(map, *reg); + if (range) { + win_offset = (*reg - range->range_min) % range->window_len; + win_page = (*reg - range->range_min) / range->window_len; + + if (val_num > 1) { + /* Bulk write shouldn't cross range boundary */ + if (*reg + val_num - 1 > range->range_max) + return -EINVAL; + + /* ... or single page boundary */ + if (val_num > range->window_len - win_offset) + return -EINVAL; + } + + /* It is possible to have selector register inside data window. + In that case, selector register is located on every page and + it needs no page switching, when accessed alone. */ + if (val_num > 1 || + range->window_start + win_offset != range->selector_reg) { + /* Use separate work_buf during page switching */ + orig_work_buf = map->work_buf; + map->work_buf = map->selector_work_buf; + + ret = _regmap_update_bits(map, range->selector_reg, + range->selector_mask, + win_page << range->selector_shift, + &page_chg); + + map->work_buf = orig_work_buf; + + if (ret < 0) + return ret; + } + + *reg = range->window_start + win_offset; + } + + return 0; +} + static int _regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len) { @@ -563,6 +830,10 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, } } + ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); + if (ret < 0) + return ret; + map->format.format_reg(map->work_buf, reg, map->reg_shift); u8[0] |= map->write_flag_mask; @@ -623,9 +894,18 @@ int _regmap_write(struct regmap *map, unsigned int reg, } } +#ifdef LOG_DEVICE + if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + dev_info(map->dev, "%x <= %x\n", reg, val); +#endif + trace_regmap_reg_write(map->dev, reg, val); if (map->format.format_write) { + ret = _regmap_select_page(map, ®, 1); + if (ret < 0) + return ret; + map->format.format_write(map, reg, val); trace_regmap_hw_write_start(map->dev, reg, 1); @@ -783,6 +1063,10 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, u8 *u8 = map->work_buf; int ret; + ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); + if (ret < 0) + return ret; + map->format.format_reg(map->work_buf, reg, map->reg_shift); /* @@ -826,6 +1110,12 @@ static int _regmap_read(struct regmap *map, unsigned int reg, ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); if (ret == 0) { *val = map->format.parse_val(map->work_buf); + +#ifdef LOG_DEVICE + if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + dev_info(map->dev, "%x => %x\n", reg, *val); +#endif + trace_regmap_reg_read(map->dev, reg, *val); } @@ -982,11 +1272,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, int ret; unsigned int tmp, orig; - map->lock(map); - ret = _regmap_read(map, reg, &orig); if (ret != 0) - goto out; + return ret; tmp = orig & ~mask; tmp |= val & mask; @@ -998,9 +1286,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, *change = false; } -out: - map->unlock(map); - return ret; } @@ -1018,7 +1303,13 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val) { bool change; - return _regmap_update_bits(map, reg, mask, val, &change); + int ret; + + map->lock(map); + ret = _regmap_update_bits(map, reg, mask, val, &change); + map->unlock(map); + + return ret; } EXPORT_SYMBOL_GPL(regmap_update_bits); @@ -1038,7 +1329,12 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change) { - return _regmap_update_bits(map, reg, mask, val, change); + int ret; + + map->lock(map); + ret = _regmap_update_bits(map, reg, mask, val, change); + map->unlock(map); + return ret; } EXPORT_SYMBOL_GPL(regmap_update_bits_check); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 65665c9c42c..8f428a8ab00 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -499,7 +499,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header, / sizeof (*ondisk)) return -EINVAL; header->snapc = kmalloc(sizeof(struct ceph_snap_context) + - snap_count * sizeof (*ondisk), + snap_count * sizeof(u64), gfp_flags); if (!header->snapc) return -ENOMEM; @@ -977,7 +977,7 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg) op = (void *)(replyhead + 1); rc = le32_to_cpu(replyhead->result); bytes = le64_to_cpu(op->extent.length); - read_op = (le32_to_cpu(op->op) == CEPH_OSD_OP_READ); + read_op = (le16_to_cpu(op->op) == CEPH_OSD_OP_READ); dout("rbd_req_cb bytes=%lld readop=%d rc=%d\n", bytes, read_op, rc); diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c index 8f05652d53e..0fcec2aae19 100644 --- a/drivers/clk/spear/spear1310_clock.c +++ b/drivers/clk/spear/spear1310_clock.c @@ -345,31 +345,30 @@ static struct frac_rate_tbl gen_rtbl[] = { /* clock parents */ static const char *vco_parents[] = { "osc_24m_clk", "osc_25m_clk", }; static const char *gpt_parents[] = { "osc_24m_clk", "apb_clk", }; -static const char *uart0_parents[] = { "pll5_clk", "uart_synth_gate_clk", }; -static const char *c3_parents[] = { "pll5_clk", "c3_synth_gate_clk", }; -static const char *gmac_phy_input_parents[] = { "gmii_125m_pad_clk", "pll2_clk", +static const char *uart0_parents[] = { "pll5_clk", "uart_syn_gclk", }; +static const char *c3_parents[] = { "pll5_clk", "c3_syn_gclk", }; +static const char *gmac_phy_input_parents[] = { "gmii_pad_clk", "pll2_clk", "osc_25m_clk", }; -static const char *gmac_phy_parents[] = { "gmac_phy_input_mux_clk", - "gmac_phy_synth_gate_clk", }; +static const char *gmac_phy_parents[] = { "phy_input_mclk", "phy_syn_gclk", }; static const char *clcd_synth_parents[] = { "vco1div4_clk", "pll2_clk", }; -static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_synth_clk", }; +static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_syn_clk", }; static const char *i2s_src_parents[] = { "vco1div2_clk", "none", "pll3_clk", "i2s_src_pad_clk", }; -static const char *i2s_ref_parents[] = { "i2s_src_mux_clk", "i2s_prs1_clk", }; +static const char *i2s_ref_parents[] = { "i2s_src_mclk", "i2s_prs1_clk", }; static const char *gen_synth0_1_parents[] = { "vco1div4_clk", "vco3div2_clk", "pll3_clk", }; static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco3div2_clk", "pll2_clk", }; static const char *rmii_phy_parents[] = { "ras_tx50_clk", "none", - "ras_pll2_clk", "ras_synth0_clk", }; + "ras_pll2_clk", "ras_syn0_clk", }; static const char *smii_rgmii_phy_parents[] = { "none", "ras_tx125_clk", - "ras_pll2_clk", "ras_synth0_clk", }; -static const char *uart_parents[] = { "ras_apb_clk", "gen_synth3_clk", }; -static const char *i2c_parents[] = { "ras_apb_clk", "gen_synth1_clk", }; -static const char *ssp1_parents[] = { "ras_apb_clk", "gen_synth1_clk", + "ras_pll2_clk", "ras_syn0_clk", }; +static const char *uart_parents[] = { "ras_apb_clk", "gen_syn3_clk", }; +static const char *i2c_parents[] = { "ras_apb_clk", "gen_syn1_clk", }; +static const char *ssp1_parents[] = { "ras_apb_clk", "gen_syn1_clk", "ras_plclk0_clk", }; -static const char *pci_parents[] = { "ras_pll3_clk", "gen_synth2_clk", }; -static const char *tdm_parents[] = { "ras_pll3_clk", "gen_synth1_clk", }; +static const char *pci_parents[] = { "ras_pll3_clk", "gen_syn2_clk", }; +static const char *tdm_parents[] = { "ras_pll3_clk", "gen_syn1_clk", }; void __init spear1310_clk_init(void) { @@ -390,9 +389,9 @@ void __init spear1310_clk_init(void) 25000000); clk_register_clkdev(clk, "osc_25m_clk", NULL); - clk = clk_register_fixed_rate(NULL, "gmii_125m_pad_clk", NULL, - CLK_IS_ROOT, 125000000); - clk_register_clkdev(clk, "gmii_125m_pad_clk", NULL); + clk = clk_register_fixed_rate(NULL, "gmii_pad_clk", NULL, CLK_IS_ROOT, + 125000000); + clk_register_clkdev(clk, "gmii_pad_clk", NULL); clk = clk_register_fixed_rate(NULL, "i2s_src_pad_clk", NULL, CLK_IS_ROOT, 12288000); @@ -406,34 +405,34 @@ void __init spear1310_clk_init(void) /* clock derived from 24 or 25 MHz osc clk */ /* vco-pll */ - clk = clk_register_mux(NULL, "vco1_mux_clk", vco_parents, + clk = clk_register_mux(NULL, "vco1_mclk", vco_parents, ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG, SPEAR1310_PLL1_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "vco1_mux_clk", NULL); - clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mux_clk", + clk_register_clkdev(clk, "vco1_mclk", NULL); + clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk", 0, SPEAR1310_PLL1_CTR, SPEAR1310_PLL1_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); clk_register_clkdev(clk, "vco1_clk", NULL); clk_register_clkdev(clk1, "pll1_clk", NULL); - clk = clk_register_mux(NULL, "vco2_mux_clk", vco_parents, + clk = clk_register_mux(NULL, "vco2_mclk", vco_parents, ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG, SPEAR1310_PLL2_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "vco2_mux_clk", NULL); - clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mux_clk", + clk_register_clkdev(clk, "vco2_mclk", NULL); + clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk", 0, SPEAR1310_PLL2_CTR, SPEAR1310_PLL2_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); clk_register_clkdev(clk, "vco2_clk", NULL); clk_register_clkdev(clk1, "pll2_clk", NULL); - clk = clk_register_mux(NULL, "vco3_mux_clk", vco_parents, + clk = clk_register_mux(NULL, "vco3_mclk", vco_parents, ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG, SPEAR1310_PLL3_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "vco3_mux_clk", NULL); - clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mux_clk", + clk_register_clkdev(clk, "vco3_mclk", NULL); + clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk", 0, SPEAR1310_PLL3_CTR, SPEAR1310_PLL3_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); clk_register_clkdev(clk, "vco3_clk", NULL); @@ -473,7 +472,7 @@ void __init spear1310_clk_init(void) /* peripherals */ clk_register_fixed_factor(NULL, "thermal_clk", "osc_24m_clk", 0, 1, 128); - clk = clk_register_gate(NULL, "thermal_gate_clk", "thermal_clk", 0, + clk = clk_register_gate(NULL, "thermal_gclk", "thermal_clk", 0, SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_THSENS_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_thermal"); @@ -500,177 +499,176 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "apb_clk", NULL); /* gpt clocks */ - clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT0_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt0_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mux_clk", 0, + clk_register_clkdev(clk, "gpt0_mclk", NULL); + clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt0"); - clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT1_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt1_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, + clk_register_clkdev(clk, "gpt1_mclk", NULL); + clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt1"); - clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT2_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt2_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, + clk_register_clkdev(clk, "gpt2_mclk", NULL); + clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0, SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt2"); - clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT3_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt3_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0, + clk_register_clkdev(clk, "gpt3_mclk", NULL); + clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0, SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt3"); /* others */ - clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", - "vco1div2_clk", 0, SPEAR1310_UART_CLK_SYNT, NULL, - aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "uart_synth_clk", NULL); - clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); + clk = clk_register_aux("uart_syn_clk", "uart_syn_gclk", "vco1div2_clk", + 0, SPEAR1310_UART_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "uart_syn_clk", NULL); + clk_register_clkdev(clk1, "uart_syn_gclk", NULL); - clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents, + clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents, ARRAY_SIZE(uart0_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_UART_CLK_SHIFT, SPEAR1310_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart0_mux_clk", NULL); + clk_register_clkdev(clk, "uart0_mclk", NULL); - clk = clk_register_gate(NULL, "uart0_clk", "uart0_mux_clk", 0, + clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UART_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "e0000000.serial"); - clk = clk_register_aux("sdhci_synth_clk", "sdhci_synth_gate_clk", + clk = clk_register_aux("sdhci_syn_clk", "sdhci_syn_gclk", "vco1div2_clk", 0, SPEAR1310_SDHCI_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "sdhci_synth_clk", NULL); - clk_register_clkdev(clk1, "sdhci_synth_gate_clk", NULL); + clk_register_clkdev(clk, "sdhci_syn_clk", NULL); + clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL); - clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_synth_gate_clk", 0, + clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SDHCI_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b3000000.sdhci"); - clk = clk_register_aux("cfxd_synth_clk", "cfxd_synth_gate_clk", - "vco1div2_clk", 0, SPEAR1310_CFXD_CLK_SYNT, NULL, - aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "cfxd_synth_clk", NULL); - clk_register_clkdev(clk1, "cfxd_synth_gate_clk", NULL); + clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk", + 0, SPEAR1310_CFXD_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "cfxd_syn_clk", NULL); + clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL); - clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_synth_gate_clk", 0, + clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CFXD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b2800000.cf"); clk_register_clkdev(clk, NULL, "arasan_xd"); - clk = clk_register_aux("c3_synth_clk", "c3_synth_gate_clk", - "vco1div2_clk", 0, SPEAR1310_C3_CLK_SYNT, NULL, - aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "c3_synth_clk", NULL); - clk_register_clkdev(clk1, "c3_synth_gate_clk", NULL); + clk = clk_register_aux("c3_syn_clk", "c3_syn_gclk", "vco1div2_clk", + 0, SPEAR1310_C3_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "c3_syn_clk", NULL); + clk_register_clkdev(clk1, "c3_syn_gclk", NULL); - clk = clk_register_mux(NULL, "c3_mux_clk", c3_parents, + clk = clk_register_mux(NULL, "c3_mclk", c3_parents, ARRAY_SIZE(c3_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_C3_CLK_SHIFT, SPEAR1310_C3_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "c3_mux_clk", NULL); + clk_register_clkdev(clk, "c3_mclk", NULL); - clk = clk_register_gate(NULL, "c3_clk", "c3_mux_clk", 0, + clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_C3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "c3"); /* gmac */ - clk = clk_register_mux(NULL, "gmac_phy_input_mux_clk", - gmac_phy_input_parents, + clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents, ARRAY_SIZE(gmac_phy_input_parents), 0, SPEAR1310_GMAC_CLK_CFG, SPEAR1310_GMAC_PHY_INPUT_CLK_SHIFT, SPEAR1310_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gmac_phy_input_mux_clk", NULL); + clk_register_clkdev(clk, "phy_input_mclk", NULL); - clk = clk_register_aux("gmac_phy_synth_clk", "gmac_phy_synth_gate_clk", - "gmac_phy_input_mux_clk", 0, SPEAR1310_GMAC_CLK_SYNT, - NULL, gmac_rtbl, ARRAY_SIZE(gmac_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "gmac_phy_synth_clk", NULL); - clk_register_clkdev(clk1, "gmac_phy_synth_gate_clk", NULL); + clk = clk_register_aux("phy_syn_clk", "phy_syn_gclk", "phy_input_mclk", + 0, SPEAR1310_GMAC_CLK_SYNT, NULL, gmac_rtbl, + ARRAY_SIZE(gmac_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "phy_syn_clk", NULL); + clk_register_clkdev(clk1, "phy_syn_gclk", NULL); - clk = clk_register_mux(NULL, "gmac_phy_mux_clk", gmac_phy_parents, + clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents, ARRAY_SIZE(gmac_phy_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GMAC_PHY_CLK_SHIFT, SPEAR1310_GMAC_PHY_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "stmmacphy.0"); /* clcd */ - clk = clk_register_mux(NULL, "clcd_synth_mux_clk", clcd_synth_parents, + clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents, ARRAY_SIZE(clcd_synth_parents), 0, SPEAR1310_CLCD_CLK_SYNT, SPEAR1310_CLCD_SYNT_CLK_SHIFT, SPEAR1310_CLCD_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "clcd_synth_mux_clk", NULL); + clk_register_clkdev(clk, "clcd_syn_mclk", NULL); - clk = clk_register_frac("clcd_synth_clk", "clcd_synth_mux_clk", 0, + clk = clk_register_frac("clcd_syn_clk", "clcd_syn_mclk", 0, SPEAR1310_CLCD_CLK_SYNT, clcd_rtbl, ARRAY_SIZE(clcd_rtbl), &_lock); - clk_register_clkdev(clk, "clcd_synth_clk", NULL); + clk_register_clkdev(clk, "clcd_syn_clk", NULL); - clk = clk_register_mux(NULL, "clcd_pixel_mux_clk", clcd_pixel_parents, + clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents, ARRAY_SIZE(clcd_pixel_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_CLCD_CLK_SHIFT, SPEAR1310_CLCD_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "clcd_pixel_clk", NULL); - clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mux_clk", 0, + clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CLCD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "clcd_clk", NULL); /* i2s */ - clk = clk_register_mux(NULL, "i2s_src_mux_clk", i2s_src_parents, + clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents, ARRAY_SIZE(i2s_src_parents), 0, SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_SRC_CLK_SHIFT, SPEAR1310_I2S_SRC_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "i2s_src_clk", NULL); - clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mux_clk", 0, + clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0, SPEAR1310_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl, ARRAY_SIZE(i2s_prs1_rtbl), &_lock, NULL); clk_register_clkdev(clk, "i2s_prs1_clk", NULL); - clk = clk_register_mux(NULL, "i2s_ref_mux_clk", i2s_ref_parents, + clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents, ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_REF_SHIFT, SPEAR1310_I2S_REF_SEL_MASK, 0, &_lock); clk_register_clkdev(clk, "i2s_ref_clk", NULL); - clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mux_clk", 0, + clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0, SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_I2S_REF_PAD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "i2s_ref_pad_clk", NULL); - clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gate_clk", + clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gclk", "i2s_ref_pad_clk", 0, SPEAR1310_I2S_CLK_CFG, &i2s_sclk_masks, i2s_sclk_rtbl, ARRAY_SIZE(i2s_sclk_rtbl), &_lock, &clk1); clk_register_clkdev(clk, "i2s_sclk_clk", NULL); - clk_register_clkdev(clk1, "i2s_sclk_gate_clk", NULL); + clk_register_clkdev(clk1, "i2s_sclk_gclk", NULL); /* clock derived from ahb clk */ clk = clk_register_gate(NULL, "i2c0_clk", "ahb_clk", 0, @@ -747,13 +745,13 @@ void __init spear1310_clk_init(void) &_lock); clk_register_clkdev(clk, "sysram1_clk", NULL); - clk = clk_register_aux("adc_synth_clk", "adc_synth_gate_clk", "ahb_clk", + clk = clk_register_aux("adc_syn_clk", "adc_syn_gclk", "ahb_clk", 0, SPEAR1310_ADC_CLK_SYNT, NULL, adc_rtbl, ARRAY_SIZE(adc_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "adc_synth_clk", NULL); - clk_register_clkdev(clk1, "adc_synth_gate_clk", NULL); + clk_register_clkdev(clk, "adc_syn_clk", NULL); + clk_register_clkdev(clk1, "adc_syn_gclk", NULL); - clk = clk_register_gate(NULL, "adc_clk", "adc_synth_gate_clk", 0, + clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_ADC_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "adc_clk"); @@ -790,37 +788,37 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, NULL, "e0300000.kbd"); /* RAS clks */ - clk = clk_register_mux(NULL, "gen_synth0_1_mux_clk", - gen_synth0_1_parents, ARRAY_SIZE(gen_synth0_1_parents), - 0, SPEAR1310_PLL_CFG, SPEAR1310_RAS_SYNT0_1_CLK_SHIFT, + clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents, + ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1310_PLL_CFG, + SPEAR1310_RAS_SYNT0_1_CLK_SHIFT, SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gen_synth0_1_clk", NULL); + clk_register_clkdev(clk, "gen_syn0_1_clk", NULL); - clk = clk_register_mux(NULL, "gen_synth2_3_mux_clk", - gen_synth2_3_parents, ARRAY_SIZE(gen_synth2_3_parents), - 0, SPEAR1310_PLL_CFG, SPEAR1310_RAS_SYNT2_3_CLK_SHIFT, + clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents, + ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1310_PLL_CFG, + SPEAR1310_RAS_SYNT2_3_CLK_SHIFT, SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gen_synth2_3_clk", NULL); + clk_register_clkdev(clk, "gen_syn2_3_clk", NULL); - clk = clk_register_frac("gen_synth0_clk", "gen_synth0_1_clk", 0, + clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_clk", 0, SPEAR1310_RAS_CLK_SYNT0, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth0_clk", NULL); + clk_register_clkdev(clk, "gen_syn0_clk", NULL); - clk = clk_register_frac("gen_synth1_clk", "gen_synth0_1_clk", 0, + clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_clk", 0, SPEAR1310_RAS_CLK_SYNT1, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth1_clk", NULL); + clk_register_clkdev(clk, "gen_syn1_clk", NULL); - clk = clk_register_frac("gen_synth2_clk", "gen_synth2_3_clk", 0, + clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_clk", 0, SPEAR1310_RAS_CLK_SYNT2, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth2_clk", NULL); + clk_register_clkdev(clk, "gen_syn2_clk", NULL); - clk = clk_register_frac("gen_synth3_clk", "gen_synth2_3_clk", 0, + clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_clk", 0, SPEAR1310_RAS_CLK_SYNT3, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth3_clk", NULL); + clk_register_clkdev(clk, "gen_syn3_clk", NULL); clk = clk_register_gate(NULL, "ras_osc_24m_clk", "osc_24m_clk", 0, SPEAR1310_RAS_CLK_ENB, SPEAR1310_OSC_24M_CLK_ENB, 0, @@ -847,7 +845,7 @@ void __init spear1310_clk_init(void) &_lock); clk_register_clkdev(clk, "ras_pll3_clk", NULL); - clk = clk_register_gate(NULL, "ras_tx125_clk", "gmii_125m_pad_clk", 0, + clk = clk_register_gate(NULL, "ras_tx125_clk", "gmii_pad_clk", 0, SPEAR1310_RAS_CLK_ENB, SPEAR1310_C125M_PAD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "ras_tx125_clk", NULL); @@ -912,7 +910,7 @@ void __init spear1310_clk_init(void) &_lock); clk_register_clkdev(clk, NULL, "5c700000.eth"); - clk = clk_register_mux(NULL, "smii_rgmii_phy_mux_clk", + clk = clk_register_mux(NULL, "smii_rgmii_phy_mclk", smii_rgmii_phy_parents, ARRAY_SIZE(smii_rgmii_phy_parents), 0, SPEAR1310_RAS_CTRL_REG1, @@ -922,184 +920,184 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, NULL, "stmmacphy.2"); clk_register_clkdev(clk, NULL, "stmmacphy.4"); - clk = clk_register_mux(NULL, "rmii_phy_mux_clk", rmii_phy_parents, + clk = clk_register_mux(NULL, "rmii_phy_mclk", rmii_phy_parents, ARRAY_SIZE(rmii_phy_parents), 0, SPEAR1310_RAS_CTRL_REG1, SPEAR1310_RMII_PHY_CLK_SHIFT, SPEAR1310_PHY_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "stmmacphy.3"); - clk = clk_register_mux(NULL, "uart1_mux_clk", uart_parents, + clk = clk_register_mux(NULL, "uart1_mclk", uart_parents, ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART1_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart1_mux_clk", NULL); + clk_register_clkdev(clk, "uart1_mclk", NULL); - clk = clk_register_gate(NULL, "uart1_clk", "uart1_mux_clk", 0, + clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5c800000.serial"); - clk = clk_register_mux(NULL, "uart2_mux_clk", uart_parents, + clk = clk_register_mux(NULL, "uart2_mclk", uart_parents, ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART2_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart2_mux_clk", NULL); + clk_register_clkdev(clk, "uart2_mclk", NULL); - clk = clk_register_gate(NULL, "uart2_clk", "uart2_mux_clk", 0, + clk = clk_register_gate(NULL, "uart2_clk", "uart2_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5c900000.serial"); - clk = clk_register_mux(NULL, "uart3_mux_clk", uart_parents, + clk = clk_register_mux(NULL, "uart3_mclk", uart_parents, ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART3_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart3_mux_clk", NULL); + clk_register_clkdev(clk, "uart3_mclk", NULL); - clk = clk_register_gate(NULL, "uart3_clk", "uart3_mux_clk", 0, + clk = clk_register_gate(NULL, "uart3_clk", "uart3_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5ca00000.serial"); - clk = clk_register_mux(NULL, "uart4_mux_clk", uart_parents, + clk = clk_register_mux(NULL, "uart4_mclk", uart_parents, ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART4_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart4_mux_clk", NULL); + clk_register_clkdev(clk, "uart4_mclk", NULL); - clk = clk_register_gate(NULL, "uart4_clk", "uart4_mux_clk", 0, + clk = clk_register_gate(NULL, "uart4_clk", "uart4_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART4_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5cb00000.serial"); - clk = clk_register_mux(NULL, "uart5_mux_clk", uart_parents, + clk = clk_register_mux(NULL, "uart5_mclk", uart_parents, ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART5_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart5_mux_clk", NULL); + clk_register_clkdev(clk, "uart5_mclk", NULL); - clk = clk_register_gate(NULL, "uart5_clk", "uart5_mux_clk", 0, + clk = clk_register_gate(NULL, "uart5_clk", "uart5_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART5_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5cc00000.serial"); - clk = clk_register_mux(NULL, "i2c1_mux_clk", i2c_parents, + clk = clk_register_mux(NULL, "i2c1_mclk", i2c_parents, ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C1_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2c1_mux_clk", NULL); + clk_register_clkdev(clk, "i2c1_mclk", NULL); - clk = clk_register_gate(NULL, "i2c1_clk", "i2c1_mux_clk", 0, + clk = clk_register_gate(NULL, "i2c1_clk", "i2c1_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5cd00000.i2c"); - clk = clk_register_mux(NULL, "i2c2_mux_clk", i2c_parents, + clk = clk_register_mux(NULL, "i2c2_mclk", i2c_parents, ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C2_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2c2_mux_clk", NULL); + clk_register_clkdev(clk, "i2c2_mclk", NULL); - clk = clk_register_gate(NULL, "i2c2_clk", "i2c2_mux_clk", 0, + clk = clk_register_gate(NULL, "i2c2_clk", "i2c2_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5ce00000.i2c"); - clk = clk_register_mux(NULL, "i2c3_mux_clk", i2c_parents, + clk = clk_register_mux(NULL, "i2c3_mclk", i2c_parents, ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C3_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2c3_mux_clk", NULL); + clk_register_clkdev(clk, "i2c3_mclk", NULL); - clk = clk_register_gate(NULL, "i2c3_clk", "i2c3_mux_clk", 0, + clk = clk_register_gate(NULL, "i2c3_clk", "i2c3_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5cf00000.i2c"); - clk = clk_register_mux(NULL, "i2c4_mux_clk", i2c_parents, + clk = clk_register_mux(NULL, "i2c4_mclk", i2c_parents, ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C4_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2c4_mux_clk", NULL); + clk_register_clkdev(clk, "i2c4_mclk", NULL); - clk = clk_register_gate(NULL, "i2c4_clk", "i2c4_mux_clk", 0, + clk = clk_register_gate(NULL, "i2c4_clk", "i2c4_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C4_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5d000000.i2c"); - clk = clk_register_mux(NULL, "i2c5_mux_clk", i2c_parents, + clk = clk_register_mux(NULL, "i2c5_mclk", i2c_parents, ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C5_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2c5_mux_clk", NULL); + clk_register_clkdev(clk, "i2c5_mclk", NULL); - clk = clk_register_gate(NULL, "i2c5_clk", "i2c5_mux_clk", 0, + clk = clk_register_gate(NULL, "i2c5_clk", "i2c5_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C5_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5d100000.i2c"); - clk = clk_register_mux(NULL, "i2c6_mux_clk", i2c_parents, + clk = clk_register_mux(NULL, "i2c6_mclk", i2c_parents, ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C6_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2c6_mux_clk", NULL); + clk_register_clkdev(clk, "i2c6_mclk", NULL); - clk = clk_register_gate(NULL, "i2c6_clk", "i2c6_mux_clk", 0, + clk = clk_register_gate(NULL, "i2c6_clk", "i2c6_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C6_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5d200000.i2c"); - clk = clk_register_mux(NULL, "i2c7_mux_clk", i2c_parents, + clk = clk_register_mux(NULL, "i2c7_mclk", i2c_parents, ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C7_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2c7_mux_clk", NULL); + clk_register_clkdev(clk, "i2c7_mclk", NULL); - clk = clk_register_gate(NULL, "i2c7_clk", "i2c7_mux_clk", 0, + clk = clk_register_gate(NULL, "i2c7_clk", "i2c7_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C7_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5d300000.i2c"); - clk = clk_register_mux(NULL, "ssp1_mux_clk", ssp1_parents, + clk = clk_register_mux(NULL, "ssp1_mclk", ssp1_parents, ARRAY_SIZE(ssp1_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_SSP1_CLK_SHIFT, SPEAR1310_SSP1_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "ssp1_mux_clk", NULL); + clk_register_clkdev(clk, "ssp1_mclk", NULL); - clk = clk_register_gate(NULL, "ssp1_clk", "ssp1_mux_clk", 0, + clk = clk_register_gate(NULL, "ssp1_clk", "ssp1_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_SSP1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "5d400000.spi"); - clk = clk_register_mux(NULL, "pci_mux_clk", pci_parents, + clk = clk_register_mux(NULL, "pci_mclk", pci_parents, ARRAY_SIZE(pci_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_PCI_CLK_SHIFT, SPEAR1310_PCI_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "pci_mux_clk", NULL); + clk_register_clkdev(clk, "pci_mclk", NULL); - clk = clk_register_gate(NULL, "pci_clk", "pci_mux_clk", 0, + clk = clk_register_gate(NULL, "pci_clk", "pci_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_PCI_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "pci"); - clk = clk_register_mux(NULL, "tdm1_mux_clk", tdm_parents, + clk = clk_register_mux(NULL, "tdm1_mclk", tdm_parents, ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_TDM1_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "tdm1_mux_clk", NULL); + clk_register_clkdev(clk, "tdm1_mclk", NULL); - clk = clk_register_gate(NULL, "tdm1_clk", "tdm1_mux_clk", 0, + clk = clk_register_gate(NULL, "tdm1_clk", "tdm1_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_TDM1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "tdm_hdlc.0"); - clk = clk_register_mux(NULL, "tdm2_mux_clk", tdm_parents, + clk = clk_register_mux(NULL, "tdm2_mclk", tdm_parents, ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0, SPEAR1310_TDM2_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "tdm2_mux_clk", NULL); + clk_register_clkdev(clk, "tdm2_mclk", NULL); - clk = clk_register_gate(NULL, "tdm2_clk", "tdm2_mux_clk", 0, + clk = clk_register_gate(NULL, "tdm2_clk", "tdm2_mclk", 0, SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_TDM2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "tdm_hdlc.1"); diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c index e3ea7216223..2352cee7f64 100644 --- a/drivers/clk/spear/spear1340_clock.c +++ b/drivers/clk/spear/spear1340_clock.c @@ -369,27 +369,25 @@ static struct frac_rate_tbl gen_rtbl[] = { /* clock parents */ static const char *vco_parents[] = { "osc_24m_clk", "osc_25m_clk", }; -static const char *sys_parents[] = { "none", "pll1_clk", "none", "none", - "sys_synth_clk", "none", "pll2_clk", "pll3_clk", }; -static const char *ahb_parents[] = { "cpu_div3_clk", "amba_synth_clk", }; +static const char *sys_parents[] = { "pll1_clk", "pll1_clk", "pll1_clk", + "pll1_clk", "sys_synth_clk", "sys_synth_clk", "pll2_clk", "pll3_clk", }; +static const char *ahb_parents[] = { "cpu_div3_clk", "amba_syn_clk", }; static const char *gpt_parents[] = { "osc_24m_clk", "apb_clk", }; static const char *uart0_parents[] = { "pll5_clk", "osc_24m_clk", - "uart0_synth_gate_clk", }; + "uart0_syn_gclk", }; static const char *uart1_parents[] = { "pll5_clk", "osc_24m_clk", - "uart1_synth_gate_clk", }; -static const char *c3_parents[] = { "pll5_clk", "c3_synth_gate_clk", }; -static const char *gmac_phy_input_parents[] = { "gmii_125m_pad_clk", "pll2_clk", + "uart1_syn_gclk", }; +static const char *c3_parents[] = { "pll5_clk", "c3_syn_gclk", }; +static const char *gmac_phy_input_parents[] = { "gmii_pad_clk", "pll2_clk", "osc_25m_clk", }; -static const char *gmac_phy_parents[] = { "gmac_phy_input_mux_clk", - "gmac_phy_synth_gate_clk", }; +static const char *gmac_phy_parents[] = { "phy_input_mclk", "phy_syn_gclk", }; static const char *clcd_synth_parents[] = { "vco1div4_clk", "pll2_clk", }; -static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_synth_clk", }; +static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_syn_clk", }; static const char *i2s_src_parents[] = { "vco1div2_clk", "pll2_clk", "pll3_clk", "i2s_src_pad_clk", }; -static const char *i2s_ref_parents[] = { "i2s_src_mux_clk", "i2s_prs1_clk", }; -static const char *spdif_out_parents[] = { "i2s_src_pad_clk", "gen_synth2_clk", -}; -static const char *spdif_in_parents[] = { "pll2_clk", "gen_synth3_clk", }; +static const char *i2s_ref_parents[] = { "i2s_src_mclk", "i2s_prs1_clk", }; +static const char *spdif_out_parents[] = { "i2s_src_pad_clk", "gen_syn2_clk", }; +static const char *spdif_in_parents[] = { "pll2_clk", "gen_syn3_clk", }; static const char *gen_synth0_1_parents[] = { "vco1div4_clk", "vco3div2_clk", "pll3_clk", }; @@ -415,9 +413,9 @@ void __init spear1340_clk_init(void) 25000000); clk_register_clkdev(clk, "osc_25m_clk", NULL); - clk = clk_register_fixed_rate(NULL, "gmii_125m_pad_clk", NULL, - CLK_IS_ROOT, 125000000); - clk_register_clkdev(clk, "gmii_125m_pad_clk", NULL); + clk = clk_register_fixed_rate(NULL, "gmii_pad_clk", NULL, CLK_IS_ROOT, + 125000000); + clk_register_clkdev(clk, "gmii_pad_clk", NULL); clk = clk_register_fixed_rate(NULL, "i2s_src_pad_clk", NULL, CLK_IS_ROOT, 12288000); @@ -431,35 +429,35 @@ void __init spear1340_clk_init(void) /* clock derived from 24 or 25 MHz osc clk */ /* vco-pll */ - clk = clk_register_mux(NULL, "vco1_mux_clk", vco_parents, + clk = clk_register_mux(NULL, "vco1_mclk", vco_parents, ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG, SPEAR1340_PLL1_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "vco1_mux_clk", NULL); - clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mux_clk", - 0, SPEAR1340_PLL1_CTR, SPEAR1340_PLL1_FRQ, pll_rtbl, + clk_register_clkdev(clk, "vco1_mclk", NULL); + clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk", 0, + SPEAR1340_PLL1_CTR, SPEAR1340_PLL1_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); clk_register_clkdev(clk, "vco1_clk", NULL); clk_register_clkdev(clk1, "pll1_clk", NULL); - clk = clk_register_mux(NULL, "vco2_mux_clk", vco_parents, + clk = clk_register_mux(NULL, "vco2_mclk", vco_parents, ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG, SPEAR1340_PLL2_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "vco2_mux_clk", NULL); - clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mux_clk", - 0, SPEAR1340_PLL2_CTR, SPEAR1340_PLL2_FRQ, pll_rtbl, + clk_register_clkdev(clk, "vco2_mclk", NULL); + clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk", 0, + SPEAR1340_PLL2_CTR, SPEAR1340_PLL2_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); clk_register_clkdev(clk, "vco2_clk", NULL); clk_register_clkdev(clk1, "pll2_clk", NULL); - clk = clk_register_mux(NULL, "vco3_mux_clk", vco_parents, + clk = clk_register_mux(NULL, "vco3_mclk", vco_parents, ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG, SPEAR1340_PLL3_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "vco3_mux_clk", NULL); - clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mux_clk", - 0, SPEAR1340_PLL3_CTR, SPEAR1340_PLL3_FRQ, pll_rtbl, + clk_register_clkdev(clk, "vco3_mclk", NULL); + clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk", 0, + SPEAR1340_PLL3_CTR, SPEAR1340_PLL3_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); clk_register_clkdev(clk, "vco3_clk", NULL); clk_register_clkdev(clk1, "pll3_clk", NULL); @@ -498,7 +496,7 @@ void __init spear1340_clk_init(void) /* peripherals */ clk_register_fixed_factor(NULL, "thermal_clk", "osc_24m_clk", 0, 1, 128); - clk = clk_register_gate(NULL, "thermal_gate_clk", "thermal_clk", 0, + clk = clk_register_gate(NULL, "thermal_gclk", "thermal_clk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_THSENS_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_thermal"); @@ -509,23 +507,23 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, "ddr_clk", NULL); /* clock derived from pll1 clk */ - clk = clk_register_frac("sys_synth_clk", "vco1div2_clk", 0, + clk = clk_register_frac("sys_syn_clk", "vco1div2_clk", 0, SPEAR1340_SYS_CLK_SYNT, sys_synth_rtbl, ARRAY_SIZE(sys_synth_rtbl), &_lock); - clk_register_clkdev(clk, "sys_synth_clk", NULL); + clk_register_clkdev(clk, "sys_syn_clk", NULL); - clk = clk_register_frac("amba_synth_clk", "vco1div2_clk", 0, + clk = clk_register_frac("amba_syn_clk", "vco1div2_clk", 0, SPEAR1340_AMBA_CLK_SYNT, amba_synth_rtbl, ARRAY_SIZE(amba_synth_rtbl), &_lock); - clk_register_clkdev(clk, "amba_synth_clk", NULL); + clk_register_clkdev(clk, "amba_syn_clk", NULL); - clk = clk_register_mux(NULL, "sys_mux_clk", sys_parents, + clk = clk_register_mux(NULL, "sys_mclk", sys_parents, ARRAY_SIZE(sys_parents), 0, SPEAR1340_SYS_CLK_CTRL, SPEAR1340_SCLK_SRC_SEL_SHIFT, SPEAR1340_SCLK_SRC_SEL_MASK, 0, &_lock); clk_register_clkdev(clk, "sys_clk", NULL); - clk = clk_register_fixed_factor(NULL, "cpu_clk", "sys_mux_clk", 0, 1, + clk = clk_register_fixed_factor(NULL, "cpu_clk", "sys_mclk", 0, 1, 2); clk_register_clkdev(clk, "cpu_clk", NULL); @@ -548,194 +546,193 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, "apb_clk", NULL); /* gpt clocks */ - clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT0_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt0_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mux_clk", 0, + clk_register_clkdev(clk, "gpt0_mclk", NULL); + clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt0"); - clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT1_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt1_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, + clk_register_clkdev(clk, "gpt1_mclk", NULL); + clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt1"); - clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT2_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt2_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, + clk_register_clkdev(clk, "gpt2_mclk", NULL); + clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt2"); - clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt_parents, + clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents, ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT3_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt3_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0, + clk_register_clkdev(clk, "gpt3_mclk", NULL); + clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt3"); /* others */ - clk = clk_register_aux("uart0_synth_clk", "uart0_synth_gate_clk", + clk = clk_register_aux("uart0_syn_clk", "uart0_syn_gclk", "vco1div2_clk", 0, SPEAR1340_UART0_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "uart0_synth_clk", NULL); - clk_register_clkdev(clk1, "uart0_synth_gate_clk", NULL); + clk_register_clkdev(clk, "uart0_syn_clk", NULL); + clk_register_clkdev(clk1, "uart0_syn_gclk", NULL); - clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents, + clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents, ARRAY_SIZE(uart0_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART0_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart0_mux_clk", NULL); + clk_register_clkdev(clk, "uart0_mclk", NULL); - clk = clk_register_gate(NULL, "uart0_clk", "uart0_mux_clk", 0, + clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UART0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "e0000000.serial"); - clk = clk_register_aux("uart1_synth_clk", "uart1_synth_gate_clk", + clk = clk_register_aux("uart1_syn_clk", "uart1_syn_gclk", "vco1div2_clk", 0, SPEAR1340_UART1_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "uart1_synth_clk", NULL); - clk_register_clkdev(clk1, "uart1_synth_gate_clk", NULL); + clk_register_clkdev(clk, "uart1_syn_clk", NULL); + clk_register_clkdev(clk1, "uart1_syn_gclk", NULL); - clk = clk_register_mux(NULL, "uart1_mux_clk", uart1_parents, + clk = clk_register_mux(NULL, "uart1_mclk", uart1_parents, ARRAY_SIZE(uart1_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART1_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart1_mux_clk", NULL); + clk_register_clkdev(clk, "uart1_mclk", NULL); - clk = clk_register_gate(NULL, "uart1_clk", "uart1_mux_clk", 0, - SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UART1_CLK_ENB, 0, + clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0, + SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_UART1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b4100000.serial"); - clk = clk_register_aux("sdhci_synth_clk", "sdhci_synth_gate_clk", + clk = clk_register_aux("sdhci_syn_clk", "sdhci_syn_gclk", "vco1div2_clk", 0, SPEAR1340_SDHCI_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "sdhci_synth_clk", NULL); - clk_register_clkdev(clk1, "sdhci_synth_gate_clk", NULL); + clk_register_clkdev(clk, "sdhci_syn_clk", NULL); + clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL); - clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_synth_gate_clk", 0, + clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SDHCI_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b3000000.sdhci"); - clk = clk_register_aux("cfxd_synth_clk", "cfxd_synth_gate_clk", - "vco1div2_clk", 0, SPEAR1340_CFXD_CLK_SYNT, NULL, - aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "cfxd_synth_clk", NULL); - clk_register_clkdev(clk1, "cfxd_synth_gate_clk", NULL); + clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk", + 0, SPEAR1340_CFXD_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "cfxd_syn_clk", NULL); + clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL); - clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_synth_gate_clk", 0, + clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CFXD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b2800000.cf"); clk_register_clkdev(clk, NULL, "arasan_xd"); - clk = clk_register_aux("c3_synth_clk", "c3_synth_gate_clk", - "vco1div2_clk", 0, SPEAR1340_C3_CLK_SYNT, NULL, - aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "c3_synth_clk", NULL); - clk_register_clkdev(clk1, "c3_synth_gate_clk", NULL); + clk = clk_register_aux("c3_syn_clk", "c3_syn_gclk", "vco1div2_clk", 0, + SPEAR1340_C3_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "c3_syn_clk", NULL); + clk_register_clkdev(clk1, "c3_syn_gclk", NULL); - clk = clk_register_mux(NULL, "c3_mux_clk", c3_parents, + clk = clk_register_mux(NULL, "c3_mclk", c3_parents, ARRAY_SIZE(c3_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_C3_CLK_SHIFT, SPEAR1340_C3_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "c3_mux_clk", NULL); + clk_register_clkdev(clk, "c3_mclk", NULL); - clk = clk_register_gate(NULL, "c3_clk", "c3_mux_clk", 0, + clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_C3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "c3"); /* gmac */ - clk = clk_register_mux(NULL, "gmac_phy_input_mux_clk", - gmac_phy_input_parents, + clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents, ARRAY_SIZE(gmac_phy_input_parents), 0, SPEAR1340_GMAC_CLK_CFG, SPEAR1340_GMAC_PHY_INPUT_CLK_SHIFT, SPEAR1340_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gmac_phy_input_mux_clk", NULL); + clk_register_clkdev(clk, "phy_input_mclk", NULL); - clk = clk_register_aux("gmac_phy_synth_clk", "gmac_phy_synth_gate_clk", - "gmac_phy_input_mux_clk", 0, SPEAR1340_GMAC_CLK_SYNT, - NULL, gmac_rtbl, ARRAY_SIZE(gmac_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "gmac_phy_synth_clk", NULL); - clk_register_clkdev(clk1, "gmac_phy_synth_gate_clk", NULL); + clk = clk_register_aux("phy_syn_clk", "phy_syn_gclk", "phy_input_mclk", + 0, SPEAR1340_GMAC_CLK_SYNT, NULL, gmac_rtbl, + ARRAY_SIZE(gmac_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "phy_syn_clk", NULL); + clk_register_clkdev(clk1, "phy_syn_gclk", NULL); - clk = clk_register_mux(NULL, "gmac_phy_mux_clk", gmac_phy_parents, + clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents, ARRAY_SIZE(gmac_phy_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GMAC_PHY_CLK_SHIFT, SPEAR1340_GMAC_PHY_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "stmmacphy.0"); /* clcd */ - clk = clk_register_mux(NULL, "clcd_synth_mux_clk", clcd_synth_parents, + clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents, ARRAY_SIZE(clcd_synth_parents), 0, SPEAR1340_CLCD_CLK_SYNT, SPEAR1340_CLCD_SYNT_CLK_SHIFT, SPEAR1340_CLCD_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "clcd_synth_mux_clk", NULL); + clk_register_clkdev(clk, "clcd_syn_mclk", NULL); - clk = clk_register_frac("clcd_synth_clk", "clcd_synth_mux_clk", 0, + clk = clk_register_frac("clcd_syn_clk", "clcd_syn_mclk", 0, SPEAR1340_CLCD_CLK_SYNT, clcd_rtbl, ARRAY_SIZE(clcd_rtbl), &_lock); - clk_register_clkdev(clk, "clcd_synth_clk", NULL); + clk_register_clkdev(clk, "clcd_syn_clk", NULL); - clk = clk_register_mux(NULL, "clcd_pixel_mux_clk", clcd_pixel_parents, + clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents, ARRAY_SIZE(clcd_pixel_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_CLCD_CLK_SHIFT, SPEAR1340_CLCD_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "clcd_pixel_clk", NULL); - clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mux_clk", 0, + clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CLCD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "clcd_clk", NULL); /* i2s */ - clk = clk_register_mux(NULL, "i2s_src_mux_clk", i2s_src_parents, + clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents, ARRAY_SIZE(i2s_src_parents), 0, SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_SRC_CLK_SHIFT, SPEAR1340_I2S_SRC_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "i2s_src_clk", NULL); - clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mux_clk", 0, + clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0, SPEAR1340_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl, ARRAY_SIZE(i2s_prs1_rtbl), &_lock, NULL); clk_register_clkdev(clk, "i2s_prs1_clk", NULL); - clk = clk_register_mux(NULL, "i2s_ref_mux_clk", i2s_ref_parents, + clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents, ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_REF_SHIFT, SPEAR1340_I2S_REF_SEL_MASK, 0, &_lock); clk_register_clkdev(clk, "i2s_ref_clk", NULL); - clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mux_clk", 0, + clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_I2S_REF_PAD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "i2s_ref_pad_clk", NULL); - clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gate_clk", - "i2s_ref_mux_clk", 0, SPEAR1340_I2S_CLK_CFG, - &i2s_sclk_masks, i2s_sclk_rtbl, - ARRAY_SIZE(i2s_sclk_rtbl), &_lock, &clk1); + clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gclk", "i2s_ref_mclk", + 0, SPEAR1340_I2S_CLK_CFG, &i2s_sclk_masks, + i2s_sclk_rtbl, ARRAY_SIZE(i2s_sclk_rtbl), &_lock, + &clk1); clk_register_clkdev(clk, "i2s_sclk_clk", NULL); - clk_register_clkdev(clk1, "i2s_sclk_gate_clk", NULL); + clk_register_clkdev(clk1, "i2s_sclk_gclk", NULL); /* clock derived from ahb clk */ clk = clk_register_gate(NULL, "i2c0_clk", "ahb_clk", 0, @@ -744,7 +741,7 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, NULL, "e0280000.i2c"); clk = clk_register_gate(NULL, "i2c1_clk", "ahb_clk", 0, - SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2C1_CLK_ENB, 0, + SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_I2C1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b4000000.i2c"); @@ -800,13 +797,13 @@ void __init spear1340_clk_init(void) &_lock); clk_register_clkdev(clk, "sysram1_clk", NULL); - clk = clk_register_aux("adc_synth_clk", "adc_synth_gate_clk", "ahb_clk", + clk = clk_register_aux("adc_syn_clk", "adc_syn_gclk", "ahb_clk", 0, SPEAR1340_ADC_CLK_SYNT, NULL, adc_rtbl, ARRAY_SIZE(adc_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "adc_synth_clk", NULL); - clk_register_clkdev(clk1, "adc_synth_gate_clk", NULL); + clk_register_clkdev(clk, "adc_syn_clk", NULL); + clk_register_clkdev(clk1, "adc_syn_gclk", NULL); - clk = clk_register_gate(NULL, "adc_clk", "adc_synth_gate_clk", 0, + clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_ADC_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "adc_clk"); @@ -843,39 +840,39 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, NULL, "e0300000.kbd"); /* RAS clks */ - clk = clk_register_mux(NULL, "gen_synth0_1_mux_clk", - gen_synth0_1_parents, ARRAY_SIZE(gen_synth0_1_parents), - 0, SPEAR1340_PLL_CFG, SPEAR1340_GEN_SYNT0_1_CLK_SHIFT, + clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents, + ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1340_PLL_CFG, + SPEAR1340_GEN_SYNT0_1_CLK_SHIFT, SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gen_synth0_1_clk", NULL); + clk_register_clkdev(clk, "gen_syn0_1_clk", NULL); - clk = clk_register_mux(NULL, "gen_synth2_3_mux_clk", - gen_synth2_3_parents, ARRAY_SIZE(gen_synth2_3_parents), - 0, SPEAR1340_PLL_CFG, SPEAR1340_GEN_SYNT2_3_CLK_SHIFT, + clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents, + ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1340_PLL_CFG, + SPEAR1340_GEN_SYNT2_3_CLK_SHIFT, SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gen_synth2_3_clk", NULL); + clk_register_clkdev(clk, "gen_syn2_3_clk", NULL); - clk = clk_register_frac("gen_synth0_clk", "gen_synth0_1_clk", 0, + clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_clk", 0, SPEAR1340_GEN_CLK_SYNT0, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth0_clk", NULL); + clk_register_clkdev(clk, "gen_syn0_clk", NULL); - clk = clk_register_frac("gen_synth1_clk", "gen_synth0_1_clk", 0, + clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_clk", 0, SPEAR1340_GEN_CLK_SYNT1, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth1_clk", NULL); + clk_register_clkdev(clk, "gen_syn1_clk", NULL); - clk = clk_register_frac("gen_synth2_clk", "gen_synth2_3_clk", 0, + clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_clk", 0, SPEAR1340_GEN_CLK_SYNT2, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth2_clk", NULL); + clk_register_clkdev(clk, "gen_syn2_clk", NULL); - clk = clk_register_frac("gen_synth3_clk", "gen_synth2_3_clk", 0, + clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_clk", 0, SPEAR1340_GEN_CLK_SYNT3, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); - clk_register_clkdev(clk, "gen_synth3_clk", NULL); + clk_register_clkdev(clk, "gen_syn3_clk", NULL); - clk = clk_register_gate(NULL, "mali_clk", "gen_synth3_clk", 0, + clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_MALI_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "mali"); @@ -890,74 +887,74 @@ void __init spear1340_clk_init(void) &_lock); clk_register_clkdev(clk, NULL, "spear_cec.1"); - clk = clk_register_mux(NULL, "spdif_out_mux_clk", spdif_out_parents, + clk = clk_register_mux(NULL, "spdif_out_mclk", spdif_out_parents, ARRAY_SIZE(spdif_out_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_OUT_CLK_SHIFT, SPEAR1340_SPDIF_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "spdif_out_mux_clk", NULL); + clk_register_clkdev(clk, "spdif_out_mclk", NULL); - clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mux_clk", 0, + clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_OUT_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spdif-out"); - clk = clk_register_mux(NULL, "spdif_in_mux_clk", spdif_in_parents, + clk = clk_register_mux(NULL, "spdif_in_mclk", spdif_in_parents, ARRAY_SIZE(spdif_in_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_IN_CLK_SHIFT, SPEAR1340_SPDIF_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "spdif_in_mux_clk", NULL); + clk_register_clkdev(clk, "spdif_in_mclk", NULL); - clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mux_clk", 0, + clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_IN_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spdif-in"); - clk = clk_register_gate(NULL, "acp_clk", "acp_mux_clk", 0, + clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "acp_clk"); - clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mux_clk", 0, + clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "plgpio"); - clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mux_clk", 0, + clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "video_dec"); - clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mux_clk", 0, + clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_ENC_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "video_enc"); - clk = clk_register_gate(NULL, "video_in_clk", "video_in_mux_clk", 0, + clk = clk_register_gate(NULL, "video_in_clk", "video_in_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_IN_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_vip"); - clk = clk_register_gate(NULL, "cam0_clk", "cam0_mux_clk", 0, + clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_camif.0"); - clk = clk_register_gate(NULL, "cam1_clk", "cam1_mux_clk", 0, + clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_camif.1"); - clk = clk_register_gate(NULL, "cam2_clk", "cam2_mux_clk", 0, + clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_camif.2"); - clk = clk_register_gate(NULL, "cam3_clk", "cam3_mux_clk", 0, + clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_camif.3"); - clk = clk_register_gate(NULL, "pwm_clk", "pwm_mux_clk", 0, + clk = clk_register_gate(NULL, "pwm_clk", "pwm_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PWM_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "pwm"); diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c index 01dd6daff2a..c3157454bb3 100644 --- a/drivers/clk/spear/spear3xx_clock.c +++ b/drivers/clk/spear/spear3xx_clock.c @@ -122,12 +122,12 @@ static struct gpt_rate_tbl gpt_rtbl[] = { }; /* clock parents */ -static const char *uart0_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; -static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", +static const char *uart0_parents[] = { "pll3_clk", "uart_syn_gclk", }; +static const char *firda_parents[] = { "pll3_clk", "firda_syn_gclk", }; -static const char *gpt0_parents[] = { "pll3_48m_clk", "gpt0_synth_clk", }; -static const char *gpt1_parents[] = { "pll3_48m_clk", "gpt1_synth_clk", }; -static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; +static const char *gpt0_parents[] = { "pll3_clk", "gpt0_syn_clk", }; +static const char *gpt1_parents[] = { "pll3_clk", "gpt1_syn_clk", }; +static const char *gpt2_parents[] = { "pll3_clk", "gpt2_syn_clk", }; static const char *gen2_3_parents[] = { "pll1_clk", "pll2_clk", }; static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", "pll2_clk", }; @@ -137,7 +137,7 @@ static void __init spear300_clk_init(void) { struct clk *clk; - clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, + clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_clk", 0, 1, 1); clk_register_clkdev(clk, NULL, "60000000.clcd"); @@ -219,15 +219,11 @@ static void __init spear310_clk_init(void) #define SPEAR320_UARTX_PCLK_VAL_SYNTH1 0x0 #define SPEAR320_UARTX_PCLK_VAL_APB 0x1 -static const char *i2s_ref_parents[] = { "ras_pll2_clk", - "ras_gen2_synth_gate_clk", }; -static const char *sdhci_parents[] = { "ras_pll3_48m_clk", - "ras_gen3_synth_gate_clk", -}; +static const char *i2s_ref_parents[] = { "ras_pll2_clk", "ras_syn2_gclk", }; +static const char *sdhci_parents[] = { "ras_pll3_clk", "ras_syn3_gclk", }; static const char *smii0_parents[] = { "smii_125m_pad", "ras_pll2_clk", - "ras_gen0_synth_gate_clk", }; -static const char *uartx_parents[] = { "ras_gen1_synth_gate_clk", "ras_apb_clk", -}; + "ras_syn0_gclk", }; +static const char *uartx_parents[] = { "ras_syn1_gclk", "ras_apb_clk", }; static void __init spear320_clk_init(void) { @@ -237,7 +233,7 @@ static void __init spear320_clk_init(void) CLK_IS_ROOT, 125000000); clk_register_clkdev(clk, "smii_125m_pad", NULL); - clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, + clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_clk", 0, 1, 1); clk_register_clkdev(clk, NULL, "90000000.clcd"); @@ -363,9 +359,9 @@ void __init spear3xx_clk_init(void) clk_register_clkdev(clk, NULL, "fc900000.rtc"); /* clock derived from 24 MHz osc clk */ - clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, + clk = clk_register_fixed_rate(NULL, "pll3_clk", "osc_24m_clk", 0, 48000000); - clk_register_clkdev(clk, "pll3_48m_clk", NULL); + clk_register_clkdev(clk, "pll3_clk", NULL); clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_24m_clk", 0, 1, 1); @@ -392,98 +388,98 @@ void __init spear3xx_clk_init(void) HCLK_RATIO_MASK, 0, &_lock); clk_register_clkdev(clk, "ahb_clk", NULL); - clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", - "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, - ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "uart_synth_clk", NULL); - clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); + clk = clk_register_aux("uart_syn_clk", "uart_syn_gclk", "pll1_clk", 0, + UART_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), + &_lock, &clk1); + clk_register_clkdev(clk, "uart_syn_clk", NULL); + clk_register_clkdev(clk1, "uart_syn_gclk", NULL); - clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents, + clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents, ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart0_mux_clk", NULL); + clk_register_clkdev(clk, "uart0_mclk", NULL); - clk = clk_register_gate(NULL, "uart0", "uart0_mux_clk", 0, - PERIP1_CLK_ENB, UART_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "uart0", "uart0_mclk", 0, PERIP1_CLK_ENB, + UART_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0000000.serial"); - clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", - "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, - ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "firda_synth_clk", NULL); - clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); + clk = clk_register_aux("firda_syn_clk", "firda_syn_gclk", "pll1_clk", 0, + FIRDA_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), + &_lock, &clk1); + clk_register_clkdev(clk, "firda_syn_clk", NULL); + clk_register_clkdev(clk1, "firda_syn_gclk", NULL); - clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, + clk = clk_register_mux(NULL, "firda_mclk", firda_parents, ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "firda_mux_clk", NULL); + clk_register_clkdev(clk, "firda_mclk", NULL); - clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, + clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0, PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "firda"); /* gpt clocks */ - clk_register_gpt("gpt0_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, - gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); + clk_register_gpt("gpt0_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl, + ARRAY_SIZE(gpt_rtbl), &_lock); clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents, ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt0"); - clk_register_gpt("gpt1_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, - gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); - clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt1_parents, + clk_register_gpt("gpt1_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl, + ARRAY_SIZE(gpt_rtbl), &_lock); + clk = clk_register_mux(NULL, "gpt1_mclk", gpt1_parents, ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt1_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, + clk_register_clkdev(clk, "gpt1_mclk", NULL); + clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0, PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt1"); - clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, - gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); - clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, + clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl, + ARRAY_SIZE(gpt_rtbl), &_lock); + clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents, ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt2_mux_clk", NULL); - clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, + clk_register_clkdev(clk, "gpt2_mclk", NULL); + clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0, PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt2"); /* general synths clocks */ - clk = clk_register_aux("gen0_synth_clk", "gen0_synth_gate_clk", - "pll1_clk", 0, GEN0_CLK_SYNT, NULL, aux_rtbl, - ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "gen0_synth_clk", NULL); - clk_register_clkdev(clk1, "gen0_synth_gate_clk", NULL); - - clk = clk_register_aux("gen1_synth_clk", "gen1_synth_gate_clk", - "pll1_clk", 0, GEN1_CLK_SYNT, NULL, aux_rtbl, - ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "gen1_synth_clk", NULL); - clk_register_clkdev(clk1, "gen1_synth_gate_clk", NULL); - - clk = clk_register_mux(NULL, "gen2_3_parent_clk", gen2_3_parents, + clk = clk_register_aux("gen0_syn_clk", "gen0_syn_gclk", "pll1_clk", + 0, GEN0_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), + &_lock, &clk1); + clk_register_clkdev(clk, "gen0_syn_clk", NULL); + clk_register_clkdev(clk1, "gen0_syn_gclk", NULL); + + clk = clk_register_aux("gen1_syn_clk", "gen1_syn_gclk", "pll1_clk", + 0, GEN1_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), + &_lock, &clk1); + clk_register_clkdev(clk, "gen1_syn_clk", NULL); + clk_register_clkdev(clk1, "gen1_syn_gclk", NULL); + + clk = clk_register_mux(NULL, "gen2_3_par_clk", gen2_3_parents, ARRAY_SIZE(gen2_3_parents), 0, CORE_CLK_CFG, GEN_SYNTH2_3_CLK_SHIFT, GEN_SYNTH2_3_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gen2_3_parent_clk", NULL); + clk_register_clkdev(clk, "gen2_3_par_clk", NULL); - clk = clk_register_aux("gen2_synth_clk", "gen2_synth_gate_clk", - "gen2_3_parent_clk", 0, GEN2_CLK_SYNT, NULL, aux_rtbl, + clk = clk_register_aux("gen2_syn_clk", "gen2_syn_gclk", + "gen2_3_par_clk", 0, GEN2_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "gen2_synth_clk", NULL); - clk_register_clkdev(clk1, "gen2_synth_gate_clk", NULL); + clk_register_clkdev(clk, "gen2_syn_clk", NULL); + clk_register_clkdev(clk1, "gen2_syn_gclk", NULL); - clk = clk_register_aux("gen3_synth_clk", "gen3_synth_gate_clk", - "gen2_3_parent_clk", 0, GEN3_CLK_SYNT, NULL, aux_rtbl, + clk = clk_register_aux("gen3_syn_clk", "gen3_syn_gclk", + "gen2_3_par_clk", 0, GEN3_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "gen3_synth_clk", NULL); - clk_register_clkdev(clk1, "gen3_synth_gate_clk", NULL); + clk_register_clkdev(clk, "gen3_syn_clk", NULL); + clk_register_clkdev(clk1, "gen3_syn_gclk", NULL); /* clock derived from pll3 clk */ - clk = clk_register_gate(NULL, "usbh_clk", "pll3_48m_clk", 0, - PERIP1_CLK_ENB, USBH_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "usbh_clk", "pll3_clk", 0, PERIP1_CLK_ENB, + USBH_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "usbh_clk", NULL); clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1, @@ -494,8 +490,8 @@ void __init spear3xx_clk_init(void) 1); clk_register_clkdev(clk, "usbh.1_clk", NULL); - clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, - PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB, + USBD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "designware_udc"); /* clock derived from ahb clk */ @@ -579,29 +575,25 @@ void __init spear3xx_clk_init(void) RAS_CLK_ENB, RAS_PLL2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "ras_pll2_clk", NULL); - clk = clk_register_gate(NULL, "ras_pll3_48m_clk", "pll3_48m_clk", 0, + clk = clk_register_gate(NULL, "ras_pll3_clk", "pll3_clk", 0, RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "ras_pll3_48m_clk", NULL); - - clk = clk_register_gate(NULL, "ras_gen0_synth_gate_clk", - "gen0_synth_gate_clk", 0, RAS_CLK_ENB, - RAS_SYNT0_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "ras_gen0_synth_gate_clk", NULL); - - clk = clk_register_gate(NULL, "ras_gen1_synth_gate_clk", - "gen1_synth_gate_clk", 0, RAS_CLK_ENB, - RAS_SYNT1_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "ras_gen1_synth_gate_clk", NULL); - - clk = clk_register_gate(NULL, "ras_gen2_synth_gate_clk", - "gen2_synth_gate_clk", 0, RAS_CLK_ENB, - RAS_SYNT2_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "ras_gen2_synth_gate_clk", NULL); - - clk = clk_register_gate(NULL, "ras_gen3_synth_gate_clk", - "gen3_synth_gate_clk", 0, RAS_CLK_ENB, - RAS_SYNT3_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "ras_gen3_synth_gate_clk", NULL); + clk_register_clkdev(clk, "ras_pll3_clk", NULL); + + clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk", 0, + RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_syn0_gclk", NULL); + + clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk", 0, + RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_syn1_gclk", NULL); + + clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk", 0, + RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_syn2_gclk", NULL); + + clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk", 0, + RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_syn3_gclk", NULL); if (of_machine_is_compatible("st,spear300")) spear300_clk_init(); diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c index 61026ae564a..a98d0866f54 100644 --- a/drivers/clk/spear/spear6xx_clock.c +++ b/drivers/clk/spear/spear6xx_clock.c @@ -97,13 +97,12 @@ static struct aux_rate_tbl aux_rtbl[] = { {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ }; -static const char *clcd_parents[] = { "pll3_48m_clk", "clcd_synth_gate_clk", }; -static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", -}; -static const char *uart_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; -static const char *gpt0_1_parents[] = { "pll3_48m_clk", "gpt0_1_synth_clk", }; -static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; -static const char *gpt3_parents[] = { "pll3_48m_clk", "gpt3_synth_clk", }; +static const char *clcd_parents[] = { "pll3_clk", "clcd_syn_gclk", }; +static const char *firda_parents[] = { "pll3_clk", "firda_syn_gclk", }; +static const char *uart_parents[] = { "pll3_clk", "uart_syn_gclk", }; +static const char *gpt0_1_parents[] = { "pll3_clk", "gpt0_1_syn_clk", }; +static const char *gpt2_parents[] = { "pll3_clk", "gpt2_syn_clk", }; +static const char *gpt3_parents[] = { "pll3_clk", "gpt3_syn_clk", }; static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", "pll2_clk", }; @@ -136,9 +135,9 @@ void __init spear6xx_clk_init(void) clk_register_clkdev(clk, NULL, "rtc-spear"); /* clock derived from 30 MHz osc clk */ - clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, + clk = clk_register_fixed_rate(NULL, "pll3_clk", "osc_24m_clk", 0, 48000000); - clk_register_clkdev(clk, "pll3_48m_clk", NULL); + clk_register_clkdev(clk, "pll3_clk", NULL); clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "osc_30m_clk", 0, PLL1_CTR, PLL1_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), @@ -146,9 +145,9 @@ void __init spear6xx_clk_init(void) clk_register_clkdev(clk, "vco1_clk", NULL); clk_register_clkdev(clk1, "pll1_clk", NULL); - clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, - "osc_30m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, - ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); + clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "osc_30m_clk", + 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), + &_lock, &clk1, NULL); clk_register_clkdev(clk, "vco2_clk", NULL); clk_register_clkdev(clk1, "pll2_clk", NULL); @@ -165,111 +164,111 @@ void __init spear6xx_clk_init(void) HCLK_RATIO_MASK, 0, &_lock); clk_register_clkdev(clk, "ahb_clk", NULL); - clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", - "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, - ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "uart_synth_clk", NULL); - clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); + clk = clk_register_aux("uart_syn_clk", "uart_syn_gclk", "pll1_clk", 0, + UART_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), + &_lock, &clk1); + clk_register_clkdev(clk, "uart_syn_clk", NULL); + clk_register_clkdev(clk1, "uart_syn_gclk", NULL); - clk = clk_register_mux(NULL, "uart_mux_clk", uart_parents, + clk = clk_register_mux(NULL, "uart_mclk", uart_parents, ARRAY_SIZE(uart_parents), 0, PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "uart_mux_clk", NULL); + clk_register_clkdev(clk, "uart_mclk", NULL); - clk = clk_register_gate(NULL, "uart0", "uart_mux_clk", 0, - PERIP1_CLK_ENB, UART0_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "uart0", "uart_mclk", 0, PERIP1_CLK_ENB, + UART0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0000000.serial"); - clk = clk_register_gate(NULL, "uart1", "uart_mux_clk", 0, - PERIP1_CLK_ENB, UART1_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "uart1", "uart_mclk", 0, PERIP1_CLK_ENB, + UART1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0080000.serial"); - clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", - "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, - ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "firda_synth_clk", NULL); - clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); + clk = clk_register_aux("firda_syn_clk", "firda_syn_gclk", "pll1_clk", + 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), + &_lock, &clk1); + clk_register_clkdev(clk, "firda_syn_clk", NULL); + clk_register_clkdev(clk1, "firda_syn_gclk", NULL); - clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, + clk = clk_register_mux(NULL, "firda_mclk", firda_parents, ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "firda_mux_clk", NULL); + clk_register_clkdev(clk, "firda_mclk", NULL); - clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, + clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0, PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "firda"); - clk = clk_register_aux("clcd_synth_clk", "clcd_synth_gate_clk", - "pll1_clk", 0, CLCD_CLK_SYNT, NULL, aux_rtbl, - ARRAY_SIZE(aux_rtbl), &_lock, &clk1); - clk_register_clkdev(clk, "clcd_synth_clk", NULL); - clk_register_clkdev(clk1, "clcd_synth_gate_clk", NULL); + clk = clk_register_aux("clcd_syn_clk", "clcd_syn_gclk", "pll1_clk", + 0, CLCD_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl), + &_lock, &clk1); + clk_register_clkdev(clk, "clcd_syn_clk", NULL); + clk_register_clkdev(clk1, "clcd_syn_gclk", NULL); - clk = clk_register_mux(NULL, "clcd_mux_clk", clcd_parents, + clk = clk_register_mux(NULL, "clcd_mclk", clcd_parents, ARRAY_SIZE(clcd_parents), 0, PERIP_CLK_CFG, CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "clcd_mux_clk", NULL); + clk_register_clkdev(clk, "clcd_mclk", NULL); - clk = clk_register_gate(NULL, "clcd_clk", "clcd_mux_clk", 0, + clk = clk_register_gate(NULL, "clcd_clk", "clcd_mclk", 0, PERIP1_CLK_ENB, CLCD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "clcd"); /* gpt clocks */ - clk = clk_register_gpt("gpt0_1_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, + clk = clk_register_gpt("gpt0_1_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); - clk_register_clkdev(clk, "gpt0_1_synth_clk", NULL); + clk_register_clkdev(clk, "gpt0_1_syn_clk", NULL); - clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt0_1_parents, + clk = clk_register_mux(NULL, "gpt0_mclk", gpt0_1_parents, ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt0"); - clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt0_1_parents, + clk = clk_register_mux(NULL, "gpt1_mclk", gpt0_1_parents, ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt1_mux_clk", NULL); + clk_register_clkdev(clk, "gpt1_mclk", NULL); - clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, + clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0, PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt1"); - clk = clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, + clk = clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); - clk_register_clkdev(clk, "gpt2_synth_clk", NULL); + clk_register_clkdev(clk, "gpt2_syn_clk", NULL); - clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, + clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents, ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt2_mux_clk", NULL); + clk_register_clkdev(clk, "gpt2_mclk", NULL); - clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, + clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0, PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt2"); - clk = clk_register_gpt("gpt3_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, + clk = clk_register_gpt("gpt3_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); - clk_register_clkdev(clk, "gpt3_synth_clk", NULL); + clk_register_clkdev(clk, "gpt3_syn_clk", NULL); - clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt3_parents, + clk = clk_register_mux(NULL, "gpt3_mclk", gpt3_parents, ARRAY_SIZE(gpt3_parents), 0, PERIP_CLK_CFG, GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gpt3_mux_clk", NULL); + clk_register_clkdev(clk, "gpt3_mclk", NULL); - clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0, + clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0, PERIP1_CLK_ENB, GPT3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt3"); /* clock derived from pll3 clk */ - clk = clk_register_gate(NULL, "usbh0_clk", "pll3_48m_clk", 0, + clk = clk_register_gate(NULL, "usbh0_clk", "pll3_clk", 0, PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "usbh.0_clk"); - clk = clk_register_gate(NULL, "usbh1_clk", "pll3_48m_clk", 0, + clk = clk_register_gate(NULL, "usbh1_clk", "pll3_clk", 0, PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "usbh.1_clk"); - clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, - PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB, + USBD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "designware_udc"); /* clock derived from ahb clk */ @@ -278,9 +277,8 @@ void __init spear6xx_clk_init(void) clk_register_clkdev(clk, "ahbmult2_clk", NULL); clk = clk_register_mux(NULL, "ddr_clk", ddr_parents, - ARRAY_SIZE(ddr_parents), - 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, - &_lock); + ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, + MCTR_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "ddr_clk", NULL); clk = clk_register_divider(NULL, "apb_clk", "ahb_clk", diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c index 9764045428c..b7e7b49d8f6 100644 --- a/drivers/gpu/drm/gma500/cdv_device.c +++ b/drivers/gpu/drm/gma500/cdv_device.c @@ -78,21 +78,6 @@ static int cdv_backlight_combination_mode(struct drm_device *dev) return REG_READ(BLC_PWM_CTL2) & PWM_LEGACY_MODE; } -static int cdv_get_brightness(struct backlight_device *bd) -{ - struct drm_device *dev = bl_get_data(bd); - u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; - - if (cdv_backlight_combination_mode(dev)) { - u8 lbpc; - - val &= ~1; - pci_read_config_byte(dev->pdev, 0xF4, &lbpc); - val *= lbpc; - } - return val; -} - static u32 cdv_get_max_backlight(struct drm_device *dev) { u32 max = REG_READ(BLC_PWM_CTL); @@ -110,6 +95,22 @@ static u32 cdv_get_max_backlight(struct drm_device *dev) return max; } +static int cdv_get_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + + if (cdv_backlight_combination_mode(dev)) { + u8 lbpc; + + val &= ~1; + pci_read_config_byte(dev->pdev, 0xF4, &lbpc); + val *= lbpc; + } + return (val * 100)/cdv_get_max_backlight(dev); + +} + static int cdv_set_brightness(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); @@ -120,6 +121,9 @@ static int cdv_set_brightness(struct backlight_device *bd) if (level < 1) level = 1; + level *= cdv_get_max_backlight(dev); + level /= 100; + if (cdv_backlight_combination_mode(dev)) { u32 max = cdv_get_max_backlight(dev); u8 lbpc; @@ -157,7 +161,6 @@ static int cdv_backlight_init(struct drm_device *dev) cdv_backlight_device->props.brightness = cdv_get_brightness(cdv_backlight_device); - cdv_backlight_device->props.max_brightness = cdv_get_max_backlight(dev); backlight_update_status(cdv_backlight_device); dev_priv->backlight_device = cdv_backlight_device; return 0; diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index 4f186eca3a3..c430bd42468 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -144,6 +144,8 @@ struct opregion_asle { #define ASLE_CBLV_VALID (1<<31) +static struct psb_intel_opregion *system_opregion; + static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_psb_private *dev_priv = dev->dev_private; @@ -205,7 +207,7 @@ void psb_intel_opregion_enable_asle(struct drm_device *dev) struct drm_psb_private *dev_priv = dev->dev_private; struct opregion_asle *asle = dev_priv->opregion.asle; - if (asle) { + if (asle && system_opregion ) { /* Don't do this on Medfield or other non PC like devices, they use the bit for something different altogether */ psb_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); @@ -221,7 +223,6 @@ void psb_intel_opregion_enable_asle(struct drm_device *dev) #define ACPI_EV_LID (1<<1) #define ACPI_EV_DOCK (1<<2) -static struct psb_intel_opregion *system_opregion; static int psb_intel_opregion_video_event(struct notifier_block *nb, unsigned long val, void *data) @@ -266,9 +267,6 @@ void psb_intel_opregion_init(struct drm_device *dev) system_opregion = opregion; register_acpi_notifier(&psb_intel_opregion_notifier); } - - if (opregion->asle) - psb_intel_opregion_enable_asle(dev); } void psb_intel_opregion_fini(struct drm_device *dev) diff --git a/drivers/gpu/drm/gma500/opregion.h b/drivers/gpu/drm/gma500/opregion.h index 72dc6b92126..4a90f8b0e16 100644 --- a/drivers/gpu/drm/gma500/opregion.h +++ b/drivers/gpu/drm/gma500/opregion.h @@ -27,6 +27,7 @@ extern void psb_intel_opregion_asle_intr(struct drm_device *dev); extern void psb_intel_opregion_init(struct drm_device *dev); extern void psb_intel_opregion_fini(struct drm_device *dev); extern int psb_intel_opregion_setup(struct drm_device *dev); +extern void psb_intel_opregion_enable_asle(struct drm_device *dev); #else @@ -46,4 +47,8 @@ extern inline int psb_intel_opregion_setup(struct drm_device *dev) { return 0; } + +extern inline void psb_intel_opregion_enable_asle(struct drm_device *dev) +{ +} #endif diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index eff039bf92d..5971bc82b76 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -144,6 +144,10 @@ static int psb_backlight_init(struct drm_device *dev) psb_backlight_device->props.max_brightness = 100; backlight_update_status(psb_backlight_device); dev_priv->backlight_device = psb_backlight_device; + + /* This must occur after the backlight is properly initialised */ + psb_lid_timer_init(dev_priv); + return 0; } @@ -354,13 +358,6 @@ static int psb_chip_setup(struct drm_device *dev) return 0; } -/* Not exactly an erratum more an irritation */ -static void psb_chip_errata(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - psb_lid_timer_init(dev_priv); -} - static void psb_chip_teardown(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; @@ -379,7 +376,6 @@ const struct psb_ops psb_chip_ops = { .sgx_offset = PSB_SGX_OFFSET, .chip_setup = psb_chip_setup, .chip_teardown = psb_chip_teardown, - .errata = psb_chip_errata, .crtc_helper = &psb_intel_helper_funcs, .crtc_funcs = &psb_intel_crtc_funcs, diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index caba6e08693..a8858a907f4 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -374,6 +374,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (ret) return ret; + psb_intel_opregion_enable_asle(dev); #if 0 /*enable runtime pm at last*/ pm_runtime_enable(&dev->pdev->dev); diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index bef04c19276..3fda8c87f02 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -386,6 +386,7 @@ config HID_MULTITOUCH - Unitec Panels - XAT optical touch panels - Xiroku optical touch panels + - Zytronic touch panels If unsure, say N. diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 875ff451842..32039235cfe 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -659,6 +659,9 @@ #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600 +#define USB_VENDOR_ID_SENNHEISER 0x1395 +#define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c + #define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002 @@ -808,6 +811,9 @@ #define USB_VENDOR_ID_ZYDACRON 0x13EC #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006 +#define USB_VENDOR_ID_ZYTRONIC 0x14c8 +#define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 + #define USB_VENDOR_ID_PRIMAX 0x0461 #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 132b0019365..5301006f6c1 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -301,6 +301,9 @@ static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, {} }; diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6e3332a9997..76479246d4e 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1048,6 +1048,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, + /* Zytronic panels */ + { .driver_data = MT_CLS_SERIAL, + MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC, + USB_DEVICE_ID_ZYTRONIC_ZXY100) }, + /* Generic MT device */ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, { } diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0597ee604f6..903eef3d3e1 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -76,6 +76,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 5c1bc995e56..f10221f4080 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -123,7 +123,7 @@ static void ipoib_ud_skb_put_frags(struct ipoib_dev_priv *priv, skb_frag_size_set(frag, size); skb->data_len += size; - skb->truesize += size; + skb->truesize += PAGE_SIZE; } else skb_put(skb, length); @@ -156,14 +156,18 @@ static struct sk_buff *ipoib_alloc_rx_skb(struct net_device *dev, int id) struct ipoib_dev_priv *priv = netdev_priv(dev); struct sk_buff *skb; int buf_size; + int tailroom; u64 *mapping; - if (ipoib_ud_need_sg(priv->max_ib_mtu)) + if (ipoib_ud_need_sg(priv->max_ib_mtu)) { buf_size = IPOIB_UD_HEAD_SIZE; - else + tailroom = 128; /* reserve some tailroom for IP/TCP headers */ + } else { buf_size = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu); + tailroom = 0; + } - skb = dev_alloc_skb(buf_size + 4); + skb = dev_alloc_skb(buf_size + tailroom + 4); if (unlikely(!skb)) return NULL; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 5f6b7f63cde..7a0ce8d4288 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1377,10 +1377,14 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) break; case SRPT_STATE_NEED_DATA: /* DMA_TO_DEVICE (write) - RDMA read error. */ + + /* XXX(hch): this is a horrible layering violation.. */ spin_lock_irqsave(&ioctx->cmd.t_state_lock, flags); ioctx->cmd.transport_state |= CMD_T_LUN_STOP; + ioctx->cmd.transport_state &= ~CMD_T_ACTIVE; spin_unlock_irqrestore(&ioctx->cmd.t_state_lock, flags); - transport_generic_handle_data(&ioctx->cmd); + + complete(&ioctx->cmd.transport_lun_stop_comp); break; case SRPT_STATE_CMD_RSP_SENT: /* @@ -1463,9 +1467,10 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch, /** * srpt_handle_rdma_comp() - Process an IB RDMA completion notification. * - * Note: transport_generic_handle_data() is asynchronous so unmapping the - * data that has been transferred via IB RDMA must be postponed until the - * check_stop_free() callback. + * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping + * the data that has been transferred via IB RDMA had to be postponed until the + * check_stop_free() callback. None of this is nessecary anymore and needs to + * be cleaned up. */ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch, struct srpt_send_ioctx *ioctx, @@ -1477,7 +1482,7 @@ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch, if (opcode == SRPT_RDMA_READ_LAST) { if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA, SRPT_STATE_DATA_IN)) - transport_generic_handle_data(&ioctx->cmd); + target_execute_cmd(&ioctx->cmd); else printk(KERN_ERR "%s[%d]: wrong state = %d\n", __func__, __LINE__, srpt_get_cmd_state(ioctx)); diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 3a74e4410fc..86e2f4a62b9 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -26,6 +26,8 @@ * These routines are used by both DMA-remapping and Interrupt-remapping */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* has to precede printk.h */ + #include <linux/pci.h> #include <linux/dmar.h> #include <linux/iova.h> @@ -39,8 +41,6 @@ #include <asm/irq_remapping.h> #include <asm/iommu_table.h> -#define PREFIX "DMAR: " - /* No locks are needed as DMA remapping hardware unit * list is constructed at boot time and hotplug of * these units are not supported by the architecture. @@ -83,16 +83,12 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, * ignore it */ if (!bus) { - printk(KERN_WARNING - PREFIX "Device scope bus [%d] not found\n", - scope->bus); + pr_warn("Device scope bus [%d] not found\n", scope->bus); break; } pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn)); if (!pdev) { - printk(KERN_WARNING PREFIX - "Device scope device [%04x:%02x:%02x.%02x] not found\n", - segment, bus->number, path->dev, path->fn); + /* warning will be printed below */ break; } path ++; @@ -100,9 +96,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, bus = pdev->subordinate; } if (!pdev) { - printk(KERN_WARNING PREFIX - "Device scope device [%04x:%02x:%02x.%02x] not found\n", - segment, scope->bus, path->dev, path->fn); + pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n", + segment, scope->bus, path->dev, path->fn); *dev = NULL; return 0; } @@ -110,9 +105,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, pdev->subordinate) || (scope->entry_type == \ ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) { pci_dev_put(pdev); - printk(KERN_WARNING PREFIX - "Device scope type does not match for %s\n", - pci_name(pdev)); + pr_warn("Device scope type does not match for %s\n", + pci_name(pdev)); return -EINVAL; } *dev = pdev; @@ -134,8 +128,7 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) (*cnt)++; else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) { - printk(KERN_WARNING PREFIX - "Unsupported device scope\n"); + pr_warn("Unsupported device scope\n"); } start += scope->length; } @@ -261,25 +254,23 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) case ACPI_DMAR_TYPE_HARDWARE_UNIT: drhd = container_of(header, struct acpi_dmar_hardware_unit, header); - printk (KERN_INFO PREFIX - "DRHD base: %#016Lx flags: %#x\n", + pr_info("DRHD base: %#016Lx flags: %#x\n", (unsigned long long)drhd->address, drhd->flags); break; case ACPI_DMAR_TYPE_RESERVED_MEMORY: rmrr = container_of(header, struct acpi_dmar_reserved_memory, header); - printk (KERN_INFO PREFIX - "RMRR base: %#016Lx end: %#016Lx\n", + pr_info("RMRR base: %#016Lx end: %#016Lx\n", (unsigned long long)rmrr->base_address, (unsigned long long)rmrr->end_address); break; case ACPI_DMAR_TYPE_ATSR: atsr = container_of(header, struct acpi_dmar_atsr, header); - printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); + pr_info("ATSR flags: %#x\n", atsr->flags); break; case ACPI_DMAR_HARDWARE_AFFINITY: rhsa = container_of(header, struct acpi_dmar_rhsa, header); - printk(KERN_INFO PREFIX "RHSA base: %#016Lx proximity domain: %#x\n", + pr_info("RHSA base: %#016Lx proximity domain: %#x\n", (unsigned long long)rhsa->base_address, rhsa->proximity_domain); break; @@ -299,7 +290,7 @@ static int __init dmar_table_detect(void) &dmar_tbl_size); if (ACPI_SUCCESS(status) && !dmar_tbl) { - printk (KERN_WARNING PREFIX "Unable to map DMAR\n"); + pr_warn("Unable to map DMAR\n"); status = AE_NOT_FOUND; } @@ -333,20 +324,18 @@ parse_dmar_table(void) return -ENODEV; if (dmar->width < PAGE_SHIFT - 1) { - printk(KERN_WARNING PREFIX "Invalid DMAR haw\n"); + pr_warn("Invalid DMAR haw\n"); return -EINVAL; } - printk (KERN_INFO PREFIX "Host address width %d\n", - dmar->width + 1); + pr_info("Host address width %d\n", dmar->width + 1); entry_header = (struct acpi_dmar_header *)(dmar + 1); while (((unsigned long)entry_header) < (((unsigned long)dmar) + dmar_tbl->length)) { /* Avoid looping forever on bad ACPI tables */ if (entry_header->length == 0) { - printk(KERN_WARNING PREFIX - "Invalid 0-length structure\n"); + pr_warn("Invalid 0-length structure\n"); ret = -EINVAL; break; } @@ -369,8 +358,7 @@ parse_dmar_table(void) #endif break; default: - printk(KERN_WARNING PREFIX - "Unknown DMAR structure type %d\n", + pr_warn("Unknown DMAR structure type %d\n", entry_header->type); ret = 0; /* for forward compatibility */ break; @@ -469,12 +457,12 @@ int __init dmar_table_init(void) ret = parse_dmar_table(); if (ret) { if (ret != -ENODEV) - printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); + pr_info("parse DMAR table failure.\n"); return ret; } if (list_empty(&dmar_drhd_units)) { - printk(KERN_INFO PREFIX "No DMAR devices found\n"); + pr_info("No DMAR devices found\n"); return -ENODEV; } @@ -506,8 +494,7 @@ int __init check_zero_address(void) (((unsigned long)dmar) + dmar_tbl->length)) { /* Avoid looping forever on bad ACPI tables */ if (entry_header->length == 0) { - printk(KERN_WARNING PREFIX - "Invalid 0-length structure\n"); + pr_warn("Invalid 0-length structure\n"); return 0; } @@ -558,8 +545,7 @@ int __init detect_intel_iommu(void) if (ret && irq_remapping_enabled && cpu_has_x2apic && dmar->flags & 0x1) - printk(KERN_INFO - "Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); + pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { iommu_detected = 1; @@ -579,14 +565,89 @@ int __init detect_intel_iommu(void) } +static void unmap_iommu(struct intel_iommu *iommu) +{ + iounmap(iommu->reg); + release_mem_region(iommu->reg_phys, iommu->reg_size); +} + +/** + * map_iommu: map the iommu's registers + * @iommu: the iommu to map + * @phys_addr: the physical address of the base resgister + * + * Memory map the iommu's registers. Start w/ a single page, and + * possibly expand if that turns out to be insufficent. + */ +static int map_iommu(struct intel_iommu *iommu, u64 phys_addr) +{ + int map_size, err=0; + + iommu->reg_phys = phys_addr; + iommu->reg_size = VTD_PAGE_SIZE; + + if (!request_mem_region(iommu->reg_phys, iommu->reg_size, iommu->name)) { + pr_err("IOMMU: can't reserve memory\n"); + err = -EBUSY; + goto out; + } + + iommu->reg = ioremap(iommu->reg_phys, iommu->reg_size); + if (!iommu->reg) { + pr_err("IOMMU: can't map the region\n"); + err = -ENOMEM; + goto release; + } + + iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); + iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); + + if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { + err = -EINVAL; + warn_invalid_dmar(phys_addr, " returns all ones"); + goto unmap; + } + + /* the registers might be more than one page */ + map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), + cap_max_fault_reg_offset(iommu->cap)); + map_size = VTD_PAGE_ALIGN(map_size); + if (map_size > iommu->reg_size) { + iounmap(iommu->reg); + release_mem_region(iommu->reg_phys, iommu->reg_size); + iommu->reg_size = map_size; + if (!request_mem_region(iommu->reg_phys, iommu->reg_size, + iommu->name)) { + pr_err("IOMMU: can't reserve memory\n"); + err = -EBUSY; + goto out; + } + iommu->reg = ioremap(iommu->reg_phys, iommu->reg_size); + if (!iommu->reg) { + pr_err("IOMMU: can't map the region\n"); + err = -ENOMEM; + goto release; + } + } + err = 0; + goto out; + +unmap: + iounmap(iommu->reg); +release: + release_mem_region(iommu->reg_phys, iommu->reg_size); +out: + return err; +} + int alloc_iommu(struct dmar_drhd_unit *drhd) { struct intel_iommu *iommu; - int map_size; u32 ver; static int iommu_allocated = 0; int agaw = 0; int msagaw = 0; + int err; if (!drhd->reg_base_addr) { warn_invalid_dmar(0, ""); @@ -600,30 +661,22 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->seq_id = iommu_allocated++; sprintf (iommu->name, "dmar%d", iommu->seq_id); - iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE); - if (!iommu->reg) { - printk(KERN_ERR "IOMMU: can't map the region\n"); + err = map_iommu(iommu, drhd->reg_base_addr); + if (err) { + pr_err("IOMMU: failed to map %s\n", iommu->name); goto error; } - iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); - iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); - - if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { - warn_invalid_dmar(drhd->reg_base_addr, " returns all ones"); - goto err_unmap; - } + err = -EINVAL; agaw = iommu_calculate_agaw(iommu); if (agaw < 0) { - printk(KERN_ERR - "Cannot get a valid agaw for iommu (seq_id = %d)\n", - iommu->seq_id); + pr_err("Cannot get a valid agaw for iommu (seq_id = %d)\n", + iommu->seq_id); goto err_unmap; } msagaw = iommu_calculate_max_sagaw(iommu); if (msagaw < 0) { - printk(KERN_ERR - "Cannot get a valid max agaw for iommu (seq_id = %d)\n", + pr_err("Cannot get a valid max agaw for iommu (seq_id = %d)\n", iommu->seq_id); goto err_unmap; } @@ -632,19 +685,6 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->node = -1; - /* the registers might be more than one page */ - map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), - cap_max_fault_reg_offset(iommu->cap)); - map_size = VTD_PAGE_ALIGN(map_size); - if (map_size > VTD_PAGE_SIZE) { - iounmap(iommu->reg); - iommu->reg = ioremap(drhd->reg_base_addr, map_size); - if (!iommu->reg) { - printk(KERN_ERR "IOMMU: can't map the region\n"); - goto error; - } - } - ver = readl(iommu->reg + DMAR_VER_REG); pr_info("IOMMU %d: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n", iommu->seq_id, @@ -659,10 +699,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) return 0; err_unmap: - iounmap(iommu->reg); + unmap_iommu(iommu); error: kfree(iommu); - return -1; + return err; } void free_iommu(struct intel_iommu *iommu) @@ -673,7 +713,8 @@ void free_iommu(struct intel_iommu *iommu) free_dmar_iommu(iommu); if (iommu->reg) - iounmap(iommu->reg); + unmap_iommu(iommu); + kfree(iommu); } @@ -710,7 +751,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index) if (fault & DMA_FSTS_IQE) { head = readl(iommu->reg + DMAR_IQH_REG); if ((head >> DMAR_IQ_SHIFT) == index) { - printk(KERN_ERR "VT-d detected invalid descriptor: " + pr_err("VT-d detected invalid descriptor: " "low=%llx, high=%llx\n", (unsigned long long)qi->desc[index].low, (unsigned long long)qi->desc[index].high); @@ -1129,15 +1170,14 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type, reason = dmar_get_fault_reason(fault_reason, &fault_type); if (fault_type == INTR_REMAP) - printk(KERN_ERR "INTR-REMAP: Request device [[%02x:%02x.%d] " + pr_err("INTR-REMAP: Request device [[%02x:%02x.%d] " "fault index %llx\n" "INTR-REMAP:[fault reason %02d] %s\n", (source_id >> 8), PCI_SLOT(source_id & 0xFF), PCI_FUNC(source_id & 0xFF), addr >> 48, fault_reason, reason); else - printk(KERN_ERR - "DMAR:[%s] Request device [%02x:%02x.%d] " + pr_err("DMAR:[%s] Request device [%02x:%02x.%d] " "fault addr %llx \n" "DMAR:[fault reason %02d] %s\n", (type ? "DMA Read" : "DMA Write"), @@ -1157,8 +1197,7 @@ irqreturn_t dmar_fault(int irq, void *dev_id) raw_spin_lock_irqsave(&iommu->register_lock, flag); fault_status = readl(iommu->reg + DMAR_FSTS_REG); if (fault_status) - printk(KERN_ERR "DRHD: handling fault status reg %x\n", - fault_status); + pr_err("DRHD: handling fault status reg %x\n", fault_status); /* TBD: ignore advanced fault log currently */ if (!(fault_status & DMA_FSTS_PPF)) @@ -1224,7 +1263,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) irq = create_irq(); if (!irq) { - printk(KERN_ERR "IOMMU: no free vectors\n"); + pr_err("IOMMU: no free vectors\n"); return -EINVAL; } @@ -1241,7 +1280,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu); if (ret) - printk(KERN_ERR "IOMMU: can't request irq\n"); + pr_err("IOMMU: can't request irq\n"); return ret; } @@ -1258,8 +1297,7 @@ int __init enable_drhd_fault_handling(void) ret = dmar_set_interrupt(iommu); if (ret) { - printk(KERN_ERR "DRHD %Lx: failed to enable fault, " - " interrupt, ret %d\n", + pr_err("DRHD %Lx: failed to enable fault, interrupt, ret %d\n", (unsigned long long)drhd->reg_base_addr, ret); return -1; } diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 6d347064b8b..e0b18f3ae9a 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -902,7 +902,6 @@ static int intel_setup_ioapic_entry(int irq, return 0; } -#ifdef CONFIG_SMP /* * Migrate the IO-APIC irq in the presence of intr-remapping. * @@ -924,6 +923,10 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, struct irq_cfg *cfg = data->chip_data; unsigned int dest, irq = data->irq; struct irte irte; + int err; + + if (!config_enabled(CONFIG_SMP)) + return -EINVAL; if (!cpumask_intersects(mask, cpu_online_mask)) return -EINVAL; @@ -931,10 +934,16 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, if (get_irte(irq, &irte)) return -EBUSY; - if (assign_irq_vector(irq, cfg, mask)) - return -EBUSY; + err = assign_irq_vector(irq, cfg, mask); + if (err) + return err; - dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask); + err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest); + if (err) { + if (assign_irq_vector(irq, cfg, data->affinity)) + pr_err("Failed to recover vector for irq %d\n", irq); + return err; + } irte.vector = cfg->vector; irte.dest_id = IRTE_DEST(dest); @@ -956,7 +965,6 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, cpumask_copy(data->affinity, mask); return 0; } -#endif static void intel_compose_msi_msg(struct pci_dev *pdev, unsigned int irq, unsigned int dest, @@ -1058,9 +1066,7 @@ struct irq_remap_ops intel_irq_remap_ops = { .reenable = reenable_irq_remapping, .enable_faulting = enable_drhd_fault_handling, .setup_ioapic_entry = intel_setup_ioapic_entry, -#ifdef CONFIG_SMP .set_affinity = intel_ioapic_set_affinity, -#endif .free_irq = free_irte, .compose_msi_msg = intel_compose_msi_msg, .msi_alloc_irq = intel_msi_alloc_irq, diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 40cda8e98d8..1d29b1c66e7 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -111,16 +111,15 @@ int setup_ioapic_remapped_entry(int irq, vector, attr); } -#ifdef CONFIG_SMP int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, bool force) { - if (!remap_ops || !remap_ops->set_affinity) + if (!config_enabled(CONFIG_SMP) || !remap_ops || + !remap_ops->set_affinity) return 0; return remap_ops->set_affinity(data, mask, force); } -#endif void free_remapped_irq(int irq) { diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h index be9d72950c5..b12974cc1df 100644 --- a/drivers/iommu/irq_remapping.h +++ b/drivers/iommu/irq_remapping.h @@ -59,11 +59,9 @@ struct irq_remap_ops { unsigned int, int, struct io_apic_irq_attr *); -#ifdef CONFIG_SMP /* Set the CPU affinity of a remapped interrupt */ int (*set_affinity)(struct irq_data *data, const struct cpumask *mask, bool force); -#endif /* Free an IRQ */ int (*free_irq)(int); diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 1a0ae4445ff..5f21f629b7a 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -135,8 +135,8 @@ send_layer2(struct mISDNstack *st, struct sk_buff *skb) skb = NULL; else if (*debug & DEBUG_SEND_ERR) printk(KERN_DEBUG - "%s ch%d mgr prim(%x) addr(%x) err %d\n", - __func__, ch->nr, hh->prim, ch->addr, ret); + "%s mgr prim(%x) err %d\n", + __func__, hh->prim, ret); } out: mutex_unlock(&st->lmutex); diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d039de8322f..b58b7a33914 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1084,6 +1084,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->split_io = dm_rh_get_region_size(ms->rh); ti->num_flush_requests = 1; ti->num_discard_requests = 1; + ti->discard_zeroes_data_unsupported = 1; ms->kmirrord_wq = alloc_workqueue("kmirrord", WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); @@ -1214,7 +1215,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, * We need to dec pending if this was a write. */ if (rw == WRITE) { - if (!(bio->bi_rw & REQ_FLUSH)) + if (!(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) dm_rh_dec(ms->rh, map_context->ll); return error; } diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 7771ed21218..69732e03eb3 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -404,6 +404,9 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) return; } + if (bio->bi_rw & REQ_DISCARD) + return; + /* We must inform the log that the sync count has changed. */ log->type->set_region_sync(log, region, 0); @@ -524,7 +527,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios) struct bio *bio; for (bio = bios->head; bio; bio = bio->bi_next) { - if (bio->bi_rw & REQ_FLUSH) + if (bio->bi_rw & (REQ_FLUSH | REQ_DISCARD)) continue; rh_inc(rh, dm_rh_bio_to_region(rh, bio)); } diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index ce59824fb41..68694da0d21 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1245,7 +1245,10 @@ static void process_discard(struct thin_c *tc, struct bio *bio) cell_release_singleton(cell, bio); cell_release_singleton(cell2, bio); - remap_and_issue(tc, bio, lookup_result.block); + if ((!lookup_result.shared) && pool->pf.discard_passdown) + remap_and_issue(tc, bio, lookup_result.block); + else + bio_endio(bio, 0); } break; @@ -2628,6 +2631,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) if (tc->pool->pf.discard_enabled) { ti->discards_supported = 1; ti->num_discard_requests = 1; + ti->discard_zeroes_data_unsupported = 1; } dm_put(pool_md); diff --git a/drivers/md/md.c b/drivers/md/md.c index a4c219e3c85..d5ab4493c8b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2931,6 +2931,7 @@ offset_store(struct md_rdev *rdev, const char *buf, size_t len) * can be sane */ return -EBUSY; rdev->data_offset = offset; + rdev->new_data_offset = offset; return len; } @@ -3926,8 +3927,8 @@ array_state_show(struct mddev *mddev, char *page) return sprintf(page, "%s\n", array_states[st]); } -static int do_md_stop(struct mddev * mddev, int ro, int is_open); -static int md_set_readonly(struct mddev * mddev, int is_open); +static int do_md_stop(struct mddev * mddev, int ro, struct block_device *bdev); +static int md_set_readonly(struct mddev * mddev, struct block_device *bdev); static int do_md_run(struct mddev * mddev); static int restart_array(struct mddev *mddev); @@ -3943,14 +3944,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) /* stopping an active array */ if (atomic_read(&mddev->openers) > 0) return -EBUSY; - err = do_md_stop(mddev, 0, 0); + err = do_md_stop(mddev, 0, NULL); break; case inactive: /* stopping an active array */ if (mddev->pers) { if (atomic_read(&mddev->openers) > 0) return -EBUSY; - err = do_md_stop(mddev, 2, 0); + err = do_md_stop(mddev, 2, NULL); } else err = 0; /* already inactive */ break; @@ -3958,7 +3959,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) break; /* not supported yet */ case readonly: if (mddev->pers) - err = md_set_readonly(mddev, 0); + err = md_set_readonly(mddev, NULL); else { mddev->ro = 1; set_disk_ro(mddev->gendisk, 1); @@ -3968,7 +3969,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) case read_auto: if (mddev->pers) { if (mddev->ro == 0) - err = md_set_readonly(mddev, 0); + err = md_set_readonly(mddev, NULL); else if (mddev->ro == 1) err = restart_array(mddev); if (err == 0) { @@ -5351,15 +5352,17 @@ void md_stop(struct mddev *mddev) } EXPORT_SYMBOL_GPL(md_stop); -static int md_set_readonly(struct mddev *mddev, int is_open) +static int md_set_readonly(struct mddev *mddev, struct block_device *bdev) { int err = 0; mutex_lock(&mddev->open_mutex); - if (atomic_read(&mddev->openers) > is_open) { + if (atomic_read(&mddev->openers) > !!bdev) { printk("md: %s still in use.\n",mdname(mddev)); err = -EBUSY; goto out; } + if (bdev) + sync_blockdev(bdev); if (mddev->pers) { __md_stop_writes(mddev); @@ -5381,18 +5384,26 @@ out: * 0 - completely stop and dis-assemble array * 2 - stop but do not disassemble array */ -static int do_md_stop(struct mddev * mddev, int mode, int is_open) +static int do_md_stop(struct mddev * mddev, int mode, + struct block_device *bdev) { struct gendisk *disk = mddev->gendisk; struct md_rdev *rdev; mutex_lock(&mddev->open_mutex); - if (atomic_read(&mddev->openers) > is_open || + if (atomic_read(&mddev->openers) > !!bdev || mddev->sysfs_active) { printk("md: %s still in use.\n",mdname(mddev)); mutex_unlock(&mddev->open_mutex); return -EBUSY; } + if (bdev) + /* It is possible IO was issued on some other + * open file which was closed before we took ->open_mutex. + * As that was not the last close __blkdev_put will not + * have called sync_blockdev, so we must. + */ + sync_blockdev(bdev); if (mddev->pers) { if (mddev->ro) @@ -5466,7 +5477,7 @@ static void autorun_array(struct mddev *mddev) err = do_md_run(mddev); if (err) { printk(KERN_WARNING "md: do_md_run() returned %d\n", err); - do_md_stop(mddev, 0, 0); + do_md_stop(mddev, 0, NULL); } } @@ -6481,11 +6492,11 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, goto done_unlock; case STOP_ARRAY: - err = do_md_stop(mddev, 0, 1); + err = do_md_stop(mddev, 0, bdev); goto done_unlock; case STOP_ARRAY_RO: - err = md_set_readonly(mddev, 1); + err = md_set_readonly(mddev, bdev); goto done_unlock; case BLKROSET: diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 240ff312504..cacd008d686 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1818,8 +1818,14 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio) if (atomic_dec_and_test(&r1_bio->remaining)) { /* if we're here, all write(s) have completed, so clean up */ - md_done_sync(mddev, r1_bio->sectors, 1); - put_buf(r1_bio); + int s = r1_bio->sectors; + if (test_bit(R1BIO_MadeGood, &r1_bio->state) || + test_bit(R1BIO_WriteError, &r1_bio->state)) + reschedule_retry(r1_bio); + else { + put_buf(r1_bio); + md_done_sync(mddev, s, 1); + } } } diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c index 83c1aa6b2e6..f11f6f07e91 100644 --- a/drivers/media/video/cx25821/cx25821-core.c +++ b/drivers/media/video/cx25821/cx25821-core.c @@ -904,9 +904,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) list_add_tail(&dev->devlist, &cx25821_devlist); mutex_unlock(&cx25821_devlist_mutex); - strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown"); - strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821"); - if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index b9aa801b00a..029f2934a6d 100644 --- a/drivers/media/video/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h @@ -187,7 +187,7 @@ enum port { }; struct cx25821_board { - char *name; + const char *name; enum port porta; enum port portb; enum port portc; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 83dbb2ddff1..0cbada18f6f 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -681,6 +681,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); + SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap); /* yes, really vidioc_subscribe_event */ SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event); SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event); diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index db194e433c0..61c097a98f5 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -24,6 +24,7 @@ #include <linux/slab.h> #include <linux/regmap.h> #include <linux/err.h> +#include <linux/regulator/of_regulator.h> #include <linux/mfd/core.h> #include <linux/mfd/tps65217.h> @@ -132,6 +133,61 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg, } EXPORT_SYMBOL_GPL(tps65217_clear_bits); +#ifdef CONFIG_OF +static struct of_regulator_match reg_matches[] = { + { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 }, + { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 }, + { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 }, + { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 }, + { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 }, + { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 }, + { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 }, +}; + +static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) +{ + struct device_node *node = client->dev.of_node; + struct tps65217_board *pdata; + struct device_node *regs; + int count = ARRAY_SIZE(reg_matches); + int ret, i; + + regs = of_find_node_by_name(node, "regulators"); + if (!regs) + return NULL; + + ret = of_regulator_match(&client->dev, regs, reg_matches, count); + of_node_put(regs); + if ((ret < 0) || (ret > count)) + return NULL; + + count = ret; + pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + for (i = 0; i < count; i++) { + if (!reg_matches[i].init_data || !reg_matches[i].of_node) + continue; + + pdata->tps65217_init_data[i] = reg_matches[i].init_data; + pdata->of_node[i] = reg_matches[i].of_node; + } + + return pdata; +} + +static struct of_device_id tps65217_of_match[] = { + { .compatible = "ti,tps65217", }, + { }, +}; +#else +static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) +{ + return NULL; +} +#endif + static struct regmap_config tps65217_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -141,10 +197,14 @@ static int __devinit tps65217_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct tps65217 *tps; + struct regulator_init_data *reg_data; struct tps65217_board *pdata = client->dev.platform_data; int i, ret; unsigned int version; + if (!pdata && client->dev.of_node) + pdata = tps65217_parse_dt(client); + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; @@ -182,8 +242,9 @@ static int __devinit tps65217_probe(struct i2c_client *client, } pdev->dev.parent = tps->dev; - platform_device_add_data(pdev, &pdata->tps65217_init_data[i], - sizeof(pdata->tps65217_init_data[i])); + pdev->dev.of_node = pdata->of_node[i]; + reg_data = pdata->tps65217_init_data[i]; + platform_device_add_data(pdev, reg_data, sizeof(*reg_data)); tps->regulator_pdev[i] = pdev; platform_device_add(pdev); @@ -212,6 +273,8 @@ MODULE_DEVICE_TABLE(i2c, tps65217_id_table); static struct i2c_driver tps65217_driver = { .driver = { .name = "tps65217", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tps65217_of_match), }, .id_table = tps65217_id_table, .probe = tps65217_probe, diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c index 3680aa251de..2cf084eb9d5 100644 --- a/drivers/net/bonding/bond_debugfs.c +++ b/drivers/net/bonding/bond_debugfs.c @@ -6,7 +6,7 @@ #include "bonding.h" #include "bond_alb.h" -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_NET_NS) #include <linux/debugfs.h> #include <linux/seq_file.h> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b9c2ae62166..2ee76993f05 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3227,6 +3227,12 @@ static int bond_master_netdev_event(unsigned long event, switch (event) { case NETDEV_CHANGENAME: return bond_event_changename(event_bond); + case NETDEV_UNREGISTER: + bond_remove_proc_entry(event_bond); + break; + case NETDEV_REGISTER: + bond_create_proc_entry(event_bond); + break; default: break; } @@ -4411,8 +4417,6 @@ static void bond_uninit(struct net_device *bond_dev) bond_work_cancel_all(bond); - bond_remove_proc_entry(bond); - bond_debug_unregister(bond); __hw_addr_flush(&bond->mc_list); @@ -4814,7 +4818,6 @@ static int bond_init(struct net_device *bond_dev) bond_set_lockdep_class(bond_dev); - bond_create_proc_entry(bond); list_add_tail(&bond->bond_list, &bn->dev_list); bond_prepare_sysfs_group(bond); diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 9cc15701101..1f78b63d5ef 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -261,7 +261,6 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) if ((phy_data & BMSR_LSTATUS) == 0) { /* link down */ netif_carrier_off(netdev); - netif_stop_queue(netdev); hw->hibernate = true; if (atl1c_reset_mac(hw) != 0) if (netif_msg_hw(adapter)) diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 46b8b7d8163..d09c6b583d1 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -656,7 +656,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); - skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); + skb = alloc_skb(RX_PKT_BUF_SZ, GFP_ATOMIC | GFP_DMA); if (skb == NULL) return -ENOMEM; mapping = dma_map_single(bp->sdev->dma_dev, skb->data, @@ -967,7 +967,7 @@ static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev) dma_unmap_single(bp->sdev->dma_dev, mapping, len, DMA_TO_DEVICE); - bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA); + bounce_skb = alloc_skb(len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) goto err_out; diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index ac7b7448853..1fa4927a45b 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -5372,7 +5372,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp) int k, last; if (skb == NULL) { - j++; + j = NEXT_TX_BD(j); continue; } @@ -5384,8 +5384,8 @@ bnx2_free_tx_skbs(struct bnx2 *bp) tx_buf->skb = NULL; last = tx_buf->nr_frags; - j++; - for (k = 0; k < last; k++, j++) { + j = NEXT_TX_BD(j); + for (k = 0; k < last; k++, j = NEXT_TX_BD(j)) { tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)]; dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping), diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index c95e7b5e2b8..2c89d17cbb2 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -534,7 +534,8 @@ int cnic_unregister_driver(int ulp_type) } if (atomic_read(&ulp_ops->ref_count) != 0) - netdev_warn(dev->netdev, "Failed waiting for ref count to go to zero\n"); + pr_warn("%s: Failed waiting for ref count to go to zero\n", + __func__); return 0; out_unlock: @@ -1053,12 +1054,13 @@ static int cnic_init_uio(struct cnic_dev *dev) uinfo = &udev->cnic_uinfo; - uinfo->mem[0].addr = dev->netdev->base_addr; + uinfo->mem[0].addr = pci_resource_start(dev->pcidev, 0); uinfo->mem[0].internal_addr = dev->regview; - uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start; uinfo->mem[0].memtype = UIO_MEM_PHYS; if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { + uinfo->mem[0].size = MB_GET_CID_ADDR(TX_TSS_CID + + TX_MAX_TSS_RINGS + 1); uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen & PAGE_MASK; if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) @@ -1068,6 +1070,8 @@ static int cnic_init_uio(struct cnic_dev *dev) uinfo->name = "bnx2_cnic"; } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { + uinfo->mem[0].size = pci_resource_len(dev->pcidev, 0); + uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk & PAGE_MASK; uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index f2db8fca46a..ab1d80ff079 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2063,10 +2063,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - /* Steal sock reference for processing TX time stamps */ - swap(skb_new->sk, skb->sk); - swap(skb_new->destructor, skb->destructor); - kfree_skb(skb); + if (skb->sk) + skb_set_owner_w(skb_new, skb->sk); + consume_skb(skb); skb = skb_new; } diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index 36db4df09ae..1f063dcd8f8 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -1572,6 +1572,9 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) ctrl = er32(CTRL); status = er32(STATUS); rxcw = er32(RXCW); + /* SYNCH bit and IV bit are sticky */ + udelay(10); + rxcw = er32(RXCW); if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) { diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 238ab2f8a5e..e3a7b07df62 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -325,24 +325,46 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) **/ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) { - u16 phy_reg; - u32 phy_id; + u16 phy_reg = 0; + u32 phy_id = 0; + s32 ret_val; + u16 retry_count; + + for (retry_count = 0; retry_count < 2; retry_count++) { + ret_val = e1e_rphy_locked(hw, PHY_ID1, &phy_reg); + if (ret_val || (phy_reg == 0xFFFF)) + continue; + phy_id = (u32)(phy_reg << 16); - e1e_rphy_locked(hw, PHY_ID1, &phy_reg); - phy_id = (u32)(phy_reg << 16); - e1e_rphy_locked(hw, PHY_ID2, &phy_reg); - phy_id |= (u32)(phy_reg & PHY_REVISION_MASK); + ret_val = e1e_rphy_locked(hw, PHY_ID2, &phy_reg); + if (ret_val || (phy_reg == 0xFFFF)) { + phy_id = 0; + continue; + } + phy_id |= (u32)(phy_reg & PHY_REVISION_MASK); + break; + } if (hw->phy.id) { if (hw->phy.id == phy_id) return true; - } else { - if ((phy_id != 0) && (phy_id != PHY_REVISION_MASK)) - hw->phy.id = phy_id; + } else if (phy_id) { + hw->phy.id = phy_id; + hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK); return true; } - return false; + /* + * In case the PHY needs to be in mdio slow mode, + * set slow mode and try to get the PHY id again. + */ + hw->phy.ops.release(hw); + ret_val = e1000_set_mdio_slow_mode_hv(hw); + if (!ret_val) + ret_val = e1000e_get_phy_id(hw); + hw->phy.ops.acquire(hw); + + return !ret_val; } /** diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 18ca3bcadf0..e242104ab47 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6647,6 +6647,11 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc) return -EINVAL; } + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { + e_err(drv, "Enable failed, SR-IOV enabled\n"); + return -EINVAL; + } + /* Hardware supports up to 8 traffic classes */ if (tc > adapter->dcb_cfg.num_tcs.pg_tcs || (hw->mac.type == ixgbe_mac_82598EB && diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index f69ec4288b1..41e32257a4e 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -201,6 +201,9 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter, unsigned int i, eop, count = 0; unsigned int total_bytes = 0, total_packets = 0; + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + i = tx_ring->next_to_clean; eop = tx_ring->tx_buffer_info[i].next_to_watch; eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); @@ -969,8 +972,6 @@ static irqreturn_t ixgbevf_msix_clean_tx(int irq, void *data) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { tx_ring = &(adapter->tx_ring[r_idx]); - tx_ring->total_bytes = 0; - tx_ring->total_packets = 0; ixgbevf_clean_tx_irq(adapter, tx_ring); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, r_idx + 1); @@ -994,16 +995,6 @@ static irqreturn_t ixgbevf_msix_clean_rx(int irq, void *data) struct ixgbe_hw *hw = &adapter->hw; struct ixgbevf_ring *rx_ring; int r_idx; - int i; - - r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); - for (i = 0; i < q_vector->rxr_count; i++) { - rx_ring = &(adapter->rx_ring[r_idx]); - rx_ring->total_bytes = 0; - rx_ring->total_packets = 0; - r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, - r_idx + 1); - } if (!q_vector->rxr_count) return IRQ_HANDLED; diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c index fb8377da168..4b785e10f2e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c @@ -51,7 +51,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) desc->des3 = desc->des2 + BUF_SIZE_4KiB; priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum); - + wmb(); entry = (++priv->cur_tx) % txsize; desc = priv->dma_tx + entry; @@ -59,6 +59,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) len, DMA_TO_DEVICE); desc->des3 = desc->des2 + BUF_SIZE_4KiB; priv->hw->desc->prepare_tx_desc(desc, 0, len, csum); + wmb(); priv->hw->desc->set_tx_owner(desc); priv->tx_skbuff[entry] = NULL; } else { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 51b3b68528e..ea3003edde1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1212,6 +1212,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion); wmb(); priv->hw->desc->set_tx_owner(desc); + wmb(); } /* Interrupt on completition only for the latest segment */ @@ -1227,6 +1228,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) /* To avoid raise condition */ priv->hw->desc->set_tx_owner(first); + wmb(); priv->cur_tx++; @@ -1290,6 +1292,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv) } wmb(); priv->hw->desc->set_rx_owner(p + entry); + wmb(); } } diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 39ea0674dcd..5c120189ec8 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -46,7 +46,13 @@ static int mdio_mux_read(struct mii_bus *bus, int phy_id, int regnum) struct mdio_mux_parent_bus *pb = cb->parent; int r; - mutex_lock(&pb->mii_bus->mdio_lock); + /* In theory multiple mdio_mux could be stacked, thus creating + * more than a single level of nesting. But in practice, + * SINGLE_DEPTH_NESTING will cover the vast majority of use + * cases. We use it, instead of trying to handle the general + * case. + */ + mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING); r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); if (r) goto out; @@ -71,7 +77,7 @@ static int mdio_mux_write(struct mii_bus *bus, int phy_id, int r; - mutex_lock(&pb->mii_bus->mdio_lock); + mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING); r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); if (r) goto out; diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index b01960fcfbc..a051cedd64b 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -346,6 +346,15 @@ static const struct driver_info qmi_wwan_force_int1 = { .data = BIT(1), /* interface whitelist bitmap */ }; +static const struct driver_info qmi_wwan_force_int2 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(2), /* interface whitelist bitmap */ +}; + static const struct driver_info qmi_wwan_force_int3 = { .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, @@ -498,6 +507,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE MF60 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x1402, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int2, + }, { /* Sierra Wireless MC77xx in QMI mode */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x1199, diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index f1f8bd09bd8..c8baf020c20 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1072,7 +1072,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { - bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); + bounce_skb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 509301a5e7e..ff5d689e13f 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -3405,7 +3405,7 @@ il4965_remove_dynamic_key(struct il_priv *il, return 0; } - if (il->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) { + if (il->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_INVALID) { IL_WARN("Removing wrong key %d 0x%x\n", keyconf->keyidx, key_flags); spin_unlock_irqrestore(&il->sta_lock, flags); @@ -3420,7 +3420,7 @@ il4965_remove_dynamic_key(struct il_priv *il, memset(&il->stations[sta_id].sta.key, 0, sizeof(struct il4965_keyinfo)); il->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; - il->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; + il->stations[sta_id].sta.key.key_offset = keyconf->hw_key_idx; il->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; il->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index cbf2dc18341..5d4807c2b56 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -4767,14 +4767,12 @@ il_bg_watchdog(unsigned long data) return; /* monitor and check for other stuck queues */ - if (il_is_any_associated(il)) { - for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { - /* skip as we already checked the command queue */ - if (cnt == il->cmd_queue) - continue; - if (il_check_stuck_queue(il, cnt)) - return; - } + for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { + /* skip as we already checked the command queue */ + if (cnt == il->cmd_queue) + continue; + if (il_check_stuck_queue(il, cnt)) + return; } mod_timer(&il->watchdog, diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ce61b6fae1c..5c7fd185373 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -958,6 +958,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, case NL80211_HIDDEN_SSID_ZERO_CONTENTS: /* firmware doesn't support this type of hidden SSID */ default: + kfree(bss_cfg); return -EINVAL; } diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index d357d1ed92f..74ecc33fdd9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -436,8 +436,8 @@ void rt2x00usb_kick_queue(struct data_queue *queue) case QID_RX: if (!rt2x00queue_full(queue)) rt2x00queue_for_each_entry(queue, - Q_INDEX_DONE, Q_INDEX, + Q_INDEX_DONE, NULL, rt2x00usb_kick_rx_entry); break; diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c index efc4b7f308c..f3cfa0b9adf 100644 --- a/drivers/oprofile/oprofile_perf.c +++ b/drivers/oprofile/oprofile_perf.c @@ -1,5 +1,6 @@ /* * Copyright 2010 ARM Ltd. + * Copyright 2012 Advanced Micro Devices, Inc., Robert Richter * * Perf-events backend for OProfile. */ @@ -25,7 +26,7 @@ static int oprofile_perf_enabled; static DEFINE_MUTEX(oprofile_perf_mutex); static struct op_counter_config *counter_config; -static struct perf_event **perf_events[NR_CPUS]; +static DEFINE_PER_CPU(struct perf_event **, perf_events); static int num_counters; /* @@ -38,7 +39,7 @@ static void op_overflow_handler(struct perf_event *event, u32 cpu = smp_processor_id(); for (id = 0; id < num_counters; ++id) - if (perf_events[cpu][id] == event) + if (per_cpu(perf_events, cpu)[id] == event) break; if (id != num_counters) @@ -74,7 +75,7 @@ static int op_create_counter(int cpu, int event) { struct perf_event *pevent; - if (!counter_config[event].enabled || perf_events[cpu][event]) + if (!counter_config[event].enabled || per_cpu(perf_events, cpu)[event]) return 0; pevent = perf_event_create_kernel_counter(&counter_config[event].attr, @@ -91,18 +92,18 @@ static int op_create_counter(int cpu, int event) return -EBUSY; } - perf_events[cpu][event] = pevent; + per_cpu(perf_events, cpu)[event] = pevent; return 0; } static void op_destroy_counter(int cpu, int event) { - struct perf_event *pevent = perf_events[cpu][event]; + struct perf_event *pevent = per_cpu(perf_events, cpu)[event]; if (pevent) { perf_event_release_kernel(pevent); - perf_events[cpu][event] = NULL; + per_cpu(perf_events, cpu)[event] = NULL; } } @@ -257,12 +258,12 @@ void oprofile_perf_exit(void) for_each_possible_cpu(cpu) { for (id = 0; id < num_counters; ++id) { - event = perf_events[cpu][id]; + event = per_cpu(perf_events, cpu)[id]; if (event) perf_event_release_kernel(event); } - kfree(perf_events[cpu]); + kfree(per_cpu(perf_events, cpu)); } kfree(counter_config); @@ -277,8 +278,6 @@ int __init oprofile_perf_init(struct oprofile_operations *ops) if (ret) return ret; - memset(&perf_events, 0, sizeof(perf_events)); - num_counters = perf_num_counters(); if (num_counters <= 0) { pr_info("oprofile: no performance counters\n"); @@ -298,9 +297,9 @@ int __init oprofile_perf_init(struct oprofile_operations *ops) } for_each_possible_cpu(cpu) { - perf_events[cpu] = kcalloc(num_counters, + per_cpu(perf_events, cpu) = kcalloc(num_counters, sizeof(struct perf_event *), GFP_KERNEL); - if (!perf_events[cpu]) { + if (!per_cpu(perf_events, cpu)) { pr_info("oprofile: failed to allocate %d perf events " "for cpu %d\n", num_counters, cpu); ret = -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c index dd6d93aa533..90c837f469a 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/pinctrl-imx.c @@ -474,7 +474,9 @@ static int __devinit imx_pinctrl_parse_groups(struct device_node *np, grp->configs[j] = config & ~IMX_PAD_SION; } +#ifdef DEBUG IMX_PMX_DUMP(info, grp->pins, grp->mux_mode, grp->configs, grp->npins); +#endif return 0; } diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/pinctrl-imx6q.c index 7737d4d71a3..e9bf71fbedc 100644 --- a/drivers/pinctrl/pinctrl-imx6q.c +++ b/drivers/pinctrl/pinctrl-imx6q.c @@ -1950,6 +1950,8 @@ static struct imx_pin_reg imx6q_pin_regs[] = { IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__GPIO_1_12 */ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__SJC_DONE */ IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__ANATOP_TESTO_3 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 0, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__ANATOP_USBOTG_ID */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_1__ANATOP_USBOTG_ID */ }; /* Pad names for the pinmux subsystem */ diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 4f20f8dd3d7..17f6dfd8dbf 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -694,10 +694,10 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); static int __devinit ideapad_acpi_add(struct acpi_device *adevice) { int ret, i; - unsigned long cfg; + int cfg; struct ideapad_private *priv; - if (read_method_int(adevice->handle, "_CFG", (int *)&cfg)) + if (read_method_int(adevice->handle, "_CFG", &cfg)) return -ENODEV; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -721,7 +721,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) goto input_failed; for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { - if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg)) + if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) ideapad_register_rfkill(adevice, i); else priv->rfk[i] = NULL; diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index bd89f3c8e76..5051aa970e0 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -72,6 +72,7 @@ #include <linux/string.h> #include <linux/tick.h> #include <linux/timer.h> +#include <linux/dmi.h> #include <drm/i915_drm.h> #include <asm/msr.h> #include <asm/processor.h> @@ -1485,6 +1486,24 @@ static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = { MODULE_DEVICE_TABLE(pci, ips_id_table); +static int ips_blacklist_callback(const struct dmi_system_id *id) +{ + pr_info("Blacklisted intel_ips for %s\n", id->ident); + return 1; +} + +static const struct dmi_system_id ips_blacklist[] = { + { + .callback = ips_blacklist_callback, + .ident = "HP ProBook", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook"), + }, + }, + { } /* terminating entry */ +}; + static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) { u64 platform_info; @@ -1494,6 +1513,9 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) u16 htshi, trc, trc_required_mask; u8 tse; + if (dmi_check_system(ips_blacklist)) + return -ENODEV; + ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL); if (!ips) return -ENOMEM; diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index c7a23624078..9363969ad07 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -973,7 +973,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count) { - unsigned long value = 0; + int value; int ret = 0; struct sony_nc_value *item = container_of(attr, struct sony_nc_value, devattr); @@ -984,7 +984,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, if (count > 31) return -EINVAL; - if (kstrtoul(buffer, 10, &value)) + if (kstrtoint(buffer, 10, &value)) return -EINVAL; if (item->validate) @@ -994,7 +994,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, return value; ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, - (int *)&value, NULL); + &value, NULL); if (ret < 0) return -EIO; @@ -1010,6 +1010,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, struct sony_backlight_props { struct backlight_device *dev; int handle; + int cmd_base; u8 offset; u8 maxlvl; }; @@ -1037,7 +1038,7 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd) struct sony_backlight_props *sdev = (struct sony_backlight_props *)bl_get_data(bd); - sony_call_snc_handle(sdev->handle, 0x0200, &result); + sony_call_snc_handle(sdev->handle, sdev->cmd_base + 0x100, &result); return (result & 0xff) - sdev->offset; } @@ -1049,7 +1050,8 @@ static int sony_nc_update_status_ng(struct backlight_device *bd) (struct sony_backlight_props *)bl_get_data(bd); value = bd->props.brightness + sdev->offset; - if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result)) + if (sony_call_snc_handle(sdev->handle, sdev->cmd_base | (value << 0x10), + &result)) return -EIO; return value; @@ -1172,6 +1174,11 @@ static int sony_nc_hotkeys_decode(u32 event, unsigned int handle) /* * ACPI callbacks */ +enum event_types { + HOTKEY = 1, + KILLSWITCH, + GFX_SWITCH +}; static void sony_nc_notify(struct acpi_device *device, u32 event) { u32 real_ev = event; @@ -1196,7 +1203,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) /* hotkey event */ case 0x0100: case 0x0127: - ev_type = 1; + ev_type = HOTKEY; real_ev = sony_nc_hotkeys_decode(event, handle); if (real_ev > 0) @@ -1216,7 +1223,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) * update the rfkill device status when the * switch is moved. */ - ev_type = 2; + ev_type = KILLSWITCH; sony_call_snc_handle(handle, 0x0100, &result); real_ev = result & 0x03; @@ -1226,6 +1233,24 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) break; + case 0x0128: + case 0x0146: + /* Hybrid GFX switching */ + sony_call_snc_handle(handle, 0x0000, &result); + dprintk("GFX switch event received (reason: %s)\n", + (result & 0x01) ? + "switch change" : "unknown"); + + /* verify the switch state + * 1: discrete GFX + * 0: integrated GFX + */ + sony_call_snc_handle(handle, 0x0100, &result); + + ev_type = GFX_SWITCH; + real_ev = result & 0xff; + break; + default: dprintk("Unknown event 0x%x for handle 0x%x\n", event, handle); @@ -1238,7 +1263,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) } else { /* old style event */ - ev_type = 1; + ev_type = HOTKEY; sony_laptop_report_input_event(real_ev); } @@ -1895,32 +1920,33 @@ static ssize_t sony_nc_battery_care_limit_store(struct device *dev, * bits 4,5: store the limit into the EC * bits 6,7: store the limit into the battery */ + cmd = 0; - /* - * handle 0x0115 should allow storing on battery too; - * handle 0x0136 same as 0x0115 + health status; - * handle 0x013f, same as 0x0136 but no storing on the battery - * - * Store only inside the EC for now, regardless the handle number - */ - if (value == 0) - /* disable limits */ - cmd = 0x0; + if (value > 0) { + if (value <= 50) + cmd = 0x20; - else if (value <= 50) - cmd = 0x21; + else if (value <= 80) + cmd = 0x10; - else if (value <= 80) - cmd = 0x11; + else if (value <= 100) + cmd = 0x30; - else if (value <= 100) - cmd = 0x31; + else + return -EINVAL; - else - return -EINVAL; + /* + * handle 0x0115 should allow storing on battery too; + * handle 0x0136 same as 0x0115 + health status; + * handle 0x013f, same as 0x0136 but no storing on the battery + */ + if (bcare_ctl->handle != 0x013f) + cmd = cmd | (cmd << 2); - if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100, - &result)) + cmd = (cmd | 0x1) << 0x10; + } + + if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result)) return -EIO; return count; @@ -2115,7 +2141,7 @@ static ssize_t sony_nc_thermal_mode_show(struct device *dev, struct device_attribute *attr, char *buffer) { ssize_t count = 0; - unsigned int mode = sony_nc_thermal_mode_get(); + int mode = sony_nc_thermal_mode_get(); if (mode < 0) return mode; @@ -2474,6 +2500,7 @@ static void sony_nc_backlight_ng_read_limits(int handle, { u64 offset; int i; + int lvl_table_len = 0; u8 min = 0xff, max = 0x00; unsigned char buffer[32] = { 0 }; @@ -2482,8 +2509,6 @@ static void sony_nc_backlight_ng_read_limits(int handle, props->maxlvl = 0xff; offset = sony_find_snc_handle(handle); - if (offset < 0) - return; /* try to read the boundaries from ACPI tables, if we fail the above * defaults should be reasonable @@ -2493,11 +2518,21 @@ static void sony_nc_backlight_ng_read_limits(int handle, if (i < 0) return; + switch (handle) { + case 0x012f: + case 0x0137: + lvl_table_len = 9; + break; + case 0x143: + lvl_table_len = 16; + break; + } + /* the buffer lists brightness levels available, brightness levels are * from position 0 to 8 in the array, other values are used by ALS * control. */ - for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) { + for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) { dprintk("Brightness level: %d\n", buffer[i]); @@ -2522,16 +2557,24 @@ static void sony_nc_backlight_setup(void) const struct backlight_ops *ops = NULL; struct backlight_properties props; - if (sony_find_snc_handle(0x12f) != -1) { + if (sony_find_snc_handle(0x12f) >= 0) { ops = &sony_backlight_ng_ops; + sony_bl_props.cmd_base = 0x0100; sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; - } else if (sony_find_snc_handle(0x137) != -1) { + } else if (sony_find_snc_handle(0x137) >= 0) { ops = &sony_backlight_ng_ops; + sony_bl_props.cmd_base = 0x0100; sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props); max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; + } else if (sony_find_snc_handle(0x143) >= 0) { + ops = &sony_backlight_ng_ops; + sony_bl_props.cmd_base = 0x3000; + sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; + } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &unused))) { ops = &sony_backlight_ops; @@ -2599,6 +2642,12 @@ static int sony_nc_add(struct acpi_device *device) } } + result = sony_laptop_setup_input(device); + if (result) { + pr_err("Unable to create input devices\n"); + goto outplatform; + } + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", &handle))) { int arg = 1; @@ -2616,12 +2665,6 @@ static int sony_nc_add(struct acpi_device *device) } /* setup input devices and helper fifo */ - result = sony_laptop_setup_input(device); - if (result) { - pr_err("Unable to create input devices\n"); - goto outsnc; - } - if (acpi_video_backlight_support()) { pr_info("brightness ignored, must be controlled by ACPI video driver\n"); } else { @@ -2669,22 +2712,21 @@ static int sony_nc_add(struct acpi_device *device) return 0; - out_sysfs: +out_sysfs: for (item = sony_nc_values; item->name; ++item) { device_remove_file(&sony_pf_device->dev, &item->devattr); } sony_nc_backlight_cleanup(); - - sony_laptop_remove_input(); - - outsnc: sony_nc_function_cleanup(sony_pf_device); sony_nc_handles_cleanup(sony_pf_device); - outpresent: +outplatform: + sony_laptop_remove_input(); + +outpresent: sony_pf_remove(); - outwalk: +outwalk: sony_nc_rfkill_cleanup(); return result; } diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c86b8864e41..f34c3be6c9f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -20,6 +20,7 @@ menuconfig REGULATOR If unsure, say no. + if REGULATOR config REGULATOR_DEBUG @@ -88,6 +89,13 @@ config REGULATOR_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the regulator driver. +config REGULATOR_ARIZONA + tristate "Wolfson Arizona class devices" + depends on MFD_ARIZONA + help + Support for the regulators found on Wolfson Arizona class + devices. + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X @@ -195,6 +203,14 @@ config REGULATOR_MAX8998 via I2C bus. The provided regulator is suitable for S3C6410 and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_MAX77686 + tristate "Maxim 77686 regulator" + depends on MFD_MAX77686 + help + This driver controls a Maxim 77686 regulator + via I2C bus. The provided regulator is suitable for + Exynos-4 chips to control VARM and VINT voltages. + config REGULATOR_PCAP tristate "Motorola PCAP2 regulator driver" depends on EZX_PCAP @@ -216,6 +232,19 @@ config REGULATOR_LP3972 Say Y here to support the voltage regulators and convertors on National Semiconductors LP3972 PMIC +config REGULATOR_LP872X + bool "TI/National Semiconductor LP8720/LP8725 voltage regulators" + depends on I2C=y + select REGMAP_I2C + help + This driver supports LP8720/LP8725 PMIC + +config REGULATOR_LP8788 + bool "TI LP8788 Power Regulators" + depends on MFD_LP8788 + help + This driver supports LP8788 voltage regulator chip. + config REGULATOR_PCF50633 tristate "NXP PCF50633 regulator driver" depends on MFD_PCF50633 @@ -233,6 +262,14 @@ config REGULATOR_RC5T583 through regulator interface. The device supports multiple DCDC/LDO outputs which can be controlled by i2c communication. +config REGULATOR_S2MPS11 + tristate "Samsung S2MPS11 voltage regulator" + depends on MFD_SEC_CORE + help + This driver supports a Samsung S2MPS11 voltage output regulator + via I2C bus. S2MPS11 is comprised of high efficient Buck converters + including Dual-Phase Buck converter, Buck-Boost converter, various LDOs. + config REGULATOR_S5M8767 tristate "Samsung S5M8767A voltage regulator" depends on MFD_S5M_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 977fd46909a..3342615cf25 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o +obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o @@ -23,6 +24,9 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o +obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o +obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o +obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o @@ -30,6 +34,7 @@ obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o +obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o @@ -37,6 +42,7 @@ obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o +obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 06776ca945f..6f45bfd22e8 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -33,11 +33,6 @@ struct aat2870_regulator { struct aat2870_data *aat2870; struct regulator_desc desc; - const int *voltages; /* uV */ - - int min_uV; - int max_uV; - u8 enable_addr; u8 enable_shift; u8 enable_mask; @@ -47,14 +42,6 @@ struct aat2870_regulator { u8 voltage_mask; }; -static int aat2870_ldo_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - - return ri->voltages[selector]; -} - static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { @@ -111,7 +98,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev) } static struct regulator_ops aat2870_ldo_ops = { - .list_voltage = aat2870_ldo_list_voltage, + .list_voltage = regulator_list_voltage_table, .set_voltage_sel = aat2870_ldo_set_voltage_sel, .get_voltage_sel = aat2870_ldo_get_voltage_sel, .enable = aat2870_ldo_enable, @@ -119,7 +106,7 @@ static struct regulator_ops aat2870_ldo_ops = { .is_enabled = aat2870_ldo_is_enabled, }; -static const int aat2870_ldo_voltages[] = { +static const unsigned int aat2870_ldo_voltages[] = { 1200000, 1300000, 1500000, 1600000, 1800000, 2000000, 2200000, 2500000, 2600000, 2700000, 2800000, 2900000, @@ -132,13 +119,11 @@ static const int aat2870_ldo_voltages[] = { .name = #ids, \ .id = AAT2870_ID_##ids, \ .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ + .volt_table = aat2870_ldo_voltages, \ .ops = &aat2870_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ - .voltages = aat2870_ldo_voltages, \ - .min_uV = 1200000, \ - .max_uV = 3300000, \ } static struct aat2870_regulator aat2870_regulators[] = { diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 03f4d9c604e..182b553059c 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -43,20 +43,12 @@ * @dev: handle to the device * @plfdata: AB3100 platform data passed in at probe time * @regreg: regulator register number in the AB3100 - * @fixed_voltage: a fixed voltage for this regulator, if this - * 0 the voltages array is used instead. - * @typ_voltages: an array of available typical voltages for - * this regulator - * @voltages_len: length of the array of available voltages */ struct ab3100_regulator { struct regulator_dev *rdev; struct device *dev; struct ab3100_platform_data *plfdata; u8 regreg; - int fixed_voltage; - int const *typ_voltages; - u8 voltages_len; }; /* The order in which registers are initialized */ @@ -80,7 +72,7 @@ static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = { #define LDO_C_VOLTAGE 2650000 #define LDO_D_VOLTAGE 2650000 -static const int ldo_e_buck_typ_voltages[] = { +static const unsigned int ldo_e_buck_typ_voltages[] = { 1800000, 1400000, 1300000, @@ -90,7 +82,7 @@ static const int ldo_e_buck_typ_voltages[] = { 900000, }; -static const int ldo_f_typ_voltages[] = { +static const unsigned int ldo_f_typ_voltages[] = { 1800000, 1400000, 1300000, @@ -101,21 +93,21 @@ static const int ldo_f_typ_voltages[] = { 2650000, }; -static const int ldo_g_typ_voltages[] = { +static const unsigned int ldo_g_typ_voltages[] = { 2850000, 2750000, 1800000, 1500000, }; -static const int ldo_h_typ_voltages[] = { +static const unsigned int ldo_h_typ_voltages[] = { 2750000, 1800000, 1500000, 1200000, }; -static const int ldo_k_typ_voltages[] = { +static const unsigned int ldo_k_typ_voltages[] = { 2750000, 1800000, }; @@ -126,40 +118,27 @@ static struct ab3100_regulator ab3100_regulators[AB3100_NUM_REGULATORS] = { { .regreg = AB3100_LDO_A, - .fixed_voltage = LDO_A_VOLTAGE, }, { .regreg = AB3100_LDO_C, - .fixed_voltage = LDO_C_VOLTAGE, }, { .regreg = AB3100_LDO_D, - .fixed_voltage = LDO_D_VOLTAGE, }, { .regreg = AB3100_LDO_E, - .typ_voltages = ldo_e_buck_typ_voltages, - .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages), }, { .regreg = AB3100_LDO_F, - .typ_voltages = ldo_f_typ_voltages, - .voltages_len = ARRAY_SIZE(ldo_f_typ_voltages), }, { .regreg = AB3100_LDO_G, - .typ_voltages = ldo_g_typ_voltages, - .voltages_len = ARRAY_SIZE(ldo_g_typ_voltages), }, { .regreg = AB3100_LDO_H, - .typ_voltages = ldo_h_typ_voltages, - .voltages_len = ARRAY_SIZE(ldo_h_typ_voltages), }, { .regreg = AB3100_LDO_K, - .typ_voltages = ldo_k_typ_voltages, - .voltages_len = ARRAY_SIZE(ldo_k_typ_voltages), }, { .regreg = AB3100_LDO_EXT, @@ -167,8 +146,6 @@ ab3100_regulators[AB3100_NUM_REGULATORS] = { }, { .regreg = AB3100_BUCK, - .typ_voltages = ldo_e_buck_typ_voltages, - .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages), }, }; @@ -178,7 +155,7 @@ ab3100_regulators[AB3100_NUM_REGULATORS] = { */ static int ab3100_enable_regulator(struct regulator_dev *reg) { - struct ab3100_regulator *abreg = reg->reg_data; + struct ab3100_regulator *abreg = rdev_get_drvdata(reg); int err; u8 regval; @@ -209,7 +186,7 @@ static int ab3100_enable_regulator(struct regulator_dev *reg) static int ab3100_disable_regulator(struct regulator_dev *reg) { - struct ab3100_regulator *abreg = reg->reg_data; + struct ab3100_regulator *abreg = rdev_get_drvdata(reg); int err; u8 regval; @@ -242,7 +219,7 @@ static int ab3100_disable_regulator(struct regulator_dev *reg) static int ab3100_is_enabled_regulator(struct regulator_dev *reg) { - struct ab3100_regulator *abreg = reg->reg_data; + struct ab3100_regulator *abreg = rdev_get_drvdata(reg); u8 regval; int err; @@ -257,26 +234,12 @@ static int ab3100_is_enabled_regulator(struct regulator_dev *reg) return regval & AB3100_REG_ON_MASK; } -static int ab3100_list_voltage_regulator(struct regulator_dev *reg, - unsigned selector) -{ - struct ab3100_regulator *abreg = reg->reg_data; - - if (selector >= abreg->voltages_len) - return -EINVAL; - return abreg->typ_voltages[selector]; -} - static int ab3100_get_voltage_regulator(struct regulator_dev *reg) { - struct ab3100_regulator *abreg = reg->reg_data; + struct ab3100_regulator *abreg = rdev_get_drvdata(reg); u8 regval; int err; - /* Return the voltage for fixed regulators immediately */ - if (abreg->fixed_voltage) - return abreg->fixed_voltage; - /* * For variable types, read out setting and index into * supplied voltage list. @@ -294,20 +257,20 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg) regval &= 0xE0; regval >>= 5; - if (regval >= abreg->voltages_len) { + if (regval >= reg->desc->n_voltages) { dev_err(®->dev, "regulator register %02x contains an illegal voltage setting\n", abreg->regreg); return -EINVAL; } - return abreg->typ_voltages[regval]; + return reg->desc->volt_table[regval]; } static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg, unsigned selector) { - struct ab3100_regulator *abreg = reg->reg_data; + struct ab3100_regulator *abreg = rdev_get_drvdata(reg); u8 regval; int err; @@ -336,7 +299,7 @@ static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg, static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg, int uV) { - struct ab3100_regulator *abreg = reg->reg_data; + struct ab3100_regulator *abreg = rdev_get_drvdata(reg); u8 regval; int err; int bestindex; @@ -379,42 +342,22 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg, */ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg) { - struct ab3100_regulator *abreg = reg->reg_data; + struct ab3100_regulator *abreg = rdev_get_drvdata(reg); return abreg->plfdata->external_voltage; } -static int ab3100_enable_time_regulator(struct regulator_dev *reg) +static int ab3100_get_fixed_voltage_regulator(struct regulator_dev *reg) { - struct ab3100_regulator *abreg = reg->reg_data; - - /* Per-regulator power on delay from spec */ - switch (abreg->regreg) { - case AB3100_LDO_A: /* Fallthrough */ - case AB3100_LDO_C: /* Fallthrough */ - case AB3100_LDO_D: /* Fallthrough */ - case AB3100_LDO_E: /* Fallthrough */ - case AB3100_LDO_H: /* Fallthrough */ - case AB3100_LDO_K: - return 200; - case AB3100_LDO_F: - return 600; - case AB3100_LDO_G: - return 400; - case AB3100_BUCK: - return 1000; - default: - break; - } - return 0; + return reg->desc->min_uV; } static struct regulator_ops regulator_ops_fixed = { + .list_voltage = regulator_list_voltage_linear, .enable = ab3100_enable_regulator, .disable = ab3100_disable_regulator, .is_enabled = ab3100_is_enabled_regulator, - .get_voltage = ab3100_get_voltage_regulator, - .enable_time = ab3100_enable_time_regulator, + .get_voltage = ab3100_get_fixed_voltage_regulator, }; static struct regulator_ops regulator_ops_variable = { @@ -423,8 +366,7 @@ static struct regulator_ops regulator_ops_variable = { .is_enabled = ab3100_is_enabled_regulator, .get_voltage = ab3100_get_voltage_regulator, .set_voltage_sel = ab3100_set_voltage_regulator_sel, - .list_voltage = ab3100_list_voltage_regulator, - .enable_time = ab3100_enable_time_regulator, + .list_voltage = regulator_list_voltage_table, }; static struct regulator_ops regulator_ops_variable_sleepable = { @@ -434,8 +376,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = { .get_voltage = ab3100_get_voltage_regulator, .set_voltage_sel = ab3100_set_voltage_regulator_sel, .set_suspend_voltage = ab3100_set_suspend_voltage_regulator, - .list_voltage = ab3100_list_voltage_regulator, - .enable_time = ab3100_enable_time_regulator, + .list_voltage = regulator_list_voltage_table, }; /* @@ -457,62 +398,81 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { .name = "LDO_A", .id = AB3100_LDO_A, .ops = ®ulator_ops_fixed, + .n_voltages = 1, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .min_uV = LDO_A_VOLTAGE, + .enable_time = 200, }, { .name = "LDO_C", .id = AB3100_LDO_C, .ops = ®ulator_ops_fixed, + .n_voltages = 1, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .min_uV = LDO_C_VOLTAGE, + .enable_time = 200, }, { .name = "LDO_D", .id = AB3100_LDO_D, .ops = ®ulator_ops_fixed, + .n_voltages = 1, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .min_uV = LDO_D_VOLTAGE, + .enable_time = 200, }, { .name = "LDO_E", .id = AB3100_LDO_E, .ops = ®ulator_ops_variable_sleepable, .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages), + .volt_table = ldo_e_buck_typ_voltages, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .enable_time = 200, }, { .name = "LDO_F", .id = AB3100_LDO_F, .ops = ®ulator_ops_variable, .n_voltages = ARRAY_SIZE(ldo_f_typ_voltages), + .volt_table = ldo_f_typ_voltages, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .enable_time = 600, }, { .name = "LDO_G", .id = AB3100_LDO_G, .ops = ®ulator_ops_variable, .n_voltages = ARRAY_SIZE(ldo_g_typ_voltages), + .volt_table = ldo_g_typ_voltages, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .enable_time = 400, }, { .name = "LDO_H", .id = AB3100_LDO_H, .ops = ®ulator_ops_variable, .n_voltages = ARRAY_SIZE(ldo_h_typ_voltages), + .volt_table = ldo_h_typ_voltages, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .enable_time = 200, }, { .name = "LDO_K", .id = AB3100_LDO_K, .ops = ®ulator_ops_variable, .n_voltages = ARRAY_SIZE(ldo_k_typ_voltages), + .volt_table = ldo_k_typ_voltages, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .enable_time = 200, }, { .name = "LDO_EXT", @@ -528,6 +488,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .enable_time = 1000, }, }; diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index a739f5ca936..13d424fc1c1 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -30,9 +30,6 @@ * @dev: device pointer * @desc: regulator description * @regulator_dev: regulator device - * @max_uV: maximum voltage (for variable voltage supplies) - * @min_uV: minimum voltage (for variable voltage supplies) - * @fixed_uV: typical voltage (for fixed voltage supplies) * @update_bank: bank to control on/off * @update_reg: register to control on/off * @update_mask: mask to enable/disable regulator @@ -40,17 +37,12 @@ * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage - * @voltages: supported voltage table - * @voltages_len: number of supported voltages for the regulator * @delay: startup/set voltage delay in us */ struct ab8500_regulator_info { struct device *dev; struct regulator_desc desc; struct regulator_dev *regulator; - int max_uV; - int min_uV; - int fixed_uV; u8 update_bank; u8 update_reg; u8 update_mask; @@ -58,13 +50,11 @@ struct ab8500_regulator_info { u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; - int const *voltages; - int voltages_len; unsigned int delay; }; /* voltage tables for the vauxn/vintcore supplies */ -static const int ldo_vauxn_voltages[] = { +static const unsigned int ldo_vauxn_voltages[] = { 1100000, 1200000, 1300000, @@ -83,7 +73,7 @@ static const int ldo_vauxn_voltages[] = { 3300000, }; -static const int ldo_vaux3_voltages[] = { +static const unsigned int ldo_vaux3_voltages[] = { 1200000, 1500000, 1800000, @@ -94,7 +84,7 @@ static const int ldo_vaux3_voltages[] = { 2910000, }; -static const int ldo_vintcore_voltages[] = { +static const unsigned int ldo_vintcore_voltages[] = { 1200000, 1225000, 1250000, @@ -185,25 +175,6 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) return false; } -static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) -{ - struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - - if (info == NULL) { - dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); - return -EINVAL; - } - - /* return the uV for the fixed regulators */ - if (info->fixed_uV) - return info->fixed_uV; - - if (selector >= info->voltages_len) - return -EINVAL; - - return info->voltages[selector]; -} - static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) { int ret, val; @@ -279,14 +250,7 @@ static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int new_sel) { struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - int ret; - /* If the regulator isn't on, it won't take time here */ - ret = ab8500_regulator_is_enabled(rdev); - if (ret < 0) - return ret; - if (!ret) - return 0; return info->delay; } @@ -296,21 +260,14 @@ static struct regulator_ops ab8500_regulator_ops = { .is_enabled = ab8500_regulator_is_enabled, .get_voltage_sel = ab8500_regulator_get_voltage_sel, .set_voltage_sel = ab8500_regulator_set_voltage_sel, - .list_voltage = ab8500_list_voltage, + .list_voltage = regulator_list_voltage_table, .enable_time = ab8500_regulator_enable_time, .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, }; static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) { - struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - - if (info == NULL) { - dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); - return -EINVAL; - } - - return info->fixed_uV; + return rdev->desc->min_uV; } static struct regulator_ops ab8500_regulator_fixed_ops = { @@ -318,9 +275,8 @@ static struct regulator_ops ab8500_regulator_fixed_ops = { .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, .get_voltage = ab8500_fixed_get_voltage, - .list_voltage = ab8500_list_voltage, + .list_voltage = regulator_list_voltage_linear, .enable_time = ab8500_regulator_enable_time, - .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, }; static struct ab8500_regulator_info @@ -329,7 +285,7 @@ static struct ab8500_regulator_info * Variable Voltage Regulators * name, min mV, max mV, * update bank, reg, mask, enable val - * volt bank, reg, mask, table, table length + * volt bank, reg, mask */ [AB8500_LDO_AUX1] = { .desc = { @@ -339,9 +295,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_AUX1, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, }, - .min_uV = 1100000, - .max_uV = 3300000, .update_bank = 0x04, .update_reg = 0x09, .update_mask = 0x03, @@ -349,8 +304,6 @@ static struct ab8500_regulator_info .voltage_bank = 0x04, .voltage_reg = 0x1f, .voltage_mask = 0x0f, - .voltages = ldo_vauxn_voltages, - .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), }, [AB8500_LDO_AUX2] = { .desc = { @@ -360,9 +313,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_AUX2, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, }, - .min_uV = 1100000, - .max_uV = 3300000, .update_bank = 0x04, .update_reg = 0x09, .update_mask = 0x0c, @@ -370,8 +322,6 @@ static struct ab8500_regulator_info .voltage_bank = 0x04, .voltage_reg = 0x20, .voltage_mask = 0x0f, - .voltages = ldo_vauxn_voltages, - .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), }, [AB8500_LDO_AUX3] = { .desc = { @@ -381,9 +331,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_AUX3, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), + .volt_table = ldo_vaux3_voltages, }, - .min_uV = 1100000, - .max_uV = 3300000, .update_bank = 0x04, .update_reg = 0x0a, .update_mask = 0x03, @@ -391,8 +340,6 @@ static struct ab8500_regulator_info .voltage_bank = 0x04, .voltage_reg = 0x21, .voltage_mask = 0x07, - .voltages = ldo_vaux3_voltages, - .voltages_len = ARRAY_SIZE(ldo_vaux3_voltages), }, [AB8500_LDO_INTCORE] = { .desc = { @@ -402,9 +349,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_INTCORE, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + .volt_table = ldo_vintcore_voltages, }, - .min_uV = 1100000, - .max_uV = 3300000, .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x44, @@ -412,8 +358,6 @@ static struct ab8500_regulator_info .voltage_bank = 0x03, .voltage_reg = 0x80, .voltage_mask = 0x38, - .voltages = ldo_vintcore_voltages, - .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages), }, /* @@ -429,9 +373,9 @@ static struct ab8500_regulator_info .id = AB8500_LDO_TVOUT, .owner = THIS_MODULE, .n_voltages = 1, + .min_uV = 2000000, }, .delay = 10000, - .fixed_uV = 2000000, .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x82, @@ -445,8 +389,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_USB, .owner = THIS_MODULE, .n_voltages = 1, + .min_uV = 3300000, }, - .fixed_uV = 3300000, .update_bank = 0x03, .update_reg = 0x82, .update_mask = 0x03, @@ -460,8 +404,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_AUDIO, .owner = THIS_MODULE, .n_voltages = 1, + .min_uV = 2000000, }, - .fixed_uV = 2000000, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x02, @@ -475,8 +419,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_ANAMIC1, .owner = THIS_MODULE, .n_voltages = 1, + .min_uV = 2050000, }, - .fixed_uV = 2050000, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x08, @@ -490,8 +434,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_ANAMIC2, .owner = THIS_MODULE, .n_voltages = 1, + .min_uV = 2050000, }, - .fixed_uV = 2050000, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x10, @@ -505,8 +449,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_DMIC, .owner = THIS_MODULE, .n_voltages = 1, + .min_uV = 1800000, }, - .fixed_uV = 1800000, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x04, @@ -520,8 +464,8 @@ static struct ab8500_regulator_info .id = AB8500_LDO_ANA, .owner = THIS_MODULE, .n_voltages = 1, + .min_uV = 1200000, }, - .fixed_uV = 1200000, .update_bank = 0x04, .update_reg = 0x06, .update_mask = 0x0c, @@ -769,9 +713,7 @@ static __devinit int ab8500_regulator_register(struct platform_device *pdev, if (info->desc.id == AB8500_LDO_AUX3) { info->desc.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages); - info->voltages = ldo_vauxn_voltages; - info->voltages_len = - ARRAY_SIZE(ldo_vauxn_voltages); + info->desc.volt_table = ldo_vauxn_voltages; info->voltage_mask = 0xf; } } diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index 46d05f38baf..f123f7e3b75 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -89,9 +89,12 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int unsigned short data; int ret; - if (min_uA > chip->max_uA || min_uA < chip->min_uA) - return -EINVAL; - if (max_uA > chip->max_uA || max_uA < chip->min_uA) + if (min_uA < chip->min_uA) + min_uA = chip->min_uA; + if (max_uA > chip->max_uA) + max_uA = chip->max_uA; + + if (min_uA > chip->max_uA || max_uA < chip->min_uA) return -EINVAL; selector = DIV_ROUND_UP((min_uA - chip->min_uA) * chip->current_level, diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index e82e7eaac0f..e9c2085f9df 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -43,33 +43,15 @@ struct anatop_regulator { struct regulator_init_data *initdata; }; -static int anatop_set_voltage(struct regulator_dev *reg, int min_uV, - int max_uV, unsigned *selector) +static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); - u32 val, sel, mask; - int uv; - - uv = min_uV; - dev_dbg(®->dev, "%s: uv %d, min %d, max %d\n", __func__, - uv, anatop_reg->min_voltage, - anatop_reg->max_voltage); - - if (uv < anatop_reg->min_voltage) { - if (max_uV > anatop_reg->min_voltage) - uv = anatop_reg->min_voltage; - else - return -EINVAL; - } + u32 val, mask; if (!anatop_reg->control_reg) return -ENOTSUPP; - sel = DIV_ROUND_UP(uv - anatop_reg->min_voltage, 25000); - if (sel * 25000 + anatop_reg->min_voltage > anatop_reg->max_voltage) - return -EINVAL; - val = anatop_reg->min_bit_val + sel; - *selector = sel; + val = anatop_reg->min_bit_val + selector; dev_dbg(®->dev, "%s: calculated val %d\n", __func__, val); mask = ((1 << anatop_reg->vol_bit_width) - 1) << anatop_reg->vol_bit_shift; @@ -94,21 +76,11 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg) return val - anatop_reg->min_bit_val; } -static int anatop_list_voltage(struct regulator_dev *reg, unsigned selector) -{ - struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); - int uv; - - uv = anatop_reg->min_voltage + selector * 25000; - dev_dbg(®->dev, "vddio = %d, selector = %u\n", uv, selector); - - return uv; -} - static struct regulator_ops anatop_rops = { - .set_voltage = anatop_set_voltage, + .set_voltage_sel = anatop_set_voltage_sel, .get_voltage_sel = anatop_get_voltage_sel, - .list_voltage = anatop_list_voltage, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, }; static int __devinit anatop_regulator_probe(struct platform_device *pdev) @@ -176,6 +148,8 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1; + rdesc->min_uV = sreg->min_voltage; + rdesc->uV_step = 25000; config.dev = &pdev->dev; config.init_data = initdata; diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c new file mode 100644 index 00000000000..c8f95c07adb --- /dev/null +++ b/drivers/regulator/arizona-ldo1.c @@ -0,0 +1,138 @@ +/* + * arizona-ldo1.c -- LDO1 supply for Arizona devices + * + * Copyright 2012 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 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include <linux/mfd/arizona/core.h> +#include <linux/mfd/arizona/pdata.h> +#include <linux/mfd/arizona/registers.h> + +struct arizona_ldo1 { + struct regulator_dev *regulator; + struct arizona *arizona; + + struct regulator_consumer_supply supply; + struct regulator_init_data init_data; +}; + +static struct regulator_ops arizona_ldo1_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_desc arizona_ldo1 = { + .name = "LDO1", + .supply_name = "LDOVDD", + .type = REGULATOR_VOLTAGE, + .ops = &arizona_ldo1_ops, + + .vsel_reg = ARIZONA_LDO1_CONTROL_1, + .vsel_mask = ARIZONA_LDO1_VSEL_MASK, + .min_uV = 900000, + .uV_step = 50000, + .n_voltages = 7, + + .owner = THIS_MODULE, +}; + +static const struct regulator_init_data arizona_ldo1_default = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, +}; + +static __devinit int arizona_ldo1_probe(struct platform_device *pdev) +{ + struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; + struct arizona_ldo1 *ldo1; + int ret; + + ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); + if (ldo1 == NULL) { + dev_err(&pdev->dev, "Unable to allocate private data\n"); + return -ENOMEM; + } + + ldo1->arizona = arizona; + + /* + * Since the chip usually supplies itself we provide some + * default init_data for it. This will be overridden with + * platform data if provided. + */ + ldo1->init_data = arizona_ldo1_default; + ldo1->init_data.consumer_supplies = &ldo1->supply; + ldo1->supply.supply = "DCVDD"; + ldo1->supply.dev_name = dev_name(arizona->dev); + + config.dev = arizona->dev; + config.driver_data = ldo1; + config.regmap = arizona->regmap; + config.ena_gpio = arizona->pdata.ldoena; + + if (arizona->pdata.ldo1) + config.init_data = arizona->pdata.ldo1; + else + config.init_data = &ldo1->init_data; + + ldo1->regulator = regulator_register(&arizona_ldo1, &config); + if (IS_ERR(ldo1->regulator)) { + ret = PTR_ERR(ldo1->regulator); + dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", + ret); + return ret; + } + + platform_set_drvdata(pdev, ldo1); + + return 0; +} + +static __devexit int arizona_ldo1_remove(struct platform_device *pdev) +{ + struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev); + + regulator_unregister(ldo1->regulator); + + return 0; +} + +static struct platform_driver arizona_ldo1_driver = { + .probe = arizona_ldo1_probe, + .remove = __devexit_p(arizona_ldo1_remove), + .driver = { + .name = "arizona-ldo1", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(arizona_ldo1_driver); + +/* Module information */ +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_DESCRIPTION("Arizona LDO1 driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:arizona-ldo1"); diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c new file mode 100644 index 00000000000..450a069aa9b --- /dev/null +++ b/drivers/regulator/arizona-micsupp.c @@ -0,0 +1,188 @@ +/* + * arizona-micsupp.c -- Microphone supply for Arizona devices + * + * Copyright 2012 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 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include <linux/mfd/arizona/core.h> +#include <linux/mfd/arizona/pdata.h> +#include <linux/mfd/arizona/registers.h> + +#define ARIZONA_MICSUPP_MAX_SELECTOR 0x1f + +struct arizona_micsupp { + struct regulator_dev *regulator; + struct arizona *arizona; + + struct regulator_consumer_supply supply; + struct regulator_init_data init_data; +}; + +static int arizona_micsupp_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector > ARIZONA_MICSUPP_MAX_SELECTOR) + return -EINVAL; + + if (selector == ARIZONA_MICSUPP_MAX_SELECTOR) + return 3300000; + else + return (selector * 50000) + 1700000; +} + +static int arizona_micsupp_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + unsigned int voltage; + int selector; + + if (min_uV < 1700000) + min_uV = 1700000; + + if (min_uV > 3200000) + selector = ARIZONA_MICSUPP_MAX_SELECTOR; + else + selector = DIV_ROUND_UP(min_uV - 1700000, 50000); + + if (selector < 0) + return -EINVAL; + + voltage = arizona_micsupp_list_voltage(rdev, selector); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return selector; +} + +static struct regulator_ops arizona_micsupp_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + + .list_voltage = arizona_micsupp_list_voltage, + .map_voltage = arizona_micsupp_map_voltage, + + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_desc arizona_micsupp = { + .name = "MICVDD", + .supply_name = "CPVDD", + .type = REGULATOR_VOLTAGE, + .n_voltages = ARIZONA_MICSUPP_MAX_SELECTOR + 1, + .ops = &arizona_micsupp_ops, + + .vsel_reg = ARIZONA_LDO2_CONTROL_1, + .vsel_mask = ARIZONA_LDO2_VSEL_MASK, + .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1, + .enable_mask = ARIZONA_CPMIC_ENA, + + .owner = THIS_MODULE, +}; + +static const struct regulator_init_data arizona_micsupp_default = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_VOLTAGE, + .min_uV = 1700000, + .max_uV = 3300000, + }, + + .num_consumer_supplies = 1, +}; + +static __devinit int arizona_micsupp_probe(struct platform_device *pdev) +{ + struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; + struct arizona_micsupp *micsupp; + int ret; + + micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL); + if (micsupp == NULL) { + dev_err(&pdev->dev, "Unable to allocate private data\n"); + return -ENOMEM; + } + + micsupp->arizona = arizona; + + /* + * Since the chip usually supplies itself we provide some + * default init_data for it. This will be overridden with + * platform data if provided. + */ + micsupp->init_data = arizona_micsupp_default; + micsupp->init_data.consumer_supplies = &micsupp->supply; + micsupp->supply.supply = "MICVDD"; + micsupp->supply.dev_name = dev_name(arizona->dev); + + config.dev = arizona->dev; + config.driver_data = micsupp; + config.regmap = arizona->regmap; + + if (arizona->pdata.micvdd) + config.init_data = arizona->pdata.micvdd; + else + config.init_data = &micsupp->init_data; + + /* Default to regulated mode until the API supports bypass */ + regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1, + ARIZONA_CPMIC_BYPASS, 0); + + micsupp->regulator = regulator_register(&arizona_micsupp, &config); + if (IS_ERR(micsupp->regulator)) { + ret = PTR_ERR(micsupp->regulator); + dev_err(arizona->dev, "Failed to register mic supply: %d\n", + ret); + return ret; + } + + platform_set_drvdata(pdev, micsupp); + + return 0; +} + +static __devexit int arizona_micsupp_remove(struct platform_device *pdev) +{ + struct arizona_micsupp *micsupp = platform_get_drvdata(pdev); + + regulator_unregister(micsupp->regulator); + + return 0; +} + +static struct platform_driver arizona_micsupp_driver = { + .probe = arizona_micsupp_probe, + .remove = __devexit_p(arizona_micsupp_remove), + .driver = { + .name = "arizona-micsupp", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(arizona_micsupp_driver); + +/* Module information */ +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_DESCRIPTION("Arizona microphone supply driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:arizona-micsupp"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8b4b3829d9e..2e31dffbefe 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -23,6 +23,7 @@ #include <linux/mutex.h> #include <linux/suspend.h> #include <linux/delay.h> +#include <linux/gpio.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/regulator/of_regulator.h> @@ -108,28 +109,6 @@ static const char *rdev_get_name(struct regulator_dev *rdev) return ""; } -/* gets the regulator for a given consumer device */ -static struct regulator *get_device_regulator(struct device *dev) -{ - struct regulator *regulator = NULL; - struct regulator_dev *rdev; - - mutex_lock(®ulator_list_mutex); - list_for_each_entry(rdev, ®ulator_list, list) { - mutex_lock(&rdev->mutex); - list_for_each_entry(regulator, &rdev->consumer_list, list) { - if (regulator->dev == dev) { - mutex_unlock(&rdev->mutex); - mutex_unlock(®ulator_list_mutex); - return regulator; - } - } - mutex_unlock(&rdev->mutex); - } - mutex_unlock(®ulator_list_mutex); - return NULL; -} - /** * of_get_regulator - get a regulator device node based on supply name * @dev: Device pointer for the consumer (of regulator) device @@ -303,18 +282,6 @@ static int regulator_check_drms(struct regulator_dev *rdev) return 0; } -static ssize_t device_requested_uA_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct regulator *regulator; - - regulator = get_device_regulator(dev); - if (regulator == NULL) - return 0; - - return sprintf(buf, "%d\n", regulator->uA_load); -} - static ssize_t regulator_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -427,6 +394,9 @@ static ssize_t regulator_status_show(struct device *dev, case REGULATOR_STATUS_STANDBY: label = "standby"; break; + case REGULATOR_STATUS_UNDEFINED: + label = "undefined"; + break; default: return -ERANGE; } @@ -967,6 +937,14 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + if (rdev->constraints->ramp_delay && ops->set_ramp_delay) { + ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay); + if (ret < 0) { + rdev_err(rdev, "failed to set ramp_delay\n"); + goto out; + } + } + print_constraints(rdev); return 0; out: @@ -1097,48 +1075,29 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, list_add(®ulator->list, &rdev->consumer_list); if (dev) { - /* create a 'requested_microamps_name' sysfs entry */ - size = scnprintf(buf, REG_STR_SIZE, - "microamps_requested_%s-%s", - dev_name(dev), supply_name); - if (size >= REG_STR_SIZE) - goto overflow_err; - regulator->dev = dev; - sysfs_attr_init(®ulator->dev_attr.attr); - regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL); - if (regulator->dev_attr.attr.name == NULL) - goto attr_name_err; - - regulator->dev_attr.attr.mode = 0444; - regulator->dev_attr.show = device_requested_uA_show; - err = device_create_file(dev, ®ulator->dev_attr); - if (err < 0) { - rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n"); - goto attr_name_err; - } - /* also add a link to the device sysfs entry */ + /* Add a link to the device sysfs entry */ size = scnprintf(buf, REG_STR_SIZE, "%s-%s", dev->kobj.name, supply_name); if (size >= REG_STR_SIZE) - goto attr_err; + goto overflow_err; regulator->supply_name = kstrdup(buf, GFP_KERNEL); if (regulator->supply_name == NULL) - goto attr_err; + goto overflow_err; err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, buf); if (err) { rdev_warn(rdev, "could not add device link %s err %d\n", dev->kobj.name, err); - goto link_name_err; + /* non-fatal */ } } else { regulator->supply_name = kstrdup(supply_name, GFP_KERNEL); if (regulator->supply_name == NULL) - goto attr_err; + goto overflow_err; } regulator->debugfs = debugfs_create_dir(regulator->supply_name, @@ -1165,12 +1124,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, mutex_unlock(&rdev->mutex); return regulator; -link_name_err: - kfree(regulator->supply_name); -attr_err: - device_remove_file(regulator->dev, ®ulator->dev_attr); -attr_name_err: - kfree(regulator->dev_attr.attr.name); overflow_err: list_del(®ulator->list); kfree(regulator); @@ -1181,7 +1134,7 @@ overflow_err: static int _regulator_get_enable_time(struct regulator_dev *rdev) { if (!rdev->desc->ops->enable_time) - return 0; + return rdev->desc->enable_time; return rdev->desc->ops->enable_time(rdev); } @@ -1420,11 +1373,8 @@ void regulator_put(struct regulator *regulator) debugfs_remove_recursive(regulator->debugfs); /* remove any sysfs entries */ - if (regulator->dev) { + if (regulator->dev) sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); - device_remove_file(regulator->dev, ®ulator->dev_attr); - kfree(regulator->dev_attr.attr.name); - } kfree(regulator->supply_name); list_del(®ulator->list); kfree(regulator); @@ -1459,19 +1409,61 @@ void devm_regulator_put(struct regulator *regulator) { int rc; - rc = devres_destroy(regulator->dev, devm_regulator_release, + rc = devres_release(regulator->dev, devm_regulator_release, devm_regulator_match, regulator); - if (rc == 0) - regulator_put(regulator); - else + if (rc != 0) WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_regulator_put); +static int _regulator_do_enable(struct regulator_dev *rdev) +{ + int ret, delay; + + /* Query before enabling in case configuration dependent. */ + ret = _regulator_get_enable_time(rdev); + if (ret >= 0) { + delay = ret; + } else { + rdev_warn(rdev, "enable_time() failed: %d\n", ret); + delay = 0; + } + + trace_regulator_enable(rdev_get_name(rdev)); + + if (rdev->ena_gpio) { + gpio_set_value_cansleep(rdev->ena_gpio, + !rdev->ena_gpio_invert); + rdev->ena_gpio_state = 1; + } else if (rdev->desc->ops->enable) { + ret = rdev->desc->ops->enable(rdev); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + + /* Allow the regulator to ramp; it would be useful to extend + * this for bulk operations so that the regulators can ramp + * together. */ + trace_regulator_enable_delay(rdev_get_name(rdev)); + + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } + + trace_regulator_enable_complete(rdev_get_name(rdev)); + + return 0; +} + /* locks held by regulator_enable() */ static int _regulator_enable(struct regulator_dev *rdev) { - int ret, delay; + int ret; /* check voltage and requested load before enabling */ if (rdev->constraints && @@ -1485,40 +1477,10 @@ static int _regulator_enable(struct regulator_dev *rdev) if (!_regulator_can_change_status(rdev)) return -EPERM; - if (!rdev->desc->ops->enable) - return -EINVAL; - - /* Query before enabling in case configuration - * dependent. */ - ret = _regulator_get_enable_time(rdev); - if (ret >= 0) { - delay = ret; - } else { - rdev_warn(rdev, "enable_time() failed: %d\n", - ret); - delay = 0; - } - - trace_regulator_enable(rdev_get_name(rdev)); - - /* Allow the regulator to ramp; it would be useful - * to extend this for bulk operations so that the - * regulators can ramp together. */ - ret = rdev->desc->ops->enable(rdev); + ret = _regulator_do_enable(rdev); if (ret < 0) return ret; - trace_regulator_enable_delay(rdev_get_name(rdev)); - - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); - } - - trace_regulator_enable_complete(rdev_get_name(rdev)); - } else if (ret < 0) { rdev_err(rdev, "is_enabled() failed: %d\n", ret); return ret; @@ -1567,6 +1529,30 @@ int regulator_enable(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_enable); +static int _regulator_do_disable(struct regulator_dev *rdev) +{ + int ret; + + trace_regulator_disable(rdev_get_name(rdev)); + + if (rdev->ena_gpio) { + gpio_set_value_cansleep(rdev->ena_gpio, + rdev->ena_gpio_invert); + rdev->ena_gpio_state = 0; + + } else if (rdev->desc->ops->disable) { + ret = rdev->desc->ops->disable(rdev); + if (ret != 0) + return ret; + } + + trace_regulator_disable_complete(rdev_get_name(rdev)); + + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, + NULL); + return 0; +} + /* locks held by regulator_disable() */ static int _regulator_disable(struct regulator_dev *rdev) { @@ -1581,20 +1567,12 @@ static int _regulator_disable(struct regulator_dev *rdev) (rdev->constraints && !rdev->constraints->always_on)) { /* we are last user */ - if (_regulator_can_change_status(rdev) && - rdev->desc->ops->disable) { - trace_regulator_disable(rdev_get_name(rdev)); - - ret = rdev->desc->ops->disable(rdev); + if (_regulator_can_change_status(rdev)) { + ret = _regulator_do_disable(rdev); if (ret < 0) { rdev_err(rdev, "failed to disable\n"); return ret; } - - trace_regulator_disable_complete(rdev_get_name(rdev)); - - _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, - NULL); } rdev->use_count = 0; @@ -1812,6 +1790,10 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap); static int _regulator_is_enabled(struct regulator_dev *rdev) { + /* A GPIO control always takes precedence */ + if (rdev->ena_gpio) + return rdev->ena_gpio_state; + /* If we don't know then assume that the regulator is always on */ if (!rdev->desc->ops->is_enabled) return 1; @@ -1883,6 +1865,31 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev, EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); /** + * regulator_list_voltage_table - List voltages with table based mapping + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with table based mapping between voltages and + * selectors can set volt_table in the regulator descriptor + * and then use this function as their list_voltage() operation. + */ +int regulator_list_voltage_table(struct regulator_dev *rdev, + unsigned int selector) +{ + if (!rdev->desc->volt_table) { + BUG_ON(!rdev->desc->volt_table); + return -EINVAL; + } + + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + return rdev->desc->volt_table[selector]; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_table); + +/** * regulator_list_voltage - enumerate supported voltages * @regulator: regulator source * @selector: identify voltage to list @@ -1928,8 +1935,18 @@ EXPORT_SYMBOL_GPL(regulator_list_voltage); int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV) { + struct regulator_dev *rdev = regulator->rdev; int i, voltages, ret; + /* If we can't change voltage check the current voltage */ + if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + ret = regulator_get_voltage(regulator); + if (ret >= 0) + return (min_uV >= ret && ret <= max_uV); + else + return ret; + } + ret = regulator_count_voltages(regulator); if (ret < 0) return ret; @@ -2045,6 +2062,14 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev, { int ret, voltage; + /* Allow uV_step to be 0 for fixed voltage */ + if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) { + if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV) + return 0; + else + return -EINVAL; + } + if (!rdev->desc->uV_step) { BUG_ON(!rdev->desc->uV_step); return -EINVAL; @@ -2071,7 +2096,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, { int ret; int delay = 0; - int best_val; + int best_val = 0; unsigned int selector; int old_selector = -1; @@ -2084,7 +2109,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, * If we can't obtain the old selector there is not enough * info to call set_voltage_time_sel(). */ - if (rdev->desc->ops->set_voltage_time_sel && + if (_regulator_is_enabled(rdev) && + rdev->desc->ops->set_voltage_time_sel && rdev->desc->ops->get_voltage_sel) { old_selector = rdev->desc->ops->get_voltage_sel(rdev); if (old_selector < 0) @@ -2094,29 +2120,45 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, if (rdev->desc->ops->set_voltage) { ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); + + if (ret >= 0) { + if (rdev->desc->ops->list_voltage) + best_val = rdev->desc->ops->list_voltage(rdev, + selector); + else + best_val = _regulator_get_voltage(rdev); + } + } else if (rdev->desc->ops->set_voltage_sel) { - if (rdev->desc->ops->map_voltage) + if (rdev->desc->ops->map_voltage) { ret = rdev->desc->ops->map_voltage(rdev, min_uV, max_uV); - else - ret = regulator_map_voltage_iterate(rdev, min_uV, - max_uV); + } else { + if (rdev->desc->ops->list_voltage == + regulator_list_voltage_linear) + ret = regulator_map_voltage_linear(rdev, + min_uV, max_uV); + else + ret = regulator_map_voltage_iterate(rdev, + min_uV, max_uV); + } if (ret >= 0) { - selector = ret; - ret = rdev->desc->ops->set_voltage_sel(rdev, ret); + best_val = rdev->desc->ops->list_voltage(rdev, ret); + if (min_uV <= best_val && max_uV >= best_val) { + selector = ret; + ret = rdev->desc->ops->set_voltage_sel(rdev, + ret); + } else { + ret = -EINVAL; + } } } else { ret = -EINVAL; } - if (rdev->desc->ops->list_voltage) - best_val = rdev->desc->ops->list_voltage(rdev, selector); - else - best_val = -1; - /* Call set_voltage_time_sel if successfully obtained old_selector */ - if (ret == 0 && old_selector >= 0 && + if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 && rdev->desc->ops->set_voltage_time_sel) { delay = rdev->desc->ops->set_voltage_time_sel(rdev, @@ -2126,19 +2168,19 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, delay); delay = 0; } - } - /* Insert any necessary delays */ - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); + /* Insert any necessary delays */ + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } } - if (ret == 0) + if (ret == 0 && best_val >= 0) _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, - NULL); + (void *)best_val); trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); @@ -2249,6 +2291,46 @@ int regulator_set_voltage_time(struct regulator *regulator, EXPORT_SYMBOL_GPL(regulator_set_voltage_time); /** + *regulator_set_voltage_time_sel - get raise/fall time + * @regulator: regulator source + * @old_selector: selector for starting voltage + * @new_selector: selector for target voltage + * + * Provided with the starting and target voltage selectors, this function + * returns time in microseconds required to rise or fall to this new voltage + * + * Drivers providing ramp_delay in regulation_constraints can use this as their + * set_voltage_time_sel() operation. + */ +int regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + unsigned int ramp_delay = 0; + int old_volt, new_volt; + + if (rdev->constraints->ramp_delay) + ramp_delay = rdev->constraints->ramp_delay; + else if (rdev->desc->ramp_delay) + ramp_delay = rdev->desc->ramp_delay; + + if (ramp_delay == 0) { + rdev_warn(rdev, "ramp_delay not set\n"); + return 0; + } + + /* sanity check */ + if (!rdev->desc->ops->list_voltage) + return -EINVAL; + + old_volt = rdev->desc->ops->list_voltage(rdev, old_selector); + new_volt = rdev->desc->ops->list_voltage(rdev, new_selector); + + return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay); +} +EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel); + +/** * regulator_sync_voltage - re-apply last regulator output voltage * @regulator: regulator source * @@ -2628,7 +2710,7 @@ static void _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) { /* call rdev chain first */ - blocking_notifier_call_chain(&rdev->notifier, event, NULL); + blocking_notifier_call_chain(&rdev->notifier, event, data); } /** @@ -2909,10 +2991,10 @@ int regulator_mode_to_status(unsigned int mode) return REGULATOR_STATUS_NORMAL; case REGULATOR_MODE_IDLE: return REGULATOR_STATUS_IDLE; - case REGULATOR_STATUS_STANDBY: + case REGULATOR_MODE_STANDBY: return REGULATOR_STATUS_STANDBY; default: - return 0; + return REGULATOR_STATUS_UNDEFINED; } } EXPORT_SYMBOL_GPL(regulator_mode_to_status); @@ -3105,7 +3187,10 @@ regulator_register(const struct regulator_desc *regulator_desc, rdev->reg_data = config->driver_data; rdev->owner = regulator_desc->owner; rdev->desc = regulator_desc; - rdev->regmap = config->regmap; + if (config->regmap) + rdev->regmap = config->regmap; + else + rdev->regmap = dev_get_regmap(dev, NULL); INIT_LIST_HEAD(&rdev->consumer_list); INIT_LIST_HEAD(&rdev->list); BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); @@ -3132,6 +3217,26 @@ regulator_register(const struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); + if (config->ena_gpio) { + ret = gpio_request_one(config->ena_gpio, + GPIOF_DIR_OUT | config->ena_gpio_flags, + rdev_get_name(rdev)); + if (ret != 0) { + rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", + config->ena_gpio, ret); + goto clean; + } + + rdev->ena_gpio = config->ena_gpio; + rdev->ena_gpio_invert = config->ena_gpio_invert; + + if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH) + rdev->ena_gpio_state = 1; + + if (rdev->ena_gpio_invert) + rdev->ena_gpio_state = !rdev->ena_gpio_state; + } + /* set regulator constraints */ if (init_data) constraints = &init_data->constraints; @@ -3200,6 +3305,8 @@ unset_supplies: scrub: if (rdev->supply) regulator_put(rdev->supply); + if (rdev->ena_gpio) + gpio_free(rdev->ena_gpio); kfree(rdev->constraints); device_unregister(&rdev->dev); /* device core frees rdev */ @@ -3233,6 +3340,8 @@ void regulator_unregister(struct regulator_dev *rdev) unset_regulator_supplies(rdev); list_del(&rdev->list); kfree(rdev->constraints); + if (rdev->ena_gpio) + gpio_free(rdev->ena_gpio); device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); } @@ -3472,6 +3581,15 @@ static int __init regulator_init_complete(void) struct regulation_constraints *c; int enabled, ret; + /* + * Since DT doesn't provide an idiomatic mechanism for + * enabling full constraints and since it's much more natural + * with DT to provide them just assume that a DT enabled + * system has full constraints. + */ + if (of_have_populated_dt()) + has_full_constraints = true; + mutex_lock(®ulator_list_mutex); /* If we have a full configuration then disable any regulators diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 1005f5f7e60..36c5b92fe0a 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -107,6 +107,9 @@ static int da903x_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) struct device *da9034_dev = to_da903x_dev(rdev); uint8_t val, mask; + if (rdev->desc->n_voltages == 1) + return -EINVAL; + val = selector << info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -120,6 +123,9 @@ static int da903x_get_voltage_sel(struct regulator_dev *rdev) uint8_t val, mask; int ret; + if (rdev->desc->n_voltages == 1) + return 0; + ret = da903x_read(da9034_dev, info->vol_reg, &val); if (ret) return ret; diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 88976d8d44e..903299cf15c 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -405,12 +405,12 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev) if (!nproot) return -ENODEV; - for (np = of_get_next_child(nproot, NULL); np; - np = of_get_next_child(nproot, np)) { + for_each_child_of_node(nproot, np) { if (!of_node_cmp(np->name, regulator->info->reg_desc.name)) { config.init_data = of_get_regulator_init_data( &pdev->dev, np); + config.of_node = np; break; } } diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c index cacd33c9d04..f9d027992aa 100644 --- a/drivers/regulator/fixed-helper.c +++ b/drivers/regulator/fixed-helper.c @@ -1,4 +1,5 @@ #include <linux/slab.h> +#include <linux/string.h> #include <linux/platform_device.h> #include <linux/regulator/machine.h> #include <linux/regulator/fixed.h> @@ -13,17 +14,20 @@ static void regulator_fixed_release(struct device *dev) { struct fixed_regulator_data *data = container_of(dev, struct fixed_regulator_data, pdev.dev); + kfree(data->cfg.supply_name); kfree(data); } /** - * regulator_register_fixed - register a no-op fixed regulator + * regulator_register_fixed_name - register a no-op fixed regulator * @id: platform device id + * @name: name to be used for the regulator * @supplies: consumers for this regulator * @num_supplies: number of consumers + * @uv: voltage in microvolts */ -struct platform_device *regulator_register_fixed(int id, - struct regulator_consumer_supply *supplies, int num_supplies) +struct platform_device *regulator_register_always_on(int id, const char *name, + struct regulator_consumer_supply *supplies, int num_supplies, int uv) { struct fixed_regulator_data *data; @@ -31,8 +35,13 @@ struct platform_device *regulator_register_fixed(int id, if (!data) return NULL; - data->cfg.supply_name = "fixed-dummy"; - data->cfg.microvolts = 0; + data->cfg.supply_name = kstrdup(name, GFP_KERNEL); + if (!data->cfg.supply_name) { + kfree(data); + return NULL; + } + + data->cfg.microvolts = uv; data->cfg.gpio = -EINVAL; data->cfg.enabled_at_boot = 1; data->cfg.init_data = &data->init_data; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index f09fe7b20e8..185468c4d38 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -35,10 +35,6 @@ struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; int microvolts; - int gpio; - unsigned startup_delay; - bool enable_high; - bool is_enabled; }; @@ -61,11 +57,11 @@ of_get_fixed_voltage_config(struct device *dev) config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config), GFP_KERNEL); if (!config) - return NULL; + return ERR_PTR(-ENOMEM); config->init_data = of_get_regulator_init_data(dev, dev->of_node); if (!config->init_data) - return NULL; + return ERR_PTR(-EINVAL); init_data = config->init_data; init_data->constraints.apply_uV = 0; @@ -76,13 +72,26 @@ of_get_fixed_voltage_config(struct device *dev) } else { dev_err(dev, "Fixed regulator specified with variable voltages\n"); - return NULL; + return ERR_PTR(-EINVAL); } if (init_data->constraints.boot_on) config->enabled_at_boot = true; config->gpio = of_get_named_gpio(np, "gpio", 0); + /* + * of_get_named_gpio() currently returns ENODEV rather than + * EPROBE_DEFER. This code attempts to be compatible with both + * for now; the ENODEV check can be removed once the API is fixed. + * of_get_named_gpio() doesn't differentiate between a missing + * property (which would be fine here, since the GPIO is optional) + * and some other error. Patches have been posted for both issues. + * Once they are check in, we should replace this with: + * if (config->gpio < 0 && config->gpio != -ENOENT) + */ + if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER)) + return ERR_PTR(-EPROBE_DEFER); + delay = of_get_property(np, "startup-delay-us", NULL); if (delay) config->startup_delay = be32_to_cpu(*delay); @@ -93,41 +102,10 @@ of_get_fixed_voltage_config(struct device *dev) if (of_find_property(np, "gpio-open-drain", NULL)) config->gpio_is_open_drain = true; - return config; -} - -static int fixed_voltage_is_enabled(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - return data->is_enabled; -} - -static int fixed_voltage_enable(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - gpio_set_value_cansleep(data->gpio, data->enable_high); - data->is_enabled = true; - - return 0; -} - -static int fixed_voltage_disable(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - gpio_set_value_cansleep(data->gpio, !data->enable_high); - data->is_enabled = false; - - return 0; -} + if (of_find_property(np, "vin-supply", NULL)) + config->input_supply = "vin"; -static int fixed_voltage_enable_time(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - return data->startup_delay; + return config; } static int fixed_voltage_get_voltage(struct regulator_dev *dev) @@ -151,15 +129,6 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev, return data->microvolts; } -static struct regulator_ops fixed_voltage_gpio_ops = { - .is_enabled = fixed_voltage_is_enabled, - .enable = fixed_voltage_enable, - .disable = fixed_voltage_disable, - .enable_time = fixed_voltage_enable_time, - .get_voltage = fixed_voltage_get_voltage, - .list_voltage = fixed_voltage_list_voltage, -}; - static struct regulator_ops fixed_voltage_ops = { .get_voltage = fixed_voltage_get_voltage, .list_voltage = fixed_voltage_list_voltage, @@ -172,10 +141,13 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) struct regulator_config cfg = { }; int ret; - if (pdev->dev.of_node) + if (pdev->dev.of_node) { config = of_get_fixed_voltage_config(&pdev->dev); - else + if (IS_ERR(config)) + return PTR_ERR(config); + } else { config = pdev->dev.platform_data; + } if (!config) return -ENOMEM; @@ -196,59 +168,44 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; + drvdata->desc.ops = &fixed_voltage_ops; - if (config->microvolts) - drvdata->desc.n_voltages = 1; + drvdata->desc.enable_time = config->startup_delay; - drvdata->microvolts = config->microvolts; - drvdata->gpio = config->gpio; - drvdata->startup_delay = config->startup_delay; - - if (gpio_is_valid(config->gpio)) { - int gpio_flag; - drvdata->enable_high = config->enable_high; - - /* FIXME: Remove below print warning - * - * config->gpio must be set to -EINVAL by platform code if - * GPIO control is not required. However, early adopters - * not requiring GPIO control may forget to initialize - * config->gpio to -EINVAL. This will cause GPIO 0 to be used - * for GPIO control. - * - * This warning will be removed once there are a couple of users - * for this driver. - */ - if (!config->gpio) - dev_warn(&pdev->dev, - "using GPIO 0 for regulator enable control\n"); - - /* - * set output direction without changing state - * to prevent glitch - */ - drvdata->is_enabled = config->enabled_at_boot; - ret = drvdata->is_enabled ? - config->enable_high : !config->enable_high; - gpio_flag = ret ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - - if (config->gpio_is_open_drain) - gpio_flag |= GPIOF_OPEN_DRAIN; - - ret = gpio_request_one(config->gpio, gpio_flag, - config->supply_name); - if (ret) { + if (config->input_supply) { + drvdata->desc.supply_name = kstrdup(config->input_supply, + GFP_KERNEL); + if (!drvdata->desc.supply_name) { dev_err(&pdev->dev, - "Could not obtain regulator enable GPIO %d: %d\n", - config->gpio, ret); + "Failed to allocate input supply\n"); + ret = -ENOMEM; goto err_name; } + } + + if (config->microvolts) + drvdata->desc.n_voltages = 1; - drvdata->desc.ops = &fixed_voltage_gpio_ops; + drvdata->microvolts = config->microvolts; + if (config->gpio >= 0) + cfg.ena_gpio = config->gpio; + cfg.ena_gpio_invert = !config->enable_high; + if (config->enabled_at_boot) { + if (config->enable_high) { + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + } else { + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + } } else { - drvdata->desc.ops = &fixed_voltage_ops; + if (config->enable_high) { + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + } else { + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + } } + if (config->gpio_is_open_drain) + cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; cfg.dev = &pdev->dev; cfg.init_data = config->init_data; @@ -259,7 +216,7 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_gpio; + goto err_input; } platform_set_drvdata(pdev, drvdata); @@ -269,9 +226,8 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) return 0; -err_gpio: - if (gpio_is_valid(config->gpio)) - gpio_free(config->gpio); +err_input: + kfree(drvdata->desc.supply_name); err_name: kfree(drvdata->desc.name); err: @@ -283,8 +239,7 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); regulator_unregister(drvdata->dev); - if (gpio_is_valid(drvdata->gpio)) - gpio_free(drvdata->gpio); + kfree(drvdata->desc.supply_name); kfree(drvdata->desc.name); return 0; @@ -296,8 +251,6 @@ static const struct of_device_id fixed_of_match[] __devinitconst = { {}, }; MODULE_DEVICE_TABLE(of, fixed_of_match); -#else -#define fixed_of_match NULL #endif static struct platform_driver regulator_fixed_voltage_driver = { @@ -306,7 +259,7 @@ static struct platform_driver regulator_fixed_voltage_driver = { .driver = { .name = "reg-fixed-voltage", .owner = THIS_MODULE, - .of_match_table = fixed_of_match, + .of_match_table = of_match_ptr(fixed_of_match), }, }; diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 242851a4c1a..34b67bee932 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -36,11 +36,6 @@ struct gpio_regulator_data { struct regulator_desc desc; struct regulator_dev *dev; - int enable_gpio; - bool enable_high; - bool is_enabled; - unsigned startup_delay; - struct gpio *gpios; int nr_gpios; @@ -50,44 +45,6 @@ struct gpio_regulator_data { int state; }; -static int gpio_regulator_is_enabled(struct regulator_dev *dev) -{ - struct gpio_regulator_data *data = rdev_get_drvdata(dev); - - return data->is_enabled; -} - -static int gpio_regulator_enable(struct regulator_dev *dev) -{ - struct gpio_regulator_data *data = rdev_get_drvdata(dev); - - if (gpio_is_valid(data->enable_gpio)) { - gpio_set_value_cansleep(data->enable_gpio, data->enable_high); - data->is_enabled = true; - } - - return 0; -} - -static int gpio_regulator_disable(struct regulator_dev *dev) -{ - struct gpio_regulator_data *data = rdev_get_drvdata(dev); - - if (gpio_is_valid(data->enable_gpio)) { - gpio_set_value_cansleep(data->enable_gpio, !data->enable_high); - data->is_enabled = false; - } - - return 0; -} - -static int gpio_regulator_enable_time(struct regulator_dev *dev) -{ - struct gpio_regulator_data *data = rdev_get_drvdata(dev); - - return data->startup_delay; -} - static int gpio_regulator_get_value(struct regulator_dev *dev) { struct gpio_regulator_data *data = rdev_get_drvdata(dev); @@ -153,20 +110,12 @@ static int gpio_regulator_set_current_limit(struct regulator_dev *dev, } static struct regulator_ops gpio_regulator_voltage_ops = { - .is_enabled = gpio_regulator_is_enabled, - .enable = gpio_regulator_enable, - .disable = gpio_regulator_disable, - .enable_time = gpio_regulator_enable_time, .get_voltage = gpio_regulator_get_value, .set_voltage = gpio_regulator_set_voltage, .list_voltage = gpio_regulator_list_voltage, }; static struct regulator_ops gpio_regulator_current_ops = { - .is_enabled = gpio_regulator_is_enabled, - .enable = gpio_regulator_enable, - .disable = gpio_regulator_disable, - .enable_time = gpio_regulator_enable_time, .get_current_limit = gpio_regulator_get_value, .set_current_limit = gpio_regulator_set_current_limit, }; @@ -213,6 +162,7 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) drvdata->nr_states = config->nr_states; drvdata->desc.owner = THIS_MODULE; + drvdata->desc.enable_time = config->startup_delay; /* handle regulator type*/ switch (config->type) { @@ -232,52 +182,12 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) break; } - drvdata->enable_gpio = config->enable_gpio; - drvdata->startup_delay = config->startup_delay; - - if (gpio_is_valid(config->enable_gpio)) { - drvdata->enable_high = config->enable_high; - - ret = gpio_request(config->enable_gpio, config->supply_name); - if (ret) { - dev_err(&pdev->dev, - "Could not obtain regulator enable GPIO %d: %d\n", - config->enable_gpio, ret); - goto err_memstate; - } - - /* set output direction without changing state - * to prevent glitch - */ - if (config->enabled_at_boot) { - drvdata->is_enabled = true; - ret = gpio_direction_output(config->enable_gpio, - config->enable_high); - } else { - drvdata->is_enabled = false; - ret = gpio_direction_output(config->enable_gpio, - !config->enable_high); - } - - if (ret) { - dev_err(&pdev->dev, - "Could not configure regulator enable GPIO %d direction: %d\n", - config->enable_gpio, ret); - goto err_enablegpio; - } - } else { - /* Regulator without GPIO control is considered - * always enabled - */ - drvdata->is_enabled = true; - } - drvdata->nr_gpios = config->nr_gpios; ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios); if (ret) { dev_err(&pdev->dev, "Could not obtain regulator setting GPIOs: %d\n", ret); - goto err_enablegpio; + goto err_memstate; } /* build initial state from gpio init data. */ @@ -292,6 +202,21 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) cfg.init_data = config->init_data; cfg.driver_data = drvdata; + if (config->enable_gpio >= 0) + cfg.ena_gpio = config->enable_gpio; + cfg.ena_gpio_invert = !config->enable_high; + if (config->enabled_at_boot) { + if (config->enable_high) + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + else + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + } else { + if (config->enable_high) + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + else + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + } + drvdata->dev = regulator_register(&drvdata->desc, &cfg); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); @@ -305,9 +230,6 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) err_stategpio: gpio_free_array(drvdata->gpios, drvdata->nr_gpios); -err_enablegpio: - if (gpio_is_valid(config->enable_gpio)) - gpio_free(config->enable_gpio); err_memstate: kfree(drvdata->states); err_memgpio: @@ -329,9 +251,6 @@ static int __devexit gpio_regulator_remove(struct platform_device *pdev) kfree(drvdata->states); kfree(drvdata->gpios); - if (gpio_is_valid(drvdata->enable_gpio)) - gpio_free(drvdata->enable_gpio); - kfree(drvdata->desc.name); return 0; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 56d273f2560..1d145a07ada 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -75,19 +75,12 @@ static struct regulator_ops isl_core_ops = { static int isl6271a_get_fixed_voltage(struct regulator_dev *dev) { - int id = rdev_get_id(dev); - return (id == 1) ? 1100000 : 1300000; -} - -static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector) -{ - int id = rdev_get_id(dev); - return (id == 1) ? 1100000 : 1300000; + return dev->desc->min_uV; } static struct regulator_ops isl_fixed_ops = { .get_voltage = isl6271a_get_fixed_voltage, - .list_voltage = isl6271a_list_fixed_voltage, + .list_voltage = regulator_list_voltage_linear, }; static const struct regulator_desc isl_rd[] = { @@ -107,6 +100,7 @@ static const struct regulator_desc isl_rd[] = { .ops = &isl_fixed_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .min_uV = 1100000, }, { .name = "LDO2", .id = 2, @@ -114,6 +108,7 @@ static const struct regulator_desc isl_rd[] = { .ops = &isl_fixed_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .min_uV = 1300000, }, }; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 981bea9cb9d..7c6e3b8ff48 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -65,11 +65,11 @@ static const int buck_base_addr[] = { #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x]) #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1) -static const int buck_voltage_map[] = { - 0, 800, 850, 900, 950, 1000, 1050, 1100, - 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, - 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, - 3000, 3300, +static const unsigned int buck_voltage_map[] = { + 0, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, + 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, + 1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000, + 3000000, 3300000, }; #define BUCK_TARGET_VOL_MASK 0x3f @@ -98,39 +98,19 @@ static const int buck_voltage_map[] = { #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2) #define LDO_VOL_CONTR_MASK 0x0f -static const int ldo45_voltage_map[] = { - 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, - 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, +static const unsigned int ldo45_voltage_map[] = { + 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000, + 1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000, }; -static const int ldo123_voltage_map[] = { - 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, - 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, +static const unsigned int ldo123_voltage_map[] = { + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, }; -static const int *ldo_voltage_map[] = { - ldo123_voltage_map, /* LDO1 */ - ldo123_voltage_map, /* LDO2 */ - ldo123_voltage_map, /* LDO3 */ - ldo45_voltage_map, /* LDO4 */ - ldo45_voltage_map, /* LDO5 */ -}; - -#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)]) - #define LDO_VOL_MIN_IDX 0x00 #define LDO_VOL_MAX_IDX 0x0f -static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index) -{ - int ldo = rdev_get_id(dev) - LP3971_LDO1; - - if (index > LDO_VOL_MAX_IDX) - return -EINVAL; - - return 1000 * LDO_VOL_VALUE_MAP(ldo)[index]; -} - static int lp3971_ldo_is_enabled(struct regulator_dev *dev) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); @@ -169,7 +149,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev) reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo)); val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK; - return 1000 * LDO_VOL_VALUE_MAP(ldo)[val]; + return dev->desc->volt_table[val]; } static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev, @@ -184,7 +164,7 @@ static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev, } static struct regulator_ops lp3971_ldo_ops = { - .list_voltage = lp3971_ldo_list_voltage, + .list_voltage = regulator_list_voltage_table, .is_enabled = lp3971_ldo_is_enabled, .enable = lp3971_ldo_enable, .disable = lp3971_ldo_disable, @@ -192,14 +172,6 @@ static struct regulator_ops lp3971_ldo_ops = { .set_voltage_sel = lp3971_ldo_set_voltage_sel, }; -static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) -{ - if (index < BUCK_TARGET_VOL_MIN_IDX || index > BUCK_TARGET_VOL_MAX_IDX) - return -EINVAL; - - return 1000 * buck_voltage_map[index]; -} - static int lp3971_dcdc_is_enabled(struct regulator_dev *dev) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); @@ -240,7 +212,7 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) reg &= BUCK_TARGET_VOL_MASK; if (reg <= BUCK_TARGET_VOL_MAX_IDX) - val = 1000 * buck_voltage_map[reg]; + val = buck_voltage_map[reg]; else { val = 0; dev_warn(&dev->dev, "chip reported incorrect voltage value.\n"); @@ -273,7 +245,7 @@ static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev, } static struct regulator_ops lp3971_dcdc_ops = { - .list_voltage = lp3971_dcdc_list_voltage, + .list_voltage = regulator_list_voltage_table, .is_enabled = lp3971_dcdc_is_enabled, .enable = lp3971_dcdc_enable, .disable = lp3971_dcdc_disable, @@ -287,6 +259,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_LDO1, .ops = &lp3971_ldo_ops, .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .volt_table = ldo123_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -295,6 +268,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_LDO2, .ops = &lp3971_ldo_ops, .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .volt_table = ldo123_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -303,6 +277,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_LDO3, .ops = &lp3971_ldo_ops, .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .volt_table = ldo123_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -311,6 +286,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_LDO4, .ops = &lp3971_ldo_ops, .n_voltages = ARRAY_SIZE(ldo45_voltage_map), + .volt_table = ldo45_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -319,6 +295,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_LDO5, .ops = &lp3971_ldo_ops, .n_voltages = ARRAY_SIZE(ldo45_voltage_map), + .volt_table = ldo45_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -327,6 +304,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_DCDC1, .ops = &lp3971_dcdc_ops, .n_voltages = ARRAY_SIZE(buck_voltage_map), + .volt_table = buck_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -335,6 +313,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_DCDC2, .ops = &lp3971_dcdc_ops, .n_voltages = ARRAY_SIZE(buck_voltage_map), + .volt_table = buck_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -343,6 +322,7 @@ static const struct regulator_desc regulators[] = { .id = LP3971_DCDC3, .ops = &lp3971_dcdc_ops, .n_voltages = ARRAY_SIZE(buck_voltage_map), + .volt_table = buck_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index de073df7d34..3cdc755d9b2 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -74,54 +74,40 @@ struct lp3972 { #define LP3972_OVER2_LDO4_EN BIT(4) #define LP3972_OVER1_S_EN BIT(2) -static const int ldo1_voltage_map[] = { - 1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875, - 1900, 1925, 1950, 1975, 2000, +static const unsigned int ldo1_voltage_map[] = { + 1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000, + 1900000, 1925000, 1950000, 1975000, 2000000, }; -static const int ldo23_voltage_map[] = { - 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, - 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, +static const unsigned int ldo23_voltage_map[] = { + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, }; -static const int ldo4_voltage_map[] = { - 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, - 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, +static const unsigned int ldo4_voltage_map[] = { + 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000, + 1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000, }; -static const int ldo5_voltage_map[] = { - 0, 0, 0, 0, 0, 850, 875, 900, - 925, 950, 975, 1000, 1025, 1050, 1075, 1100, - 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, - 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, +static const unsigned int ldo5_voltage_map[] = { + 0, 0, 0, 0, 0, 850000, 875000, 900000, + 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, + 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, + 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, }; -static const int buck1_voltage_map[] = { - 725, 750, 775, 800, 825, 850, 875, 900, - 925, 950, 975, 1000, 1025, 1050, 1075, 1100, - 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, - 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, +static const unsigned int buck1_voltage_map[] = { + 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, + 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, + 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, + 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, }; -static const int buck23_voltage_map[] = { - 0, 800, 850, 900, 950, 1000, 1050, 1100, - 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, - 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, - 3000, 3300, -}; - -static const int *ldo_voltage_map[] = { - ldo1_voltage_map, - ldo23_voltage_map, - ldo23_voltage_map, - ldo4_voltage_map, - ldo5_voltage_map, -}; - -static const int *buck_voltage_map[] = { - buck1_voltage_map, - buck23_voltage_map, - buck23_voltage_map, +static const unsigned int buck23_voltage_map[] = { + 0, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, + 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, + 1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000, + 3000000, 3300000, }; static const int ldo_output_enable_mask[] = { @@ -160,7 +146,6 @@ static const int buck_base_addr[] = { LP3972_B3TV_REG, }; -#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x]) #define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x]) #define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x]) @@ -177,7 +162,6 @@ static const int buck_base_addr[] = { #define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00) #define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c) -#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x]) #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x]) #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x]) #define LP3972_BUCK_VOL_MASK 0x1f @@ -242,17 +226,6 @@ static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val) return ret; } -static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index) -{ - int ldo = rdev_get_id(dev) - LP3972_LDO1; - - if (index < LP3972_LDO_VOL_MIN_IDX(ldo) || - index > LP3972_LDO_VOL_MAX_IDX(ldo)) - return -EINVAL; - - return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index]; -} - static int lp3972_ldo_is_enabled(struct regulator_dev *dev) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); @@ -294,7 +267,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev) reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo)); val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask; - return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val]; + return dev->desc->volt_table[val]; } static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, @@ -337,7 +310,7 @@ static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, } static struct regulator_ops lp3972_ldo_ops = { - .list_voltage = lp3972_ldo_list_voltage, + .list_voltage = regulator_list_voltage_table, .is_enabled = lp3972_ldo_is_enabled, .enable = lp3972_ldo_enable, .disable = lp3972_ldo_disable, @@ -345,17 +318,6 @@ static struct regulator_ops lp3972_ldo_ops = { .set_voltage_sel = lp3972_ldo_set_voltage_sel, }; -static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) -{ - int buck = rdev_get_id(dev) - LP3972_DCDC1; - - if (index < LP3972_BUCK_VOL_MIN_IDX(buck) || - index > LP3972_BUCK_VOL_MAX_IDX(buck)) - return -EINVAL; - - return 1000 * buck_voltage_map[buck][index]; -} - static int lp3972_dcdc_is_enabled(struct regulator_dev *dev) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); @@ -401,7 +363,7 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck)); reg &= LP3972_BUCK_VOL_MASK; if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck)) - val = 1000 * buck_voltage_map[buck][reg]; + val = dev->desc->volt_table[reg]; else { val = 0; dev_warn(&dev->dev, "chip reported incorrect voltage value." @@ -436,7 +398,7 @@ static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, } static struct regulator_ops lp3972_dcdc_ops = { - .list_voltage = lp3972_dcdc_list_voltage, + .list_voltage = regulator_list_voltage_table, .is_enabled = lp3972_dcdc_is_enabled, .enable = lp3972_dcdc_enable, .disable = lp3972_dcdc_disable, @@ -450,6 +412,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_LDO1, .ops = &lp3972_ldo_ops, .n_voltages = ARRAY_SIZE(ldo1_voltage_map), + .volt_table = ldo1_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -458,6 +421,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_LDO2, .ops = &lp3972_ldo_ops, .n_voltages = ARRAY_SIZE(ldo23_voltage_map), + .volt_table = ldo23_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -466,6 +430,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_LDO3, .ops = &lp3972_ldo_ops, .n_voltages = ARRAY_SIZE(ldo23_voltage_map), + .volt_table = ldo23_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -474,6 +439,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_LDO4, .ops = &lp3972_ldo_ops, .n_voltages = ARRAY_SIZE(ldo4_voltage_map), + .volt_table = ldo4_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -482,6 +448,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_LDO5, .ops = &lp3972_ldo_ops, .n_voltages = ARRAY_SIZE(ldo5_voltage_map), + .volt_table = ldo5_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -490,6 +457,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_DCDC1, .ops = &lp3972_dcdc_ops, .n_voltages = ARRAY_SIZE(buck1_voltage_map), + .volt_table = buck1_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -498,6 +466,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_DCDC2, .ops = &lp3972_dcdc_ops, .n_voltages = ARRAY_SIZE(buck23_voltage_map), + .volt_table = buck23_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -506,6 +475,7 @@ static const struct regulator_desc regulators[] = { .id = LP3972_DCDC3, .ops = &lp3972_dcdc_ops, .n_voltages = ARRAY_SIZE(buck23_voltage_map), + .volt_table = buck23_voltage_map, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c new file mode 100644 index 00000000000..212c38eaba7 --- /dev/null +++ b/drivers/regulator/lp872x.c @@ -0,0 +1,943 @@ +/* + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.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/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/regulator/lp872x.h> +#include <linux/regulator/driver.h> +#include <linux/platform_device.h> + +/* Registers : LP8720/8725 shared */ +#define LP872X_GENERAL_CFG 0x00 +#define LP872X_LDO1_VOUT 0x01 +#define LP872X_LDO2_VOUT 0x02 +#define LP872X_LDO3_VOUT 0x03 +#define LP872X_LDO4_VOUT 0x04 +#define LP872X_LDO5_VOUT 0x05 + +/* Registers : LP8720 */ +#define LP8720_BUCK_VOUT1 0x06 +#define LP8720_BUCK_VOUT2 0x07 +#define LP8720_ENABLE 0x08 + +/* Registers : LP8725 */ +#define LP8725_LILO1_VOUT 0x06 +#define LP8725_LILO2_VOUT 0x07 +#define LP8725_BUCK1_VOUT1 0x08 +#define LP8725_BUCK1_VOUT2 0x09 +#define LP8725_BUCK2_VOUT1 0x0A +#define LP8725_BUCK2_VOUT2 0x0B +#define LP8725_BUCK_CTRL 0x0C +#define LP8725_LDO_CTRL 0x0D + +/* Mask/shift : LP8720/LP8725 shared */ +#define LP872X_VOUT_M 0x1F +#define LP872X_START_DELAY_M 0xE0 +#define LP872X_START_DELAY_S 5 +#define LP872X_EN_LDO1_M BIT(0) +#define LP872X_EN_LDO2_M BIT(1) +#define LP872X_EN_LDO3_M BIT(2) +#define LP872X_EN_LDO4_M BIT(3) +#define LP872X_EN_LDO5_M BIT(4) + +/* Mask/shift : LP8720 */ +#define LP8720_TIMESTEP_S 0 /* Addr 00h */ +#define LP8720_TIMESTEP_M BIT(0) +#define LP8720_EXT_DVS_M BIT(2) +#define LP8720_BUCK_FPWM_S 5 /* Addr 07h */ +#define LP8720_BUCK_FPWM_M BIT(5) +#define LP8720_EN_BUCK_M BIT(5) /* Addr 08h */ +#define LP8720_DVS_SEL_M BIT(7) + +/* Mask/shift : LP8725 */ +#define LP8725_TIMESTEP_M 0xC0 /* Addr 00h */ +#define LP8725_TIMESTEP_S 6 +#define LP8725_BUCK1_EN_M BIT(0) +#define LP8725_DVS1_M BIT(2) +#define LP8725_DVS2_M BIT(3) +#define LP8725_BUCK2_EN_M BIT(4) +#define LP8725_BUCK_CL_M 0xC0 /* Addr 09h, 0Bh */ +#define LP8725_BUCK_CL_S 6 +#define LP8725_BUCK1_FPWM_S 1 /* Addr 0Ch */ +#define LP8725_BUCK1_FPWM_M BIT(1) +#define LP8725_BUCK2_FPWM_S 5 +#define LP8725_BUCK2_FPWM_M BIT(5) +#define LP8725_EN_LILO1_M BIT(5) /* Addr 0Dh */ +#define LP8725_EN_LILO2_M BIT(6) + +/* PWM mode */ +#define LP872X_FORCE_PWM 1 +#define LP872X_AUTO_PWM 0 + +#define LP8720_NUM_REGULATORS 6 +#define LP8725_NUM_REGULATORS 9 +#define EXTERN_DVS_USED 0 +#define MAX_DELAY 6 + +/* dump registers in regmap-debugfs */ +#define MAX_REGISTERS 0x0F + +enum lp872x_id { + LP8720, + LP8725, +}; + +struct lp872x { + struct regmap *regmap; + struct device *dev; + enum lp872x_id chipid; + struct lp872x_platform_data *pdata; + struct regulator_dev **regulators; + int num_regulators; + enum lp872x_dvs_state dvs_pin; + int dvs_gpio; +}; + +/* LP8720/LP8725 shared voltage table for LDOs */ +static const unsigned int lp872x_ldo_vtbl[] = { + 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, + 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 2000000, + 2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2650000, 2700000, + 2750000, 2800000, 2850000, 2900000, 2950000, 3000000, 3100000, 3300000, +}; + +/* LP8720 LDO4 voltage table */ +static const unsigned int lp8720_ldo4_vtbl[] = { + 800000, 850000, 900000, 1000000, 1100000, 1200000, 1250000, 1300000, + 1350000, 1400000, 1450000, 1500000, 1550000, 1600000, 1650000, 1700000, + 1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000, + 2400000, 2500000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000, +}; + +/* LP8725 LILO(Low Input Low Output) voltage table */ +static const unsigned int lp8725_lilo_vtbl[] = { + 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, + 1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000, + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000, +}; + +/* LP8720 BUCK voltage table */ +#define EXT_R 0 /* external resistor divider */ +static const unsigned int lp8720_buck_vtbl[] = { + EXT_R, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, + 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, + 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, + 1950000, 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, +}; + +/* LP8725 BUCK voltage table */ +static const unsigned int lp8725_buck_vtbl[] = { + 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, + 1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000, + 1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000, + 2400000, 2500000, 2600000, 2700000, 2800000, 2850000, 2900000, 3000000, +}; + +/* LP8725 BUCK current limit */ +static const unsigned int lp8725_buck_uA[] = { + 460000, 780000, 1050000, 1370000, +}; + +static int lp872x_read_byte(struct lp872x *lp, u8 addr, u8 *data) +{ + int ret; + unsigned int val; + + ret = regmap_read(lp->regmap, addr, &val); + if (ret < 0) { + dev_err(lp->dev, "failed to read 0x%.2x\n", addr); + return ret; + } + + *data = (u8)val; + return 0; +} + +static inline int lp872x_write_byte(struct lp872x *lp, u8 addr, u8 data) +{ + return regmap_write(lp->regmap, addr, data); +} + +static inline int lp872x_update_bits(struct lp872x *lp, u8 addr, + unsigned int mask, u8 data) +{ + return regmap_update_bits(lp->regmap, addr, mask, data); +} + +static int _rdev_to_offset(struct regulator_dev *rdev) +{ + enum lp872x_regulator_id id = rdev_get_id(rdev); + + switch (id) { + case LP8720_ID_LDO1 ... LP8720_ID_BUCK: + return id; + case LP8725_ID_LDO1 ... LP8725_ID_BUCK2: + return id - LP8725_ID_BASE; + default: + return -EINVAL; + } +} + +static int lp872x_get_timestep_usec(struct lp872x *lp) +{ + enum lp872x_id chip = lp->chipid; + u8 val, mask, shift; + int *time_usec, size, ret; + int lp8720_time_usec[] = { 25, 50 }; + int lp8725_time_usec[] = { 32, 64, 128, 256 }; + + switch (chip) { + case LP8720: + mask = LP8720_TIMESTEP_M; + shift = LP8720_TIMESTEP_S; + time_usec = &lp8720_time_usec[0]; + size = ARRAY_SIZE(lp8720_time_usec); + break; + case LP8725: + mask = LP8725_TIMESTEP_M; + shift = LP8725_TIMESTEP_S; + time_usec = &lp8725_time_usec[0]; + size = ARRAY_SIZE(lp8725_time_usec); + break; + default: + return -EINVAL; + } + + ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val); + if (ret) + return -EINVAL; + + val = (val & mask) >> shift; + if (val >= size) + return -EINVAL; + + return *(time_usec + val); +} + +static int lp872x_regulator_enable_time(struct regulator_dev *rdev) +{ + struct lp872x *lp = rdev_get_drvdata(rdev); + enum lp872x_regulator_id regulator = rdev_get_id(rdev); + int time_step_us = lp872x_get_timestep_usec(lp); + int ret, offset; + u8 addr, val; + + if (time_step_us < 0) + return -EINVAL; + + switch (regulator) { + case LP8720_ID_LDO1 ... LP8720_ID_LDO5: + case LP8725_ID_LDO1 ... LP8725_ID_LILO2: + offset = _rdev_to_offset(rdev); + if (offset < 0) + return -EINVAL; + + addr = LP872X_LDO1_VOUT + offset; + break; + case LP8720_ID_BUCK: + addr = LP8720_BUCK_VOUT1; + break; + case LP8725_ID_BUCK1: + addr = LP8725_BUCK1_VOUT1; + break; + case LP8725_ID_BUCK2: + addr = LP8725_BUCK2_VOUT1; + break; + default: + return -EINVAL; + } + + ret = lp872x_read_byte(lp, addr, &val); + if (ret) + return ret; + + val = (val & LP872X_START_DELAY_M) >> LP872X_START_DELAY_S; + + return val > MAX_DELAY ? 0 : val * time_step_us; +} + +static void lp872x_set_dvs(struct lp872x *lp, int gpio) +{ + enum lp872x_dvs_sel dvs_sel = lp->pdata->dvs->vsel; + enum lp872x_dvs_state state; + + state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW; + gpio_set_value(gpio, state); + lp->dvs_pin = state; +} + +static u8 lp872x_select_buck_vout_addr(struct lp872x *lp, + enum lp872x_regulator_id buck) +{ + u8 val, addr; + + if (lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val)) + return 0; + + switch (buck) { + case LP8720_ID_BUCK: + if (val & LP8720_EXT_DVS_M) { + addr = (lp->dvs_pin == DVS_HIGH) ? + LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2; + } else { + if (lp872x_read_byte(lp, LP8720_ENABLE, &val)) + return 0; + + addr = val & LP8720_DVS_SEL_M ? + LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2; + } + break; + case LP8725_ID_BUCK1: + if (val & LP8725_DVS1_M) + addr = LP8725_BUCK1_VOUT1; + else + addr = (lp->dvs_pin == DVS_HIGH) ? + LP8725_BUCK1_VOUT1 : LP8725_BUCK1_VOUT2; + break; + case LP8725_ID_BUCK2: + addr = val & LP8725_DVS2_M ? + LP8725_BUCK2_VOUT1 : LP8725_BUCK2_VOUT2; + break; + default: + return 0; + } + + return addr; +} + +static bool lp872x_is_valid_buck_addr(u8 addr) +{ + switch (addr) { + case LP8720_BUCK_VOUT1: + case LP8720_BUCK_VOUT2: + case LP8725_BUCK1_VOUT1: + case LP8725_BUCK1_VOUT2: + case LP8725_BUCK2_VOUT1: + case LP8725_BUCK2_VOUT2: + return true; + default: + return false; + } +} + +static int lp872x_buck_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct lp872x *lp = rdev_get_drvdata(rdev); + enum lp872x_regulator_id buck = rdev_get_id(rdev); + u8 addr, mask = LP872X_VOUT_M; + struct lp872x_dvs *dvs = lp->pdata->dvs; + + if (dvs && gpio_is_valid(dvs->gpio)) + lp872x_set_dvs(lp, dvs->gpio); + + addr = lp872x_select_buck_vout_addr(lp, buck); + if (!lp872x_is_valid_buck_addr(addr)) + return -EINVAL; + + return lp872x_update_bits(lp, addr, mask, selector); +} + +static int lp872x_buck_get_voltage_sel(struct regulator_dev *rdev) +{ + struct lp872x *lp = rdev_get_drvdata(rdev); + enum lp872x_regulator_id buck = rdev_get_id(rdev); + u8 addr, val; + int ret; + + addr = lp872x_select_buck_vout_addr(lp, buck); + if (!lp872x_is_valid_buck_addr(addr)) + return -EINVAL; + + ret = lp872x_read_byte(lp, addr, &val); + if (ret) + return ret; + + return val & LP872X_VOUT_M; +} + +static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct lp872x *lp = rdev_get_drvdata(rdev); + enum lp872x_regulator_id buck = rdev_get_id(rdev); + int i, max = ARRAY_SIZE(lp8725_buck_uA); + u8 addr, val; + + switch (buck) { + case LP8725_ID_BUCK1: + addr = LP8725_BUCK1_VOUT2; + break; + case LP8725_ID_BUCK2: + addr = LP8725_BUCK2_VOUT2; + break; + default: + return -EINVAL; + } + + for (i = 0 ; i < max ; i++) + if (lp8725_buck_uA[i] >= min_uA && + lp8725_buck_uA[i] <= max_uA) + break; + + if (i == max) + return -EINVAL; + + val = i << LP8725_BUCK_CL_S; + + return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val); +} + +static int lp8725_buck_get_current_limit(struct regulator_dev *rdev) +{ + struct lp872x *lp = rdev_get_drvdata(rdev); + enum lp872x_regulator_id buck = rdev_get_id(rdev); + u8 addr, val; + int ret; + + switch (buck) { + case LP8725_ID_BUCK1: + addr = LP8725_BUCK1_VOUT2; + break; + case LP8725_ID_BUCK2: + addr = LP8725_BUCK2_VOUT2; + break; + default: + return -EINVAL; + } + + ret = lp872x_read_byte(lp, addr, &val); + if (ret) + return ret; + + val = (val & LP8725_BUCK_CL_M) >> LP8725_BUCK_CL_S; + + return (val < ARRAY_SIZE(lp8725_buck_uA)) ? + lp8725_buck_uA[val] : -EINVAL; +} + +static int lp872x_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct lp872x *lp = rdev_get_drvdata(rdev); + enum lp872x_regulator_id buck = rdev_get_id(rdev); + u8 addr, mask, shift, val; + + switch (buck) { + case LP8720_ID_BUCK: + addr = LP8720_BUCK_VOUT2; + mask = LP8720_BUCK_FPWM_M; + shift = LP8720_BUCK_FPWM_S; + break; + case LP8725_ID_BUCK1: + addr = LP8725_BUCK_CTRL; + mask = LP8725_BUCK1_FPWM_M; + shift = LP8725_BUCK1_FPWM_S; + break; + case LP8725_ID_BUCK2: + addr = LP8725_BUCK_CTRL; + mask = LP8725_BUCK2_FPWM_M; + shift = LP8725_BUCK2_FPWM_S; + break; + default: + return -EINVAL; + } + + if (mode == REGULATOR_MODE_FAST) + val = LP872X_FORCE_PWM << shift; + else if (mode == REGULATOR_MODE_NORMAL) + val = LP872X_AUTO_PWM << shift; + else + return -EINVAL; + + return lp872x_update_bits(lp, addr, mask, val); +} + +static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev) +{ + struct lp872x *lp = rdev_get_drvdata(rdev); + enum lp872x_regulator_id buck = rdev_get_id(rdev); + u8 addr, mask, val; + int ret; + + switch (buck) { + case LP8720_ID_BUCK: + addr = LP8720_BUCK_VOUT2; + mask = LP8720_BUCK_FPWM_M; + break; + case LP8725_ID_BUCK1: + addr = LP8725_BUCK_CTRL; + mask = LP8725_BUCK1_FPWM_M; + break; + case LP8725_ID_BUCK2: + addr = LP8725_BUCK_CTRL; + mask = LP8725_BUCK2_FPWM_M; + break; + default: + return -EINVAL; + } + + ret = lp872x_read_byte(lp, addr, &val); + if (ret) + return ret; + + return val & mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; +} + +static struct regulator_ops lp872x_ldo_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .enable_time = lp872x_regulator_enable_time, +}; + +static struct regulator_ops lp8720_buck_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = lp872x_buck_set_voltage_sel, + .get_voltage_sel = lp872x_buck_get_voltage_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .enable_time = lp872x_regulator_enable_time, + .set_mode = lp872x_buck_set_mode, + .get_mode = lp872x_buck_get_mode, +}; + +static struct regulator_ops lp8725_buck_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = lp872x_buck_set_voltage_sel, + .get_voltage_sel = lp872x_buck_get_voltage_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .enable_time = lp872x_regulator_enable_time, + .set_mode = lp872x_buck_set_mode, + .get_mode = lp872x_buck_get_mode, + .set_current_limit = lp8725_buck_set_current_limit, + .get_current_limit = lp8725_buck_get_current_limit, +}; + +static struct regulator_desc lp8720_regulator_desc[] = { + { + .name = "ldo1", + .id = LP8720_ID_LDO1, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO1_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8720_ENABLE, + .enable_mask = LP872X_EN_LDO1_M, + }, + { + .name = "ldo2", + .id = LP8720_ID_LDO2, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO2_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8720_ENABLE, + .enable_mask = LP872X_EN_LDO2_M, + }, + { + .name = "ldo3", + .id = LP8720_ID_LDO3, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO3_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8720_ENABLE, + .enable_mask = LP872X_EN_LDO3_M, + }, + { + .name = "ldo4", + .id = LP8720_ID_LDO4, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp8720_ldo4_vtbl), + .volt_table = lp8720_ldo4_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO4_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8720_ENABLE, + .enable_mask = LP872X_EN_LDO4_M, + }, + { + .name = "ldo5", + .id = LP8720_ID_LDO5, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO5_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8720_ENABLE, + .enable_mask = LP872X_EN_LDO5_M, + }, + { + .name = "buck", + .id = LP8720_ID_BUCK, + .ops = &lp8720_buck_ops, + .n_voltages = ARRAY_SIZE(lp8720_buck_vtbl), + .volt_table = lp8720_buck_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8720_ENABLE, + .enable_mask = LP8720_EN_BUCK_M, + }, +}; + +static struct regulator_desc lp8725_regulator_desc[] = { + { + .name = "ldo1", + .id = LP8725_ID_LDO1, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO1_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8725_LDO_CTRL, + .enable_mask = LP872X_EN_LDO1_M, + }, + { + .name = "ldo2", + .id = LP8725_ID_LDO2, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO2_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8725_LDO_CTRL, + .enable_mask = LP872X_EN_LDO2_M, + }, + { + .name = "ldo3", + .id = LP8725_ID_LDO3, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO3_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8725_LDO_CTRL, + .enable_mask = LP872X_EN_LDO3_M, + }, + { + .name = "ldo4", + .id = LP8725_ID_LDO4, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO4_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8725_LDO_CTRL, + .enable_mask = LP872X_EN_LDO4_M, + }, + { + .name = "ldo5", + .id = LP8725_ID_LDO5, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl), + .volt_table = lp872x_ldo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP872X_LDO5_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8725_LDO_CTRL, + .enable_mask = LP872X_EN_LDO5_M, + }, + { + .name = "lilo1", + .id = LP8725_ID_LILO1, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl), + .volt_table = lp8725_lilo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8725_LILO1_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8725_LDO_CTRL, + .enable_mask = LP8725_EN_LILO1_M, + }, + { + .name = "lilo2", + .id = LP8725_ID_LILO2, + .ops = &lp872x_ldo_ops, + .n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl), + .volt_table = lp8725_lilo_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8725_LILO2_VOUT, + .vsel_mask = LP872X_VOUT_M, + .enable_reg = LP8725_LDO_CTRL, + .enable_mask = LP8725_EN_LILO2_M, + }, + { + .name = "buck1", + .id = LP8725_ID_BUCK1, + .ops = &lp8725_buck_ops, + .n_voltages = ARRAY_SIZE(lp8725_buck_vtbl), + .volt_table = lp8725_buck_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP872X_GENERAL_CFG, + .enable_mask = LP8725_BUCK1_EN_M, + }, + { + .name = "buck2", + .id = LP8725_ID_BUCK2, + .ops = &lp8725_buck_ops, + .n_voltages = ARRAY_SIZE(lp8725_buck_vtbl), + .volt_table = lp8725_buck_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP872X_GENERAL_CFG, + .enable_mask = LP8725_BUCK2_EN_M, + }, +}; + +static int lp872x_check_dvs_validity(struct lp872x *lp) +{ + struct lp872x_dvs *dvs = lp->pdata->dvs; + u8 val = 0; + int ret; + + ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val); + if (ret) + return ret; + + ret = 0; + if (lp->chipid == LP8720) { + if (val & LP8720_EXT_DVS_M) + ret = dvs ? 0 : -EINVAL; + } else { + if ((val & LP8725_DVS1_M) == EXTERN_DVS_USED) + ret = dvs ? 0 : -EINVAL; + } + + return ret; +} + +static int lp872x_init_dvs(struct lp872x *lp) +{ + int ret, gpio; + struct lp872x_dvs *dvs = lp->pdata->dvs; + enum lp872x_dvs_state pinstate; + + ret = lp872x_check_dvs_validity(lp); + if (ret) { + dev_warn(lp->dev, "invalid dvs data: %d\n", ret); + return ret; + } + + gpio = dvs->gpio; + if (!gpio_is_valid(gpio)) { + dev_err(lp->dev, "invalid gpio: %d\n", gpio); + return -EINVAL; + } + + pinstate = dvs->init_state; + ret = devm_gpio_request_one(lp->dev, gpio, pinstate, "LP872X DVS"); + if (ret) { + dev_err(lp->dev, "gpio request err: %d\n", ret); + return ret; + } + + lp->dvs_pin = pinstate; + lp->dvs_gpio = gpio; + + return 0; +} + +static int lp872x_config(struct lp872x *lp) +{ + struct lp872x_platform_data *pdata = lp->pdata; + int ret; + + if (!pdata->update_config) + return 0; + + ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config); + if (ret) + return ret; + + return lp872x_init_dvs(lp); +} + +static struct regulator_init_data +*lp872x_find_regulator_init_data(int id, struct lp872x *lp) +{ + int i; + + for (i = 0; i < lp->num_regulators; i++) { + if (lp->pdata->regulator_data[i].id == id) + return lp->pdata->regulator_data[i].init_data; + } + + return NULL; +} + +static int lp872x_regulator_register(struct lp872x *lp) +{ + struct regulator_desc *desc; + struct regulator_config cfg = { }; + struct regulator_dev *rdev; + int i, ret; + + for (i = 0 ; i < lp->num_regulators ; i++) { + desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] : + &lp8725_regulator_desc[i]; + + cfg.dev = lp->dev; + cfg.init_data = lp872x_find_regulator_init_data(desc->id, lp); + cfg.driver_data = lp; + cfg.regmap = lp->regmap; + + rdev = regulator_register(desc, &cfg); + if (IS_ERR(rdev)) { + dev_err(lp->dev, "regulator register err"); + ret = PTR_ERR(rdev); + goto err; + } + + *(lp->regulators + i) = rdev; + } + + return 0; +err: + while (--i >= 0) { + rdev = *(lp->regulators + i); + regulator_unregister(rdev); + } + return ret; +} + +static void lp872x_regulator_unregister(struct lp872x *lp) +{ + struct regulator_dev *rdev; + int i; + + for (i = 0 ; i < lp->num_regulators ; i++) { + rdev = *(lp->regulators + i); + regulator_unregister(rdev); + } +} + +static const struct regmap_config lp872x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX_REGISTERS, +}; + +static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) +{ + struct lp872x *lp; + struct lp872x_platform_data *pdata = cl->dev.platform_data; + int ret, size, num_regulators; + const int lp872x_num_regulators[] = { + [LP8720] = LP8720_NUM_REGULATORS, + [LP8725] = LP8725_NUM_REGULATORS, + }; + + if (!pdata) { + dev_err(&cl->dev, "no platform data\n"); + return -EINVAL; + } + + lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL); + if (!lp) + goto err_mem; + + num_regulators = lp872x_num_regulators[id->driver_data]; + size = sizeof(struct regulator_dev *) * num_regulators; + + lp->regulators = devm_kzalloc(&cl->dev, size, GFP_KERNEL); + if (!lp->regulators) + goto err_mem; + + lp->regmap = devm_regmap_init_i2c(cl, &lp872x_regmap_config); + if (IS_ERR(lp->regmap)) { + ret = PTR_ERR(lp->regmap); + dev_err(&cl->dev, "regmap init i2c err: %d\n", ret); + goto err_dev; + } + + lp->dev = &cl->dev; + lp->pdata = pdata; + lp->chipid = id->driver_data; + lp->num_regulators = num_regulators; + i2c_set_clientdata(cl, lp); + + ret = lp872x_config(lp); + if (ret) + goto err_dev; + + return lp872x_regulator_register(lp); + +err_mem: + return -ENOMEM; +err_dev: + return ret; +} + +static int __devexit lp872x_remove(struct i2c_client *cl) +{ + struct lp872x *lp = i2c_get_clientdata(cl); + + lp872x_regulator_unregister(lp); + return 0; +} + +static const struct i2c_device_id lp872x_ids[] = { + {"lp8720", LP8720}, + {"lp8725", LP8725}, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp872x_ids); + +static struct i2c_driver lp872x_driver = { + .driver = { + .name = "lp872x", + .owner = THIS_MODULE, + }, + .probe = lp872x_probe, + .remove = __devexit_p(lp872x_remove), + .id_table = lp872x_ids, +}; + +module_i2c_driver(lp872x_driver); + +MODULE_DESCRIPTION("TI/National Semiconductor LP872x PMU Regulator Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c new file mode 100644 index 00000000000..6356e821400 --- /dev/null +++ b/drivers/regulator/lp8788-buck.c @@ -0,0 +1,629 @@ +/* + * TI LP8788 MFD - buck regulator driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.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/module.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/lp8788.h> +#include <linux/gpio.h> + +/* register address */ +#define LP8788_EN_BUCK 0x0C +#define LP8788_BUCK_DVS_SEL 0x1D +#define LP8788_BUCK1_VOUT0 0x1E +#define LP8788_BUCK1_VOUT1 0x1F +#define LP8788_BUCK1_VOUT2 0x20 +#define LP8788_BUCK1_VOUT3 0x21 +#define LP8788_BUCK2_VOUT0 0x22 +#define LP8788_BUCK2_VOUT1 0x23 +#define LP8788_BUCK2_VOUT2 0x24 +#define LP8788_BUCK2_VOUT3 0x25 +#define LP8788_BUCK3_VOUT 0x26 +#define LP8788_BUCK4_VOUT 0x27 +#define LP8788_BUCK1_TIMESTEP 0x28 +#define LP8788_BUCK_PWM 0x2D + +/* mask/shift bits */ +#define LP8788_EN_BUCK1_M BIT(0) /* Addr 0Ch */ +#define LP8788_EN_BUCK2_M BIT(1) +#define LP8788_EN_BUCK3_M BIT(2) +#define LP8788_EN_BUCK4_M BIT(3) +#define LP8788_BUCK1_DVS_SEL_M 0x04 /* Addr 1Dh */ +#define LP8788_BUCK1_DVS_M 0x03 +#define LP8788_BUCK1_DVS_S 0 +#define LP8788_BUCK2_DVS_SEL_M 0x40 +#define LP8788_BUCK2_DVS_M 0x30 +#define LP8788_BUCK2_DVS_S 4 +#define LP8788_BUCK1_DVS_I2C BIT(2) +#define LP8788_BUCK2_DVS_I2C BIT(6) +#define LP8788_BUCK1_DVS_PIN (0 << 2) +#define LP8788_BUCK2_DVS_PIN (0 << 6) +#define LP8788_VOUT_M 0x1F /* Addr 1Eh ~ 27h */ +#define LP8788_STARTUP_TIME_M 0xF8 /* Addr 28h ~ 2Bh */ +#define LP8788_STARTUP_TIME_S 3 +#define LP8788_FPWM_BUCK1_M BIT(0) /* Addr 2Dh */ +#define LP8788_FPWM_BUCK1_S 0 +#define LP8788_FPWM_BUCK2_M BIT(1) +#define LP8788_FPWM_BUCK2_S 1 +#define LP8788_FPWM_BUCK3_M BIT(2) +#define LP8788_FPWM_BUCK3_S 2 +#define LP8788_FPWM_BUCK4_M BIT(3) +#define LP8788_FPWM_BUCK4_S 3 + +#define INVALID_ADDR 0xFF +#define LP8788_FORCE_PWM 1 +#define LP8788_AUTO_PWM 0 +#define PIN_LOW 0 +#define PIN_HIGH 1 +#define ENABLE_TIME_USEC 32 + +enum lp8788_dvs_state { + DVS_LOW = GPIOF_OUT_INIT_LOW, + DVS_HIGH = GPIOF_OUT_INIT_HIGH, +}; + +enum lp8788_dvs_mode { + REGISTER, + EXTPIN, +}; + +enum lp8788_buck_id { + BUCK1, + BUCK2, + BUCK3, + BUCK4, +}; + +struct lp8788_pwm_map { + u8 mask; + u8 shift; +}; + +struct lp8788_buck { + struct lp8788 *lp; + struct regulator_dev *regulator; + struct lp8788_pwm_map *pmap; + void *dvs; +}; + +/* BUCK 1 ~ 4 voltage table */ +static const int lp8788_buck_vtbl[] = { + 500000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, + 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, + 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, + 1950000, 2000000, +}; + +/* buck pwm mode selection : used for set/get_mode in regulator ops + * @forced pwm : fast mode + * @auto pwm : normal mode + */ +static struct lp8788_pwm_map buck_pmap[] = { + [BUCK1] = { + .mask = LP8788_FPWM_BUCK1_M, + .shift = LP8788_FPWM_BUCK1_S, + }, + [BUCK2] = { + .mask = LP8788_FPWM_BUCK2_M, + .shift = LP8788_FPWM_BUCK2_S, + }, + [BUCK3] = { + .mask = LP8788_FPWM_BUCK3_M, + .shift = LP8788_FPWM_BUCK3_S, + }, + [BUCK4] = { + .mask = LP8788_FPWM_BUCK4_M, + .shift = LP8788_FPWM_BUCK4_S, + }, +}; + +static const u8 buck1_vout_addr[] = { + LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1, + LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3, +}; + +static const u8 buck2_vout_addr[] = { + LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1, + LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3, +}; + +static void lp8788_buck1_set_dvs(struct lp8788_buck *buck) +{ + struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs; + enum lp8788_dvs_state pinstate; + + if (!dvs) + return; + + pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH; + if (gpio_is_valid(dvs->gpio)) + gpio_set_value(dvs->gpio, pinstate); +} + +static void lp8788_buck2_set_dvs(struct lp8788_buck *buck) +{ + struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs; + enum lp8788_dvs_state pin1, pin2; + + if (!dvs) + return; + + switch (dvs->vsel) { + case DVS_SEL_V0: + pin1 = DVS_LOW; + pin2 = DVS_LOW; + break; + case DVS_SEL_V1: + pin1 = DVS_HIGH; + pin2 = DVS_LOW; + break; + case DVS_SEL_V2: + pin1 = DVS_LOW; + pin2 = DVS_HIGH; + break; + case DVS_SEL_V3: + pin1 = DVS_HIGH; + pin2 = DVS_HIGH; + break; + default: + return; + } + + if (gpio_is_valid(dvs->gpio[0])) + gpio_set_value(dvs->gpio[0], pin1); + + if (gpio_is_valid(dvs->gpio[1])) + gpio_set_value(dvs->gpio[1], pin2); +} + +static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) +{ + switch (id) { + case BUCK1: + lp8788_buck1_set_dvs(buck); + break; + case BUCK2: + lp8788_buck2_set_dvs(buck); + break; + default: + break; + } +} + +static enum lp8788_dvs_mode +lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id) +{ + u8 val, mask; + + switch (id) { + case BUCK1: + mask = LP8788_BUCK1_DVS_SEL_M; + break; + case BUCK2: + mask = LP8788_BUCK2_DVS_SEL_M; + break; + default: + return REGISTER; + } + + lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); + + return val & mask ? REGISTER : EXTPIN; +} + +static bool lp8788_is_valid_buck_addr(u8 addr) +{ + switch (addr) { + case LP8788_BUCK1_VOUT0: + case LP8788_BUCK1_VOUT1: + case LP8788_BUCK1_VOUT2: + case LP8788_BUCK1_VOUT3: + case LP8788_BUCK2_VOUT0: + case LP8788_BUCK2_VOUT1: + case LP8788_BUCK2_VOUT2: + case LP8788_BUCK2_VOUT3: + return true; + default: + return false; + } +} + +static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, + enum lp8788_buck_id id) +{ + enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id); + struct lp8788_buck1_dvs *b1_dvs; + struct lp8788_buck2_dvs *b2_dvs; + u8 val, idx, addr; + int pin1, pin2; + + switch (id) { + case BUCK1: + if (mode == EXTPIN) { + b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs; + if (!b1_dvs) + goto err; + + idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0; + } else { + lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); + idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S; + } + addr = buck1_vout_addr[idx]; + break; + case BUCK2: + if (mode == EXTPIN) { + b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs; + if (!b2_dvs) + goto err; + + pin1 = gpio_get_value(b2_dvs->gpio[0]); + pin2 = gpio_get_value(b2_dvs->gpio[1]); + + if (pin1 == PIN_LOW && pin2 == PIN_LOW) + idx = 0; + else if (pin1 == PIN_LOW && pin2 == PIN_HIGH) + idx = 2; + else if (pin1 == PIN_HIGH && pin2 == PIN_LOW) + idx = 1; + else + idx = 3; + } else { + lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); + idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S; + } + addr = buck2_vout_addr[idx]; + break; + default: + goto err; + } + + return addr; +err: + return INVALID_ADDR; +} + +static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct lp8788_buck *buck = rdev_get_drvdata(rdev); + enum lp8788_buck_id id = rdev_get_id(rdev); + u8 addr; + + if (buck->dvs) + lp8788_set_dvs(buck, id); + + addr = lp8788_select_buck_vout_addr(buck, id); + if (!lp8788_is_valid_buck_addr(addr)) + return -EINVAL; + + return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector); +} + +static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev) +{ + struct lp8788_buck *buck = rdev_get_drvdata(rdev); + enum lp8788_buck_id id = rdev_get_id(rdev); + int ret; + u8 val, addr; + + addr = lp8788_select_buck_vout_addr(buck, id); + if (!lp8788_is_valid_buck_addr(addr)) + return -EINVAL; + + ret = lp8788_read_byte(buck->lp, addr, &val); + if (ret) + return ret; + + return val & LP8788_VOUT_M; +} + +static int lp8788_buck_enable_time(struct regulator_dev *rdev) +{ + struct lp8788_buck *buck = rdev_get_drvdata(rdev); + enum lp8788_buck_id id = rdev_get_id(rdev); + u8 val, addr = LP8788_BUCK1_TIMESTEP + id; + + if (lp8788_read_byte(buck->lp, addr, &val)) + return -EINVAL; + + val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S; + + return ENABLE_TIME_USEC * val; +} + +static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct lp8788_buck *buck = rdev_get_drvdata(rdev); + struct lp8788_pwm_map *pmap = buck->pmap; + u8 val; + + if (!pmap) + return -EINVAL; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = LP8788_FORCE_PWM << pmap->shift; + break; + case REGULATOR_MODE_NORMAL: + val = LP8788_AUTO_PWM << pmap->shift; + break; + default: + return -EINVAL; + } + + return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val); +} + +static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev) +{ + struct lp8788_buck *buck = rdev_get_drvdata(rdev); + struct lp8788_pwm_map *pmap = buck->pmap; + u8 val; + int ret; + + if (!pmap) + return -EINVAL; + + ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val); + if (ret) + return ret; + + return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; +} + +static struct regulator_ops lp8788_buck12_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = lp8788_buck12_set_voltage_sel, + .get_voltage_sel = lp8788_buck12_get_voltage_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .enable_time = lp8788_buck_enable_time, + .set_mode = lp8788_buck_set_mode, + .get_mode = lp8788_buck_get_mode, +}; + +static struct regulator_ops lp8788_buck34_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .enable_time = lp8788_buck_enable_time, + .set_mode = lp8788_buck_set_mode, + .get_mode = lp8788_buck_get_mode, +}; + +static struct regulator_desc lp8788_buck_desc[] = { + { + .name = "buck1", + .id = BUCK1, + .ops = &lp8788_buck12_ops, + .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), + .volt_table = lp8788_buck_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_BUCK, + .enable_mask = LP8788_EN_BUCK1_M, + }, + { + .name = "buck2", + .id = BUCK2, + .ops = &lp8788_buck12_ops, + .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), + .volt_table = lp8788_buck_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_BUCK, + .enable_mask = LP8788_EN_BUCK2_M, + }, + { + .name = "buck3", + .id = BUCK3, + .ops = &lp8788_buck34_ops, + .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), + .volt_table = lp8788_buck_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_BUCK3_VOUT, + .vsel_mask = LP8788_VOUT_M, + .enable_reg = LP8788_EN_BUCK, + .enable_mask = LP8788_EN_BUCK3_M, + }, + { + .name = "buck4", + .id = BUCK4, + .ops = &lp8788_buck34_ops, + .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), + .volt_table = lp8788_buck_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_BUCK4_VOUT, + .vsel_mask = LP8788_VOUT_M, + .enable_reg = LP8788_EN_BUCK, + .enable_mask = LP8788_EN_BUCK4_M, + }, +}; + +static int lp8788_set_default_dvs_ctrl_mode(struct lp8788 *lp, + enum lp8788_buck_id id) +{ + u8 mask, val; + + switch (id) { + case BUCK1: + mask = LP8788_BUCK1_DVS_SEL_M; + val = LP8788_BUCK1_DVS_I2C; + break; + case BUCK2: + mask = LP8788_BUCK2_DVS_SEL_M; + val = LP8788_BUCK2_DVS_I2C; + break; + default: + return 0; + } + + return lp8788_update_bits(lp, LP8788_BUCK_DVS_SEL, mask, val); +} + +static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name) +{ + struct device *dev = buck->lp->dev; + + if (!gpio_is_valid(gpio)) { + dev_err(dev, "invalid gpio: %d\n", gpio); + return -EINVAL; + } + + return devm_gpio_request_one(dev, gpio, DVS_LOW, name); +} + +static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, + enum lp8788_buck_id id) +{ + struct lp8788_platform_data *pdata = buck->lp->pdata; + char *b1_name = "LP8788_B1_DVS"; + char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" }; + int i, gpio, ret; + + switch (id) { + case BUCK1: + gpio = pdata->buck1_dvs->gpio; + ret = _gpio_request(buck, gpio, b1_name); + if (ret) + return ret; + + buck->dvs = pdata->buck1_dvs; + break; + case BUCK2: + for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) { + gpio = pdata->buck2_dvs->gpio[i]; + ret = _gpio_request(buck, gpio, b2_name[i]); + if (ret) + return ret; + } + buck->dvs = pdata->buck2_dvs; + break; + default: + break; + } + + return 0; +} + +static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) +{ + struct lp8788_platform_data *pdata = buck->lp->pdata; + u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M }; + u8 val[] = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN }; + + /* no dvs for buck3, 4 */ + if (id == BUCK3 || id == BUCK4) + return 0; + + /* no dvs platform data, then dvs will be selected by I2C registers */ + if (!pdata) + goto set_default_dvs_mode; + + if ((id == BUCK1 && !pdata->buck1_dvs) || + (id == BUCK2 && !pdata->buck2_dvs)) + goto set_default_dvs_mode; + + if (lp8788_dvs_gpio_request(buck, id)) + goto set_default_dvs_mode; + + return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], + val[id]); + +set_default_dvs_mode: + return lp8788_set_default_dvs_ctrl_mode(buck->lp, id); +} + +static __devinit int lp8788_buck_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + int id = pdev->id; + struct lp8788_buck *buck; + struct regulator_config cfg = { }; + struct regulator_dev *rdev; + int ret; + + buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL); + if (!buck) + return -ENOMEM; + + buck->lp = lp; + buck->pmap = &buck_pmap[id]; + + ret = lp8788_init_dvs(buck, id); + if (ret) + return ret; + + cfg.dev = lp->dev; + cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL; + cfg.driver_data = buck; + cfg.regmap = lp->regmap; + + rdev = regulator_register(&lp8788_buck_desc[id], &cfg); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(lp->dev, "BUCK%d regulator register err = %d\n", + id + 1, ret); + return ret; + } + + buck->regulator = rdev; + platform_set_drvdata(pdev, buck); + + return 0; +} + +static int __devexit lp8788_buck_remove(struct platform_device *pdev) +{ + struct lp8788_buck *buck = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + regulator_unregister(buck->regulator); + + return 0; +} + +static struct platform_driver lp8788_buck_driver = { + .probe = lp8788_buck_probe, + .remove = __devexit_p(lp8788_buck_remove), + .driver = { + .name = LP8788_DEV_BUCK, + .owner = THIS_MODULE, + }, +}; + +static int __init lp8788_buck_init(void) +{ + return platform_driver_register(&lp8788_buck_driver); +} +subsys_initcall(lp8788_buck_init); + +static void __exit lp8788_buck_exit(void) +{ + platform_driver_unregister(&lp8788_buck_driver); +} +module_exit(lp8788_buck_exit); + +MODULE_DESCRIPTION("TI LP8788 BUCK Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-buck"); diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c new file mode 100644 index 00000000000..d2122e41a96 --- /dev/null +++ b/drivers/regulator/lp8788-ldo.c @@ -0,0 +1,842 @@ +/* + * TI LP8788 MFD - ldo regulator driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.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/module.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/gpio.h> +#include <linux/mfd/lp8788.h> + +/* register address */ +#define LP8788_EN_LDO_A 0x0D /* DLDO 1 ~ 8 */ +#define LP8788_EN_LDO_B 0x0E /* DLDO 9 ~ 12, ALDO 1 ~ 4 */ +#define LP8788_EN_LDO_C 0x0F /* ALDO 5 ~ 10 */ +#define LP8788_EN_SEL 0x10 +#define LP8788_DLDO1_VOUT 0x2E +#define LP8788_DLDO2_VOUT 0x2F +#define LP8788_DLDO3_VOUT 0x30 +#define LP8788_DLDO4_VOUT 0x31 +#define LP8788_DLDO5_VOUT 0x32 +#define LP8788_DLDO6_VOUT 0x33 +#define LP8788_DLDO7_VOUT 0x34 +#define LP8788_DLDO8_VOUT 0x35 +#define LP8788_DLDO9_VOUT 0x36 +#define LP8788_DLDO10_VOUT 0x37 +#define LP8788_DLDO11_VOUT 0x38 +#define LP8788_DLDO12_VOUT 0x39 +#define LP8788_ALDO1_VOUT 0x3A +#define LP8788_ALDO2_VOUT 0x3B +#define LP8788_ALDO3_VOUT 0x3C +#define LP8788_ALDO4_VOUT 0x3D +#define LP8788_ALDO5_VOUT 0x3E +#define LP8788_ALDO6_VOUT 0x3F +#define LP8788_ALDO7_VOUT 0x40 +#define LP8788_ALDO8_VOUT 0x41 +#define LP8788_ALDO9_VOUT 0x42 +#define LP8788_ALDO10_VOUT 0x43 +#define LP8788_DLDO1_TIMESTEP 0x44 + +/* mask/shift bits */ +#define LP8788_EN_DLDO1_M BIT(0) /* Addr 0Dh ~ 0Fh */ +#define LP8788_EN_DLDO2_M BIT(1) +#define LP8788_EN_DLDO3_M BIT(2) +#define LP8788_EN_DLDO4_M BIT(3) +#define LP8788_EN_DLDO5_M BIT(4) +#define LP8788_EN_DLDO6_M BIT(5) +#define LP8788_EN_DLDO7_M BIT(6) +#define LP8788_EN_DLDO8_M BIT(7) +#define LP8788_EN_DLDO9_M BIT(0) +#define LP8788_EN_DLDO10_M BIT(1) +#define LP8788_EN_DLDO11_M BIT(2) +#define LP8788_EN_DLDO12_M BIT(3) +#define LP8788_EN_ALDO1_M BIT(4) +#define LP8788_EN_ALDO2_M BIT(5) +#define LP8788_EN_ALDO3_M BIT(6) +#define LP8788_EN_ALDO4_M BIT(7) +#define LP8788_EN_ALDO5_M BIT(0) +#define LP8788_EN_ALDO6_M BIT(1) +#define LP8788_EN_ALDO7_M BIT(2) +#define LP8788_EN_ALDO8_M BIT(3) +#define LP8788_EN_ALDO9_M BIT(4) +#define LP8788_EN_ALDO10_M BIT(5) +#define LP8788_EN_SEL_DLDO911_M BIT(0) /* Addr 10h */ +#define LP8788_EN_SEL_DLDO7_M BIT(1) +#define LP8788_EN_SEL_ALDO7_M BIT(2) +#define LP8788_EN_SEL_ALDO5_M BIT(3) +#define LP8788_EN_SEL_ALDO234_M BIT(4) +#define LP8788_EN_SEL_ALDO1_M BIT(5) +#define LP8788_VOUT_5BIT_M 0x1F /* Addr 2Eh ~ 43h */ +#define LP8788_VOUT_4BIT_M 0x0F +#define LP8788_VOUT_3BIT_M 0x07 +#define LP8788_VOUT_1BIT_M 0x01 +#define LP8788_STARTUP_TIME_M 0xF8 /* Addr 44h ~ 59h */ +#define LP8788_STARTUP_TIME_S 3 + +#define ENABLE_TIME_USEC 32 +#define ENABLE GPIOF_OUT_INIT_HIGH +#define DISABLE GPIOF_OUT_INIT_LOW + +enum lp8788_enable_mode { + REGISTER, + EXTPIN, +}; + +enum lp8788_ldo_id { + DLDO1, + DLDO2, + DLDO3, + DLDO4, + DLDO5, + DLDO6, + DLDO7, + DLDO8, + DLDO9, + DLDO10, + DLDO11, + DLDO12, + ALDO1, + ALDO2, + ALDO3, + ALDO4, + ALDO5, + ALDO6, + ALDO7, + ALDO8, + ALDO9, + ALDO10, +}; + +struct lp8788_ldo { + struct lp8788 *lp; + struct regulator_desc *desc; + struct regulator_dev *regulator; + struct lp8788_ldo_enable_pin *en_pin; +}; + +/* DLDO 1, 2, 3, 9 voltage table */ +const int lp8788_dldo1239_vtbl[] = { + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2900000, 3000000, 2850000, 2850000, 2850000, + 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, + 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, +}; + +/* DLDO 4 voltage table */ +static const int lp8788_dldo4_vtbl[] = { 1800000, 3000000 }; + +/* DLDO 5, 7, 8 and ALDO 6 voltage table */ +static const int lp8788_dldo578_aldo6_vtbl[] = { + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2900000, 3000000, 3000000, 3000000, 3000000, +}; + +/* DLDO 6 voltage table */ +static const int lp8788_dldo6_vtbl[] = { + 3000000, 3100000, 3200000, 3300000, 3400000, 3500000, 3600000, 3600000, +}; + +/* DLDO 10, 11 voltage table */ +static const int lp8788_dldo1011_vtbl[] = { + 1100000, 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, + 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, +}; + +/* ALDO 1 voltage table */ +static const int lp8788_aldo1_vtbl[] = { 1800000, 2850000 }; + +/* ALDO 7 voltage table */ +static const int lp8788_aldo7_vtbl[] = { + 1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1800000, +}; + +static enum lp8788_ldo_id lp8788_dldo_id[] = { + DLDO1, + DLDO2, + DLDO3, + DLDO4, + DLDO5, + DLDO6, + DLDO7, + DLDO8, + DLDO9, + DLDO10, + DLDO11, + DLDO12, +}; + +static enum lp8788_ldo_id lp8788_aldo_id[] = { + ALDO1, + ALDO2, + ALDO3, + ALDO4, + ALDO5, + ALDO6, + ALDO7, + ALDO8, + ALDO9, + ALDO10, +}; + +/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7 + : can be enabled either by external pin or by i2c register */ +static enum lp8788_enable_mode +lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id) +{ + int ret; + u8 val, mask; + + ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val); + if (ret) + return ret; + + switch (id) { + case DLDO7: + mask = LP8788_EN_SEL_DLDO7_M; + break; + case DLDO9: + case DLDO11: + mask = LP8788_EN_SEL_DLDO911_M; + break; + case ALDO1: + mask = LP8788_EN_SEL_ALDO1_M; + break; + case ALDO2 ... ALDO4: + mask = LP8788_EN_SEL_ALDO234_M; + break; + case ALDO5: + mask = LP8788_EN_SEL_ALDO5_M; + break; + case ALDO7: + mask = LP8788_EN_SEL_ALDO7_M; + break; + default: + return REGISTER; + } + + return val & mask ? EXTPIN : REGISTER; +} + +static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate) +{ + struct lp8788_ldo_enable_pin *pin = ldo->en_pin; + + if (!pin) + return -EINVAL; + + if (gpio_is_valid(pin->gpio)) + gpio_set_value(pin->gpio, pinstate); + + return 0; +} + +static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo) +{ + struct lp8788_ldo_enable_pin *pin = ldo->en_pin; + + if (!pin) + return -EINVAL; + + return gpio_get_value(pin->gpio) ? 1 : 0; +} + +static int lp8788_ldo_enable(struct regulator_dev *rdev) +{ + struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); + enum lp8788_ldo_id id = rdev_get_id(rdev); + enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); + + switch (mode) { + case EXTPIN: + return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE); + case REGISTER: + return regulator_enable_regmap(rdev); + default: + return -EINVAL; + } +} + +static int lp8788_ldo_disable(struct regulator_dev *rdev) +{ + struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); + enum lp8788_ldo_id id = rdev_get_id(rdev); + enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); + + switch (mode) { + case EXTPIN: + return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE); + case REGISTER: + return regulator_disable_regmap(rdev); + default: + return -EINVAL; + } +} + +static int lp8788_ldo_is_enabled(struct regulator_dev *rdev) +{ + struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); + enum lp8788_ldo_id id = rdev_get_id(rdev); + enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); + + switch (mode) { + case EXTPIN: + return lp8788_ldo_is_enabled_by_extern_pin(ldo); + case REGISTER: + return regulator_is_enabled_regmap(rdev); + default: + return -EINVAL; + } +} + +static int lp8788_ldo_enable_time(struct regulator_dev *rdev) +{ + struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); + enum lp8788_ldo_id id = rdev_get_id(rdev); + u8 val, addr = LP8788_DLDO1_TIMESTEP + id; + + if (lp8788_read_byte(ldo->lp, addr, &val)) + return -EINVAL; + + val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S; + + return ENABLE_TIME_USEC * val; +} + +static int lp8788_ldo_fixed_get_voltage(struct regulator_dev *rdev) +{ + enum lp8788_ldo_id id = rdev_get_id(rdev); + + switch (id) { + case ALDO2 ... ALDO5: + return 2850000; + case DLDO12: + case ALDO8 ... ALDO9: + return 2500000; + case ALDO10: + return 1100000; + default: + return -EINVAL; + } +} + +static struct regulator_ops lp8788_ldo_voltage_table_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = lp8788_ldo_enable, + .disable = lp8788_ldo_disable, + .is_enabled = lp8788_ldo_is_enabled, + .enable_time = lp8788_ldo_enable_time, +}; + +static struct regulator_ops lp8788_ldo_voltage_fixed_ops = { + .get_voltage = lp8788_ldo_fixed_get_voltage, + .enable = lp8788_ldo_enable, + .disable = lp8788_ldo_disable, + .is_enabled = lp8788_ldo_is_enabled, + .enable_time = lp8788_ldo_enable_time, +}; + +static struct regulator_desc lp8788_dldo_desc[] = { + { + .name = "dldo1", + .id = DLDO1, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), + .volt_table = lp8788_dldo1239_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO1_VOUT, + .vsel_mask = LP8788_VOUT_5BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO1_M, + }, + { + .name = "dldo2", + .id = DLDO2, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), + .volt_table = lp8788_dldo1239_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO2_VOUT, + .vsel_mask = LP8788_VOUT_5BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO2_M, + }, + { + .name = "dldo3", + .id = DLDO3, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), + .volt_table = lp8788_dldo1239_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO3_VOUT, + .vsel_mask = LP8788_VOUT_5BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO3_M, + }, + { + .name = "dldo4", + .id = DLDO4, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo4_vtbl), + .volt_table = lp8788_dldo4_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO4_VOUT, + .vsel_mask = LP8788_VOUT_1BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO4_M, + }, + { + .name = "dldo5", + .id = DLDO5, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), + .volt_table = lp8788_dldo578_aldo6_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO5_VOUT, + .vsel_mask = LP8788_VOUT_4BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO5_M, + }, + { + .name = "dldo6", + .id = DLDO6, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo6_vtbl), + .volt_table = lp8788_dldo6_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO6_VOUT, + .vsel_mask = LP8788_VOUT_3BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO6_M, + }, + { + .name = "dldo7", + .id = DLDO7, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), + .volt_table = lp8788_dldo578_aldo6_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO7_VOUT, + .vsel_mask = LP8788_VOUT_4BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO7_M, + }, + { + .name = "dldo8", + .id = DLDO8, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), + .volt_table = lp8788_dldo578_aldo6_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO8_VOUT, + .vsel_mask = LP8788_VOUT_4BIT_M, + .enable_reg = LP8788_EN_LDO_A, + .enable_mask = LP8788_EN_DLDO8_M, + }, + { + .name = "dldo9", + .id = DLDO9, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), + .volt_table = lp8788_dldo1239_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO9_VOUT, + .vsel_mask = LP8788_VOUT_5BIT_M, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_DLDO9_M, + }, + { + .name = "dldo10", + .id = DLDO10, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl), + .volt_table = lp8788_dldo1011_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO10_VOUT, + .vsel_mask = LP8788_VOUT_4BIT_M, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_DLDO10_M, + }, + { + .name = "dldo11", + .id = DLDO11, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl), + .volt_table = lp8788_dldo1011_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_DLDO11_VOUT, + .vsel_mask = LP8788_VOUT_4BIT_M, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_DLDO11_M, + }, + { + .name = "dldo12", + .id = DLDO12, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_DLDO12_M, + }, +}; + +static struct regulator_desc lp8788_aldo_desc[] = { + { + .name = "aldo1", + .id = ALDO1, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_aldo1_vtbl), + .volt_table = lp8788_aldo1_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_ALDO1_VOUT, + .vsel_mask = LP8788_VOUT_1BIT_M, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_ALDO1_M, + }, + { + .name = "aldo2", + .id = ALDO2, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_ALDO2_M, + }, + { + .name = "aldo3", + .id = ALDO3, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_ALDO3_M, + }, + { + .name = "aldo4", + .id = ALDO4, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_B, + .enable_mask = LP8788_EN_ALDO4_M, + }, + { + .name = "aldo5", + .id = ALDO5, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_C, + .enable_mask = LP8788_EN_ALDO5_M, + }, + { + .name = "aldo6", + .id = ALDO6, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), + .volt_table = lp8788_dldo578_aldo6_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_ALDO6_VOUT, + .vsel_mask = LP8788_VOUT_4BIT_M, + .enable_reg = LP8788_EN_LDO_C, + .enable_mask = LP8788_EN_ALDO6_M, + }, + { + .name = "aldo7", + .id = ALDO7, + .ops = &lp8788_ldo_voltage_table_ops, + .n_voltages = ARRAY_SIZE(lp8788_aldo7_vtbl), + .volt_table = lp8788_aldo7_vtbl, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LP8788_ALDO7_VOUT, + .vsel_mask = LP8788_VOUT_3BIT_M, + .enable_reg = LP8788_EN_LDO_C, + .enable_mask = LP8788_EN_ALDO7_M, + }, + { + .name = "aldo8", + .id = ALDO8, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_C, + .enable_mask = LP8788_EN_ALDO8_M, + }, + { + .name = "aldo9", + .id = ALDO9, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_C, + .enable_mask = LP8788_EN_ALDO9_M, + }, + { + .name = "aldo10", + .id = ALDO10, + .ops = &lp8788_ldo_voltage_fixed_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = LP8788_EN_LDO_C, + .enable_mask = LP8788_EN_ALDO10_M, + }, +}; + +static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo, + enum lp8788_ext_ldo_en_id id) +{ + struct device *dev = ldo->lp->dev; + struct lp8788_ldo_enable_pin *pin = ldo->en_pin; + int ret, gpio, pinstate; + char *name[] = { + [EN_ALDO1] = "LP8788_EN_ALDO1", + [EN_ALDO234] = "LP8788_EN_ALDO234", + [EN_ALDO5] = "LP8788_EN_ALDO5", + [EN_ALDO7] = "LP8788_EN_ALDO7", + [EN_DLDO7] = "LP8788_EN_DLDO7", + [EN_DLDO911] = "LP8788_EN_DLDO911", + }; + + gpio = pin->gpio; + if (!gpio_is_valid(gpio)) { + dev_err(dev, "invalid gpio: %d\n", gpio); + return -EINVAL; + } + + pinstate = pin->init_state; + ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]); + if (ret == -EBUSY) { + dev_warn(dev, "gpio%d already used\n", gpio); + return 0; + } + + return ret; +} + +static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, + enum lp8788_ldo_id id) +{ + int ret; + struct lp8788 *lp = ldo->lp; + struct lp8788_platform_data *pdata = lp->pdata; + enum lp8788_ext_ldo_en_id enable_id; + u8 en_mask[] = { + [EN_ALDO1] = LP8788_EN_SEL_ALDO1_M, + [EN_ALDO234] = LP8788_EN_SEL_ALDO234_M, + [EN_ALDO5] = LP8788_EN_SEL_ALDO5_M, + [EN_ALDO7] = LP8788_EN_SEL_ALDO7_M, + [EN_DLDO7] = LP8788_EN_SEL_DLDO7_M, + [EN_DLDO911] = LP8788_EN_SEL_DLDO911_M, + }; + u8 val[] = { + [EN_ALDO1] = 0 << 5, + [EN_ALDO234] = 0 << 4, + [EN_ALDO5] = 0 << 3, + [EN_ALDO7] = 0 << 2, + [EN_DLDO7] = 0 << 1, + [EN_DLDO911] = 0 << 0, + }; + + switch (id) { + case DLDO7: + enable_id = EN_DLDO7; + break; + case DLDO9: + case DLDO11: + enable_id = EN_DLDO911; + break; + case ALDO1: + enable_id = EN_ALDO1; + break; + case ALDO2 ... ALDO4: + enable_id = EN_ALDO234; + break; + case ALDO5: + enable_id = EN_ALDO5; + break; + case ALDO7: + enable_id = EN_ALDO7; + break; + default: + return 0; + } + + /* if no platform data for ldo pin, then set default enable mode */ + if (!pdata || !pdata->ldo_pin || !pdata->ldo_pin[enable_id]) + goto set_default_ldo_enable_mode; + + ldo->en_pin = pdata->ldo_pin[enable_id]; + + ret = lp8788_gpio_request_ldo_en(ldo, enable_id); + if (ret) + goto set_default_ldo_enable_mode; + + return ret; + +set_default_ldo_enable_mode: + return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], + val[enable_id]); +} + +static __devinit int lp8788_dldo_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + int id = pdev->id; + struct lp8788_ldo *ldo; + struct regulator_config cfg = { }; + struct regulator_dev *rdev; + int ret; + + ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); + if (!ldo) + return -ENOMEM; + + ldo->lp = lp; + ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]); + if (ret) + return ret; + + cfg.dev = lp->dev; + cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL; + cfg.driver_data = ldo; + cfg.regmap = lp->regmap; + + rdev = regulator_register(&lp8788_dldo_desc[id], &cfg); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(lp->dev, "DLDO%d regulator register err = %d\n", + id + 1, ret); + return ret; + } + + ldo->regulator = rdev; + platform_set_drvdata(pdev, ldo); + + return 0; +} + +static int __devexit lp8788_dldo_remove(struct platform_device *pdev) +{ + struct lp8788_ldo *ldo = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + regulator_unregister(ldo->regulator); + + return 0; +} + +static struct platform_driver lp8788_dldo_driver = { + .probe = lp8788_dldo_probe, + .remove = __devexit_p(lp8788_dldo_remove), + .driver = { + .name = LP8788_DEV_DLDO, + .owner = THIS_MODULE, + }, +}; + +static __devinit int lp8788_aldo_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + int id = pdev->id; + struct lp8788_ldo *ldo; + struct regulator_config cfg = { }; + struct regulator_dev *rdev; + int ret; + + ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); + if (!ldo) + return -ENOMEM; + + ldo->lp = lp; + ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]); + if (ret) + return ret; + + cfg.dev = lp->dev; + cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL; + cfg.driver_data = ldo; + cfg.regmap = lp->regmap; + + rdev = regulator_register(&lp8788_aldo_desc[id], &cfg); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(lp->dev, "ALDO%d regulator register err = %d\n", + id + 1, ret); + return ret; + } + + ldo->regulator = rdev; + platform_set_drvdata(pdev, ldo); + + return 0; +} + +static int __devexit lp8788_aldo_remove(struct platform_device *pdev) +{ + struct lp8788_ldo *ldo = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + regulator_unregister(ldo->regulator); + + return 0; +} + +static struct platform_driver lp8788_aldo_driver = { + .probe = lp8788_aldo_probe, + .remove = __devexit_p(lp8788_aldo_remove), + .driver = { + .name = LP8788_DEV_ALDO, + .owner = THIS_MODULE, + }, +}; + +static int __init lp8788_ldo_init(void) +{ + int ret; + + ret = platform_driver_register(&lp8788_dldo_driver); + if (ret) + return ret; + + return platform_driver_register(&lp8788_aldo_driver); +} +subsys_initcall(lp8788_ldo_init); + +static void __exit lp8788_ldo_exit(void) +{ + platform_driver_unregister(&lp8788_aldo_driver); + platform_driver_unregister(&lp8788_dldo_driver); +} +module_exit(lp8788_ldo_exit); + +MODULE_DESCRIPTION("TI LP8788 LDO Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-dldo"); +MODULE_ALIAS("platform:lp8788-aldo"); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index b9444ee08da..f67af3c1b96 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -48,6 +48,14 @@ struct max1586_data { }; /* + * V6 voltage + * On I2C bus, sending a "x" byte to the max1586 means : + * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) + * As regulator framework doesn't accept voltages to be 0V, we use 1uV. + */ +static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; + +/* * V3 voltage * On I2C bus, sending a "x" byte to the max1586 means : * set V3 to 0.700V + (x & 0x1f) * 0.025V @@ -55,113 +63,49 @@ struct max1586_data { * R24 and R25=100kOhm as described in the data sheet. * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm */ -static int max1586_v3_calc_voltage(struct max1586_data *max1586, - unsigned selector) -{ - unsigned range_uV = max1586->max_uV - max1586->min_uV; - - return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL); -} - -static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV, - unsigned *selector) +static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct max1586_data *max1586 = rdev_get_drvdata(rdev); struct i2c_client *client = max1586->client; - unsigned range_uV = max1586->max_uV - max1586->min_uV; u8 v3_prog; - if (min_uV > max1586->max_uV || max_uV < max1586->min_uV) - return -EINVAL; - if (min_uV < max1586->min_uV) - min_uV = max1586->min_uV; - - *selector = DIV_ROUND_UP((min_uV - max1586->min_uV) * - MAX1586_V3_MAX_VSEL, range_uV); - if (max1586_v3_calc_voltage(max1586, *selector) > max_uV) - return -EINVAL; - dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", - max1586_v3_calc_voltage(max1586, *selector) / 1000); + regulator_list_voltage_linear(rdev, selector) / 1000); - v3_prog = I2C_V3_SELECT | (u8) *selector; + v3_prog = I2C_V3_SELECT | (u8) selector; return i2c_smbus_write_byte(client, v3_prog); } -static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector) -{ - struct max1586_data *max1586 = rdev_get_drvdata(rdev); - - if (selector > MAX1586_V3_MAX_VSEL) - return -EINVAL; - return max1586_v3_calc_voltage(max1586, selector); -} - -/* - * V6 voltage - * On I2C bus, sending a "x" byte to the max1586 means : - * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) - * As regulator framework doesn't accept voltages to be 0V, we use 1uV. - */ -static int max1586_v6_calc_voltage(unsigned selector) -{ - static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; - - return voltages_uv[selector]; -} - -static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV, - unsigned int *selector) +static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) { struct i2c_client *client = rdev_get_drvdata(rdev); u8 v6_prog; - if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV) - return -EINVAL; - if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV) - return -EINVAL; - - if (min_uV < 1800000) - *selector = 0; - else if (min_uV < 2500000) - *selector = 1; - else if (min_uV < 3000000) - *selector = 2; - else if (min_uV >= 3000000) - *selector = 3; - - if (max1586_v6_calc_voltage(*selector) > max_uV) - return -EINVAL; - dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", - max1586_v6_calc_voltage(*selector) / 1000); + rdev->desc->volt_table[selector] / 1000); - v6_prog = I2C_V6_SELECT | (u8) *selector; + v6_prog = I2C_V6_SELECT | (u8) selector; return i2c_smbus_write_byte(client, v6_prog); } -static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector) -{ - if (selector > MAX1586_V6_MAX_VSEL) - return -EINVAL; - return max1586_v6_calc_voltage(selector); -} - /* * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back * the set up value. */ static struct regulator_ops max1586_v3_ops = { - .set_voltage = max1586_v3_set, - .list_voltage = max1586_v3_list, + .set_voltage_sel = max1586_v3_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, }; static struct regulator_ops max1586_v6_ops = { - .set_voltage = max1586_v6_set, - .list_voltage = max1586_v6_list, + .set_voltage_sel = max1586_v6_set_voltage_sel, + .list_voltage = regulator_list_voltage_table, }; -static const struct regulator_desc max1586_reg[] = { +static struct regulator_desc max1586_reg[] = { { .name = "Output_V3", .id = MAX1586_V3, @@ -176,6 +120,7 @@ static const struct regulator_desc max1586_reg[] = { .ops = &max1586_v6_ops, .type = REGULATOR_VOLTAGE, .n_voltages = MAX1586_V6_MAX_VSEL + 1, + .volt_table = v6_voltages_uv, .owner = THIS_MODULE, }, }; @@ -213,6 +158,13 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client, goto err; } + if (id == MAX1586_V3) { + max1586_reg[id].min_uV = max1586->min_uV; + max1586_reg[id].uV_step = + (max1586->max_uV - max1586->min_uV) / + MAX1586_V3_MAX_VSEL; + } + config.dev = &client->dev; config.init_data = pdata->subdevs[i].platform_data; config.driver_data = max1586; diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c new file mode 100644 index 00000000000..c564af6f05a --- /dev/null +++ b/drivers/regulator/max77686.c @@ -0,0 +1,389 @@ +/* + * max77686.c - Regulator driver for the Maxim 77686 + * + * Copyright (C) 2012 Samsung Electronics + * Chiwoong Byun <woong.byun@smasung.com> + * Jonghwa Lee <jonghwa3.lee@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max8997.c + */ + +#include <linux/kernel.h> +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/mfd/max77686.h> +#include <linux/mfd/max77686-private.h> + +#define MAX77686_LDO_MINUV 800000 +#define MAX77686_LDO_UVSTEP 50000 +#define MAX77686_LDO_LOW_MINUV 800000 +#define MAX77686_LDO_LOW_UVSTEP 25000 +#define MAX77686_BUCK_MINUV 750000 +#define MAX77686_BUCK_UVSTEP 50000 +#define MAX77686_RAMP_DELAY 100000 /* uV/us */ +#define MAX77686_DVS_RAMP_DELAY 27500 /* uV/us */ +#define MAX77686_DVS_MINUV 600000 +#define MAX77686_DVS_UVSTEP 12500 + +#define MAX77686_OPMODE_SHIFT 6 +#define MAX77686_OPMODE_BUCK234_SHIFT 4 +#define MAX77686_OPMODE_MASK 0x3 + +#define MAX77686_VSEL_MASK 0x3F +#define MAX77686_DVS_VSEL_MASK 0xFF + +#define MAX77686_RAMP_RATE_MASK 0xC0 + +#define MAX77686_REGULATORS MAX77686_REG_MAX +#define MAX77686_LDOS 26 + +enum max77686_ramp_rate { + RAMP_RATE_13P75MV, + RAMP_RATE_27P5MV, + RAMP_RATE_55MV, + RAMP_RATE_NO_CTRL, /* 100mV/us */ +}; + +struct max77686_data { + struct regulator_dev **rdev; +}; + +static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + unsigned int ramp_value = RAMP_RATE_NO_CTRL; + + switch (ramp_delay) { + case 1 ... 13750: + ramp_value = RAMP_RATE_13P75MV; + break; + case 13751 ... 27500: + ramp_value = RAMP_RATE_27P5MV; + break; + case 27501 ... 55000: + ramp_value = RAMP_RATE_55MV; + break; + case 55001 ... 100000: + break; + default: + pr_warn("%s: ramp_delay: %d not supported, setting 100000\n", + rdev->desc->name, ramp_delay); + } + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX77686_RAMP_RATE_MASK, ramp_value << 6); +} + +static struct regulator_ops max77686_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops max77686_buck_dvs_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = max77686_set_ramp_delay, +}; + +#define regulator_desc_ldo(num) { \ + .name = "LDO"#num, \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_MINUV, \ + .uV_step = MAX77686_LDO_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_ldo_low(num) { \ + .name = "LDO"#num, \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_LOW_MINUV, \ + .uV_step = MAX77686_LDO_LOW_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_buck(num) { \ + .name = "BUCK"#num, \ + .id = MAX77686_BUCK##num, \ + .ops = &max77686_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_BUCK_MINUV, \ + .uV_step = MAX77686_BUCK_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_BUCK5OUT + (num - 5) * 2, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_BUCK5CTRL + (num - 5) * 2, \ + .enable_mask = MAX77686_OPMODE_MASK, \ +} +#define regulator_desc_buck1(num) { \ + .name = "BUCK"#num, \ + .id = MAX77686_BUCK##num, \ + .ops = &max77686_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_BUCK_MINUV, \ + .uV_step = MAX77686_BUCK_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_BUCK1OUT, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_BUCK1CTRL, \ + .enable_mask = MAX77686_OPMODE_MASK, \ +} +#define regulator_desc_buck_dvs(num) { \ + .name = "BUCK"#num, \ + .id = MAX77686_BUCK##num, \ + .ops = &max77686_buck_dvs_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_DVS_MINUV, \ + .uV_step = MAX77686_DVS_UVSTEP, \ + .ramp_delay = MAX77686_DVS_RAMP_DELAY, \ + .n_voltages = MAX77686_DVS_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10, \ + .vsel_mask = MAX77686_DVS_VSEL_MASK, \ + .enable_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_BUCK234_SHIFT, \ +} + +static struct regulator_desc regulators[] = { + regulator_desc_ldo_low(1), + regulator_desc_ldo_low(2), + regulator_desc_ldo(3), + regulator_desc_ldo(4), + regulator_desc_ldo(5), + regulator_desc_ldo_low(6), + regulator_desc_ldo_low(7), + regulator_desc_ldo_low(8), + regulator_desc_ldo(9), + regulator_desc_ldo(10), + regulator_desc_ldo(11), + regulator_desc_ldo(12), + regulator_desc_ldo(13), + regulator_desc_ldo(14), + regulator_desc_ldo_low(15), + regulator_desc_ldo(16), + regulator_desc_ldo(17), + regulator_desc_ldo(18), + regulator_desc_ldo(19), + regulator_desc_ldo(20), + regulator_desc_ldo(21), + regulator_desc_ldo(22), + regulator_desc_ldo(23), + regulator_desc_ldo(24), + regulator_desc_ldo(25), + regulator_desc_ldo(26), + regulator_desc_buck1(1), + regulator_desc_buck_dvs(2), + regulator_desc_buck_dvs(3), + regulator_desc_buck_dvs(4), + regulator_desc_buck(5), + regulator_desc_buck(6), + regulator_desc_buck(7), + regulator_desc_buck(8), + regulator_desc_buck(9), +}; + +#ifdef CONFIG_OF +static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, + struct max77686_platform_data *pdata) +{ + struct device_node *pmic_np, *regulators_np; + struct max77686_regulator_data *rdata; + struct of_regulator_match rmatch; + unsigned int i; + + pmic_np = iodev->dev->of_node; + regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators"); + if (!regulators_np) { + dev_err(iodev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + pdata->num_regulators = ARRAY_SIZE(regulators); + rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) * + pdata->num_regulators, GFP_KERNEL); + if (!rdata) { + dev_err(iodev->dev, + "could not allocate memory for regulator data\n"); + return -ENOMEM; + } + + for (i = 0; i < pdata->num_regulators; i++) { + rmatch.name = regulators[i].name; + rmatch.init_data = NULL; + rmatch.of_node = NULL; + of_regulator_match(iodev->dev, regulators_np, &rmatch, 1); + rdata[i].initdata = rmatch.init_data; + } + + pdata->regulators = rdata; + + return 0; +} +#else +static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, + struct max77686_platform_data *pdata) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static __devinit int max77686_pmic_probe(struct platform_device *pdev) +{ + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev); + struct regulator_dev **rdev; + struct max77686_data *max77686; + int i, size; + int ret = 0; + struct regulator_config config = { }; + + dev_dbg(&pdev->dev, "%s\n", __func__); + + if (!pdata) { + dev_err(&pdev->dev, "no platform data found for regulator\n"); + return -ENODEV; + } + + if (iodev->dev->of_node) { + ret = max77686_pmic_dt_parse_pdata(iodev, pdata); + if (ret) + return ret; + } + + if (pdata->num_regulators != MAX77686_REGULATORS) { + dev_err(&pdev->dev, + "Invalid initial data for regulator's initialiation\n"); + return -EINVAL; + } + + max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data), + GFP_KERNEL); + if (!max77686) + return -ENOMEM; + + size = sizeof(struct regulator_dev *) * MAX77686_REGULATORS; + max77686->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!max77686->rdev) + return -ENOMEM; + + rdev = max77686->rdev; + config.dev = &pdev->dev; + config.regmap = iodev->regmap; + platform_set_drvdata(pdev, max77686); + + for (i = 0; i < MAX77686_REGULATORS; i++) { + config.init_data = pdata->regulators[i].initdata; + + rdev[i] = regulator_register(®ulators[i], &config); + if (IS_ERR(rdev[i])) { + ret = PTR_ERR(rdev[i]); + dev_err(&pdev->dev, + "regulator init failed for %d\n", i); + rdev[i] = NULL; + goto err; + } + } + + return 0; +err: + while (--i >= 0) + regulator_unregister(rdev[i]); + return ret; +} + +static int __devexit max77686_pmic_remove(struct platform_device *pdev) +{ + struct max77686_data *max77686 = platform_get_drvdata(pdev); + struct regulator_dev **rdev = max77686->rdev; + int i; + + for (i = 0; i < MAX77686_REGULATORS; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + + return 0; +} + +static const struct platform_device_id max77686_pmic_id[] = { + {"max77686-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, max77686_pmic_id); + +static struct platform_driver max77686_pmic_driver = { + .driver = { + .name = "max77686-pmic", + .owner = THIS_MODULE, + }, + .probe = max77686_pmic_probe, + .remove = __devexit_p(max77686_pmic_remove), + .id_table = max77686_pmic_id, +}; + +static int __init max77686_pmic_init(void) +{ + return platform_driver_register(&max77686_pmic_driver); +} +subsys_initcall(max77686_pmic_init); + +static void __exit max77686_pmic_cleanup(void) +{ + platform_driver_unregister(&max77686_pmic_driver); +} +module_exit(max77686_pmic_cleanup); + +MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver"); +MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 910c9b26d49..355ca7bad9d 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -51,7 +51,6 @@ struct max8952_data { bool vid0; bool vid1; - bool en; }; static int max8952_read_reg(struct max8952_data *max8952, u8 reg) @@ -80,38 +79,6 @@ static int max8952_list_voltage(struct regulator_dev *rdev, return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000; } -static int max8952_is_enabled(struct regulator_dev *rdev) -{ - struct max8952_data *max8952 = rdev_get_drvdata(rdev); - return max8952->en; -} - -static int max8952_enable(struct regulator_dev *rdev) -{ - struct max8952_data *max8952 = rdev_get_drvdata(rdev); - - /* If not valid, assume "ALWAYS_HIGH" */ - if (gpio_is_valid(max8952->pdata->gpio_en)) - gpio_set_value(max8952->pdata->gpio_en, 1); - - max8952->en = true; - return 0; -} - -static int max8952_disable(struct regulator_dev *rdev) -{ - struct max8952_data *max8952 = rdev_get_drvdata(rdev); - - /* If not valid, assume "ALWAYS_HIGH" -> not permitted */ - if (gpio_is_valid(max8952->pdata->gpio_en)) - gpio_set_value(max8952->pdata->gpio_en, 0); - else - return -EPERM; - - max8952->en = false; - return 0; -} - static int max8952_get_voltage_sel(struct regulator_dev *rdev) { struct max8952_data *max8952 = rdev_get_drvdata(rdev); @@ -146,12 +113,8 @@ static int max8952_set_voltage_sel(struct regulator_dev *rdev, static struct regulator_ops max8952_ops = { .list_voltage = max8952_list_voltage, - .is_enabled = max8952_is_enabled, - .enable = max8952_enable, - .disable = max8952_disable, .get_voltage_sel = max8952_get_voltage_sel, .set_voltage_sel = max8952_set_voltage_sel, - .set_suspend_disable = max8952_disable, }; static const struct regulator_desc regulator = { @@ -194,6 +157,10 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, config.init_data = &pdata->reg_data; config.driver_data = max8952; + config.ena_gpio = pdata->gpio_en; + if (pdata->reg_data.constraints.boot_on) + config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + max8952->rdev = regulator_register(®ulator, &config); if (IS_ERR(max8952->rdev)) { @@ -202,27 +169,9 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, return ret; } - max8952->en = !!(pdata->reg_data.constraints.boot_on); max8952->vid0 = pdata->default_mode & 0x1; max8952->vid1 = (pdata->default_mode >> 1) & 0x1; - if (gpio_is_valid(pdata->gpio_en)) { - if (!gpio_request(pdata->gpio_en, "MAX8952 EN")) - gpio_direction_output(pdata->gpio_en, max8952->en); - else - err = 1; - } else - err = 2; - - if (err) { - dev_info(max8952->dev, "EN gpio invalid: assume that EN" - "is always High\n"); - max8952->en = 1; - pdata->gpio_en = -1; /* Mark invalid */ - } - - err = 0; - if (gpio_is_valid(pdata->gpio_vid0) && gpio_is_valid(pdata->gpio_vid1)) { if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0")) @@ -308,7 +257,6 @@ static int __devexit max8952_pmic_remove(struct i2c_client *client) gpio_free(pdata->gpio_vid0); gpio_free(pdata->gpio_vid1); - gpio_free(pdata->gpio_en); return 0; } diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 704cd49ef37..e39a0c7260d 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -1025,7 +1025,6 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) */ if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || pdata->buck5_gpiodvs) { - bool gpio1set = false, gpio2set = false; if (!gpio_is_valid(pdata->buck125_gpios[0]) || !gpio_is_valid(pdata->buck125_gpios[1]) || @@ -1035,40 +1034,20 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) goto err_out; } - ret = gpio_request(pdata->buck125_gpios[0], - "MAX8997 SET1"); - if (ret == -EBUSY) - dev_warn(&pdev->dev, "Duplicated gpio request" - " on SET1\n"); - else if (ret) + ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0], + "MAX8997 SET1"); + if (ret) goto err_out; - else - gpio1set = true; - - ret = gpio_request(pdata->buck125_gpios[1], - "MAX8997 SET2"); - if (ret == -EBUSY) - dev_warn(&pdev->dev, "Duplicated gpio request" - " on SET2\n"); - else if (ret) { - if (gpio1set) - gpio_free(pdata->buck125_gpios[0]); + + ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1], + "MAX8997 SET2"); + if (ret) goto err_out; - } else - gpio2set = true; - ret = gpio_request(pdata->buck125_gpios[2], + ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2], "MAX8997 SET3"); - if (ret == -EBUSY) - dev_warn(&pdev->dev, "Duplicated gpio request" - " on SET3\n"); - else if (ret) { - if (gpio1set) - gpio_free(pdata->buck125_gpios[0]); - if (gpio2set) - gpio_free(pdata->buck125_gpios[1]); + if (ret) goto err_out; - } gpio_direction_output(pdata->buck125_gpios[0], (max8997->buck125_gpioindex >> 2) @@ -1079,7 +1058,6 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) gpio_direction_output(pdata->buck125_gpios[2], (max8997->buck125_gpioindex >> 0) & 0x1); /* SET3 */ - ret = 0; } /* DVS-GPIO disabled */ diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 18bb58b9b96..5dfa920ff0c 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -111,27 +111,6 @@ static const struct voltage_map_desc *ldo_voltage_map[] = { &buck4_voltage_map_desc, /* BUCK4 */ }; -static int max8998_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - const struct voltage_map_desc *desc; - int ldo = rdev_get_id(rdev); - int val; - - if (ldo >= ARRAY_SIZE(ldo_voltage_map)) - return -EINVAL; - - desc = ldo_voltage_map[ldo]; - if (desc == NULL) - return -EINVAL; - - val = desc->min + desc->step * selector; - if (val > desc->max) - return -EINVAL; - - return val * 1000; -} - static int max8998_get_enable_register(struct regulator_dev *rdev, int *reg, int *shift) { @@ -297,41 +276,18 @@ static int max8998_get_voltage_sel(struct regulator_dev *rdev) return val; } -static int max8998_set_voltage_ldo(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int max8998_set_voltage_ldo_sel(struct regulator_dev *rdev, + unsigned selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8998->iodev->i2c; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - const struct voltage_map_desc *desc; - int ldo = rdev_get_id(rdev); - int reg, shift = 0, mask, ret, i; - - if (ldo >= ARRAY_SIZE(ldo_voltage_map)) - return -EINVAL; - - desc = ldo_voltage_map[ldo]; - if (desc == NULL) - return -EINVAL; - - if (max_vol < desc->min || min_vol > desc->max) - return -EINVAL; - - if (min_vol < desc->min) - min_vol = desc->min; - - i = DIV_ROUND_UP(min_vol - desc->min, desc->step); - - if (desc->min + desc->step*i > max_vol) - return -EINVAL; - - *selector = i; + int reg, shift = 0, mask, ret; ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; - ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift); + ret = max8998_update_reg(i2c, reg, selector<<shift, mask<<shift); return ret; } @@ -347,41 +303,18 @@ static inline void buck2_gpio_set(int gpio, int v) gpio_set_value(gpio, v & 0x1); } -static int max8998_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev, + unsigned selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct max8998_platform_data *pdata = dev_get_platdata(max8998->iodev->dev); struct i2c_client *i2c = max8998->iodev->i2c; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - const struct voltage_map_desc *desc; int buck = rdev_get_id(rdev); int reg, shift = 0, mask, ret; - int i, j, previous_sel; + int j, previous_sel; static u8 buck1_last_val; - if (buck >= ARRAY_SIZE(ldo_voltage_map)) - return -EINVAL; - - desc = ldo_voltage_map[buck]; - - if (desc == NULL) - return -EINVAL; - - if (max_vol < desc->min || min_vol > desc->max) - return -EINVAL; - - if (min_vol < desc->min) - min_vol = desc->min; - - i = DIV_ROUND_UP(min_vol - desc->min, desc->step); - - if (desc->min + desc->step*i > max_vol) - return -EINVAL; - - *selector = i; - ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; @@ -390,19 +323,19 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, /* Check if voltage needs to be changed */ /* if previous_voltage equal new voltage, return */ - if (previous_sel == i) { + if (previous_sel == selector) { dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n", - max8998_list_voltage(rdev, previous_sel), - max8998_list_voltage(rdev, i)); + regulator_list_voltage_linear(rdev, previous_sel), + regulator_list_voltage_linear(rdev, selector)); return ret; } switch (buck) { case MAX8998_BUCK1: dev_dbg(max8998->dev, - "BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n" + "BUCK1, selector:%d, buck1_vol1:%d, buck1_vol2:%d\n" "buck1_vol3:%d, buck1_vol4:%d\n", - i, max8998->buck1_vol[0], max8998->buck1_vol[1], + selector, max8998->buck1_vol[0], max8998->buck1_vol[1], max8998->buck1_vol[2], max8998->buck1_vol[3]); if (gpio_is_valid(pdata->buck1_set1) && @@ -411,7 +344,7 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, /* check if requested voltage */ /* value is already defined */ for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) { - if (max8998->buck1_vol[j] == i) { + if (max8998->buck1_vol[j] == selector) { max8998->buck1_idx = j; buck1_gpio_set(pdata->buck1_set1, pdata->buck1_set2, j); @@ -426,11 +359,11 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, max8998->buck1_idx = (buck1_last_val % 2) + 2; dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n", max8998->buck1_idx); - max8998->buck1_vol[max8998->buck1_idx] = i; + max8998->buck1_vol[max8998->buck1_idx] = selector; ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); - ret = max8998_write_reg(i2c, reg, i); + ret = max8998_write_reg(i2c, reg, selector); buck1_gpio_set(pdata->buck1_set1, pdata->buck1_set2, max8998->buck1_idx); buck1_last_val++; @@ -440,20 +373,20 @@ buck1_exit: gpio_get_value(pdata->buck1_set2)); break; } else { - ret = max8998_write_reg(i2c, reg, i); + ret = max8998_write_reg(i2c, reg, selector); } break; case MAX8998_BUCK2: dev_dbg(max8998->dev, - "BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n" - , i, max8998->buck2_vol[0], max8998->buck2_vol[1]); + "BUCK2, selector:%d buck2_vol1:%d, buck2_vol2:%d\n", + selector, max8998->buck2_vol[0], max8998->buck2_vol[1]); if (gpio_is_valid(pdata->buck2_set3)) { /* check if requested voltage */ /* value is already defined */ for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) { - if (max8998->buck2_vol[j] == i) { + if (max8998->buck2_vol[j] == selector) { max8998->buck2_idx = j; buck2_gpio_set(pdata->buck2_set3, j); goto buck2_exit; @@ -465,20 +398,21 @@ buck1_exit: max8998_get_voltage_register(rdev, ®, &shift, &mask); - ret = max8998_write_reg(i2c, reg, i); - max8998->buck2_vol[max8998->buck2_idx] = i; + ret = max8998_write_reg(i2c, reg, selector); + max8998->buck2_vol[max8998->buck2_idx] = selector; buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx); buck2_exit: dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name, gpio_get_value(pdata->buck2_set3)); } else { - ret = max8998_write_reg(i2c, reg, i); + ret = max8998_write_reg(i2c, reg, selector); } break; case MAX8998_BUCK3: case MAX8998_BUCK4: - ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift); + ret = max8998_update_reg(i2c, reg, selector<<shift, + mask<<shift); break; } @@ -519,34 +453,30 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev, } static struct regulator_ops max8998_ldo_ops = { - .list_voltage = max8998_list_voltage, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .is_enabled = max8998_ldo_is_enabled, .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, .get_voltage_sel = max8998_get_voltage_sel, - .set_voltage = max8998_set_voltage_ldo, - .set_suspend_enable = max8998_ldo_enable, - .set_suspend_disable = max8998_ldo_disable, + .set_voltage_sel = max8998_set_voltage_ldo_sel, }; static struct regulator_ops max8998_buck_ops = { - .list_voltage = max8998_list_voltage, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .is_enabled = max8998_ldo_is_enabled, .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, .get_voltage_sel = max8998_get_voltage_sel, - .set_voltage = max8998_set_voltage_buck, + .set_voltage_sel = max8998_set_voltage_buck_sel, .set_voltage_time_sel = max8998_set_voltage_buck_time_sel, - .set_suspend_enable = max8998_ldo_enable, - .set_suspend_disable = max8998_ldo_disable, }; static struct regulator_ops max8998_others_ops = { .is_enabled = max8998_ldo_is_enabled, .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, - .set_suspend_enable = max8998_ldo_enable, - .set_suspend_disable = max8998_ldo_disable, }; static struct regulator_desc regulators[] = { @@ -860,7 +790,10 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) desc = ldo_voltage_map[id]; if (desc && regulators[index].ops != &max8998_others_ops) { int count = (desc->max - desc->min) / desc->step + 1; + regulators[index].n_voltages = count; + regulators[index].min_uV = desc->min * 1000; + regulators[index].uV_step = desc->step * 1000; } config.dev = max8998->dev; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 7dcdfa283e9..4932e3449fe 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -93,78 +93,78 @@ /* Voltage Values */ -static const int mc13783_sw3_val[] = { +static const unsigned int mc13783_sw3_val[] = { 5000000, 5000000, 5000000, 5500000, }; -static const int mc13783_vaudio_val[] = { +static const unsigned int mc13783_vaudio_val[] = { 2775000, }; -static const int mc13783_viohi_val[] = { +static const unsigned int mc13783_viohi_val[] = { 2775000, }; -static const int mc13783_violo_val[] = { +static const unsigned int mc13783_violo_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int mc13783_vdig_val[] = { +static const unsigned int mc13783_vdig_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int mc13783_vgen_val[] = { +static const unsigned int mc13783_vgen_val[] = { 1200000, 1300000, 1500000, 1800000, 1100000, 2000000, 2775000, 2400000, }; -static const int mc13783_vrfdig_val[] = { +static const unsigned int mc13783_vrfdig_val[] = { 1200000, 1500000, 1800000, 1875000, }; -static const int mc13783_vrfref_val[] = { +static const unsigned int mc13783_vrfref_val[] = { 2475000, 2600000, 2700000, 2775000, }; -static const int mc13783_vrfcp_val[] = { +static const unsigned int mc13783_vrfcp_val[] = { 2700000, 2775000, }; -static const int mc13783_vsim_val[] = { +static const unsigned int mc13783_vsim_val[] = { 1800000, 2900000, 3000000, }; -static const int mc13783_vesim_val[] = { +static const unsigned int mc13783_vesim_val[] = { 1800000, 2900000, }; -static const int mc13783_vcam_val[] = { +static const unsigned int mc13783_vcam_val[] = { 1500000, 1800000, 2500000, 2550000, 2600000, 2750000, 2800000, 3000000, }; -static const int mc13783_vrfbg_val[] = { +static const unsigned int mc13783_vrfbg_val[] = { 1250000, }; -static const int mc13783_vvib_val[] = { +static const unsigned int mc13783_vvib_val[] = { 1300000, 1800000, 2000000, 3000000, }; -static const int mc13783_vmmc_val[] = { +static const unsigned int mc13783_vmmc_val[] = { 1600000, 1800000, 2000000, 2600000, 2700000, 2800000, 2900000, 3000000, }; -static const int mc13783_vrf_val[] = { +static const unsigned int mc13783_vrf_val[] = { 1500000, 1875000, 2700000, 2775000, }; -static const int mc13783_gpo_val[] = { +static const unsigned int mc13783_gpo_val[] = { 3100000, }; -static const int mc13783_pwgtdrv_val[] = { +static const unsigned int mc13783_pwgtdrv_val[] = { 5500000, }; @@ -328,7 +328,7 @@ static struct regulator_ops mc13783_gpo_regulator_ops = { .enable = mc13783_gpo_regulator_enable, .disable = mc13783_gpo_regulator_disable, .is_enabled = mc13783_gpo_regulator_is_enabled, - .list_voltage = mc13xxx_regulator_list_voltage, + .list_voltage = regulator_list_voltage_table, .set_voltage = mc13xxx_fixed_regulator_set_voltage, .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 970a233dbe4..b388b746452 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -150,12 +150,12 @@ #define MC13892_USB1 50 #define MC13892_USB1_VUSBEN (1<<3) -static const int mc13892_vcoincell[] = { +static const unsigned int mc13892_vcoincell[] = { 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, }; -static const int mc13892_sw1[] = { +static const unsigned int mc13892_sw1[] = { 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 1000000, 1025000, @@ -164,7 +164,7 @@ static const int mc13892_sw1[] = { 1350000, 1375000 }; -static const int mc13892_sw[] = { +static const unsigned int mc13892_sw[] = { 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 1000000, 1025000, @@ -176,65 +176,65 @@ static const int mc13892_sw[] = { 1800000, 1825000, 1850000, 1875000 }; -static const int mc13892_swbst[] = { +static const unsigned int mc13892_swbst[] = { 5000000, }; -static const int mc13892_viohi[] = { +static const unsigned int mc13892_viohi[] = { 2775000, }; -static const int mc13892_vpll[] = { +static const unsigned int mc13892_vpll[] = { 1050000, 1250000, 1650000, 1800000, }; -static const int mc13892_vdig[] = { +static const unsigned int mc13892_vdig[] = { 1050000, 1250000, 1650000, 1800000, }; -static const int mc13892_vsd[] = { +static const unsigned int mc13892_vsd[] = { 1800000, 2000000, 2600000, 2700000, 2800000, 2900000, 3000000, 3150000, }; -static const int mc13892_vusb2[] = { +static const unsigned int mc13892_vusb2[] = { 2400000, 2600000, 2700000, 2775000, }; -static const int mc13892_vvideo[] = { +static const unsigned int mc13892_vvideo[] = { 2700000, 2775000, 2500000, 2600000, }; -static const int mc13892_vaudio[] = { +static const unsigned int mc13892_vaudio[] = { 2300000, 2500000, 2775000, 3000000, }; -static const int mc13892_vcam[] = { +static const unsigned int mc13892_vcam[] = { 2500000, 2600000, 2750000, 3000000, }; -static const int mc13892_vgen1[] = { +static const unsigned int mc13892_vgen1[] = { 1200000, 1500000, 2775000, 3150000, }; -static const int mc13892_vgen2[] = { +static const unsigned int mc13892_vgen2[] = { 1200000, 1500000, 1600000, 1800000, 2700000, 2800000, 3000000, 3150000, }; -static const int mc13892_vgen3[] = { +static const unsigned int mc13892_vgen3[] = { 1800000, 2900000, }; -static const int mc13892_vusb[] = { +static const unsigned int mc13892_vusb[] = { 3300000, }; -static const int mc13892_gpo[] = { +static const unsigned int mc13892_gpo[] = { 2750000, }; -static const int mc13892_pwgtdrv[] = { +static const unsigned int mc13892_pwgtdrv[] = { 5000000, }; @@ -394,7 +394,7 @@ static struct regulator_ops mc13892_gpo_regulator_ops = { .enable = mc13892_gpo_regulator_enable, .disable = mc13892_gpo_regulator_disable, .is_enabled = mc13892_gpo_regulator_is_enabled, - .list_voltage = mc13xxx_regulator_list_voltage, + .list_voltage = regulator_list_voltage_table, .set_voltage = mc13xxx_fixed_regulator_set_voltage, .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; @@ -436,7 +436,7 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, u32 valread; int ret; - value = mc13892_regulators[id].voltages[selector]; + value = rdev->desc->volt_table[selector]; mc13xxx_lock(priv->mc13xxx); ret = mc13xxx_reg_read(priv->mc13xxx, @@ -469,8 +469,7 @@ err: } static struct regulator_ops mc13892_sw_regulator_ops = { - .is_enabled = mc13xxx_sw_regulator_is_enabled, - .list_voltage = mc13xxx_regulator_list_voltage, + .list_voltage = regulator_list_voltage_table, .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel, .get_voltage = mc13892_sw_regulator_get_voltage, }; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 4fa9704739b..d6eda28ca5d 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -80,20 +80,6 @@ static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev) return (val & mc13xxx_regulators[id].enable_bit) != 0; } -int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - int id = rdev_get_id(rdev); - struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); - struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; - - if (selector >= mc13xxx_regulators[id].desc.n_voltages) - return -EINVAL; - - return mc13xxx_regulators[id].voltages[selector]; -} -EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage); - static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { @@ -135,14 +121,14 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages); - return mc13xxx_regulators[id].voltages[val]; + return rdev->desc->volt_table[val]; } struct regulator_ops mc13xxx_regulator_ops = { .enable = mc13xxx_regulator_enable, .disable = mc13xxx_regulator_disable, .is_enabled = mc13xxx_regulator_is_enabled, - .list_voltage = mc13xxx_regulator_list_voltage, + .list_voltage = regulator_list_voltage_table, .set_voltage_sel = mc13xxx_regulator_set_voltage_sel, .get_voltage = mc13xxx_regulator_get_voltage, }; @@ -151,15 +137,13 @@ EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops); int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { - struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); - struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", __func__, id, min_uV, max_uV); - if (min_uV >= mc13xxx_regulators[id].voltages[0] && - max_uV <= mc13xxx_regulators[id].voltages[0]) + if (min_uV <= rdev->desc->volt_table[0] && + rdev->desc->volt_table[0] <= max_uV) return 0; else return -EINVAL; @@ -168,13 +152,11 @@ EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) { - struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); - struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - return mc13xxx_regulators[id].voltages[0]; + return rdev->desc->volt_table[0]; } EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage); @@ -182,18 +164,12 @@ struct regulator_ops mc13xxx_fixed_regulator_ops = { .enable = mc13xxx_regulator_enable, .disable = mc13xxx_regulator_disable, .is_enabled = mc13xxx_regulator_is_enabled, - .list_voltage = mc13xxx_regulator_list_voltage, + .list_voltage = regulator_list_voltage_table, .set_voltage = mc13xxx_fixed_regulator_set_voltage, .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); -int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev) -{ - return 1; -} -EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled); - #ifdef CONFIG_OF int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev) { diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h index 044aba4d28e..eaff5510b6d 100644 --- a/drivers/regulator/mc13xxx.h +++ b/drivers/regulator/mc13xxx.h @@ -22,7 +22,6 @@ struct mc13xxx_regulator { int vsel_shift; int vsel_mask; int hi_bit; - int const *voltages; }; struct mc13xxx_regulator_priv { @@ -33,10 +32,6 @@ struct mc13xxx_regulator_priv { struct regulator_dev *regulators[]; }; -extern int mc13xxx_sw_regulator(struct regulator_dev *rdev); -extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev); -extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, - unsigned selector); extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector); extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev); @@ -68,6 +63,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; .desc = { \ .name = #_name, \ .n_voltages = ARRAY_SIZE(_voltages), \ + .volt_table = _voltages, \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ .id = prefix ## _name, \ @@ -78,7 +74,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; .vsel_reg = prefix ## _vsel_reg, \ .vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\ .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\ - .voltages = _voltages, \ } #define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \ @@ -86,6 +81,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; .desc = { \ .name = #_name, \ .n_voltages = ARRAY_SIZE(_voltages), \ + .volt_table = _voltages, \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ .id = prefix ## _name, \ @@ -93,7 +89,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; }, \ .reg = prefix ## _reg, \ .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ } #define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \ @@ -101,6 +96,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; .desc = { \ .name = #_name, \ .n_voltages = ARRAY_SIZE(_voltages), \ + .volt_table = _voltages, \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ .id = prefix ## _name, \ @@ -108,7 +104,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; }, \ .reg = prefix ## _reg, \ .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ } #define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops) \ diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 56593b75168..3e4106f2bda 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -20,7 +20,7 @@ static void of_get_regulation_constraints(struct device_node *np, struct regulator_init_data **init_data) { const __be32 *min_uV, *max_uV, *uV_offset; - const __be32 *min_uA, *max_uA; + const __be32 *min_uA, *max_uA, *ramp_delay; struct regulation_constraints *constraints = &(*init_data)->constraints; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -60,6 +60,10 @@ static void of_get_regulation_constraints(struct device_node *np, constraints->always_on = true; else /* status change should be possible if not always on. */ constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS; + + ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL); + if (ramp_delay) + constraints->ramp_delay = be32_to_cpu(*ramp_delay); } /** @@ -88,15 +92,17 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, EXPORT_SYMBOL_GPL(of_get_regulator_init_data); /** - * of_regulator_match - extract regulator init data + * of_regulator_match - extract regulator init data when node + * property "regulator-compatible" matches with the regulator name. * @dev: device requesting the data * @node: parent device node of the regulators * @matches: match table for the regulators * @num_matches: number of entries in match table * * This function uses a match table specified by the regulator driver and - * looks up the corresponding init data in the device tree. Note that the - * match table is modified in place. + * looks up the corresponding init data in the device tree if + * regulator-compatible matches. Note that the match table is modified + * in place. * * Returns the number of matches found or a negative error code on failure. */ @@ -106,27 +112,40 @@ int of_regulator_match(struct device *dev, struct device_node *node, { unsigned int count = 0; unsigned int i; + const char *regulator_comp; + struct device_node *child; if (!dev || !node) return -EINVAL; - for (i = 0; i < num_matches; i++) { - struct of_regulator_match *match = &matches[i]; - struct device_node *child; - - child = of_find_node_by_name(node, match->name); - if (!child) - continue; - - match->init_data = of_get_regulator_init_data(dev, child); - if (!match->init_data) { - dev_err(dev, "failed to parse DT for regulator %s\n", + for_each_child_of_node(node, child) { + regulator_comp = of_get_property(child, + "regulator-compatible", NULL); + if (!regulator_comp) { + dev_err(dev, "regulator-compatible is missing for node %s\n", child->name); - return -EINVAL; + continue; + } + for (i = 0; i < num_matches; i++) { + struct of_regulator_match *match = &matches[i]; + if (match->of_node) + continue; + + if (strcmp(match->name, regulator_comp)) + continue; + + match->init_data = + of_get_regulator_init_data(dev, child); + if (!match->init_data) { + dev_err(dev, + "failed to parse DT for regulator %s\n", + child->name); + return -EINVAL; + } + match->of_node = child; + count++; + break; } - - match->of_node = child; - count++; } return count; diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 795f75a6ac3..17d19fbbc49 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -257,8 +257,7 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) unsigned int reg; palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); - reg &= ~PALMAS_SMPS12_CTRL_STATUS_MASK; - reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT; + reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; switch (mode) { case REGULATOR_MODE_NORMAL: @@ -374,11 +373,22 @@ static int palmas_set_voltage_smps_sel(struct regulator_dev *dev, static int palmas_map_voltage_smps(struct regulator_dev *rdev, int min_uV, int max_uV) { + struct palmas_pmic *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); int ret, voltage; - ret = ((min_uV - 500000) / 10000) + 1; - if (ret < 0) - return ret; + if (min_uV == 0) + return 0; + + if (pmic->range[id]) { /* RANGE is x2 */ + if (min_uV < 1000000) + min_uV = 1000000; + ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 1; + } else { /* RANGE is x1 */ + if (min_uV < 500000) + min_uV = 500000; + ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 1; + } /* Map back into a voltage to verify we're still in bounds */ voltage = palmas_list_voltage_smps(rdev, ret); @@ -400,19 +410,14 @@ static struct regulator_ops palmas_ops_smps = { .map_voltage = palmas_map_voltage_smps, }; -static int palmas_list_voltage_smps10(struct regulator_dev *dev, - unsigned selector) -{ - return 3750000 + (selector * 1250000); -} - static struct regulator_ops palmas_ops_smps10 = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .list_voltage = palmas_list_voltage_smps10, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, }; static int palmas_is_enabled_ldo(struct regulator_dev *dev) @@ -522,7 +527,15 @@ static int palmas_smps_init(struct palmas *palmas, int id, if (ret) return ret; - if (id != PALMAS_REG_SMPS10) { + switch (id) { + case PALMAS_REG_SMPS10: + if (reg_init->mode_sleep) { + reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK; + reg |= reg_init->mode_sleep << + PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT; + } + break; + default: if (reg_init->warm_reset) reg |= PALMAS_SMPS12_CTRL_WR_S; @@ -534,14 +547,8 @@ static int palmas_smps_init(struct palmas *palmas, int id, reg |= reg_init->mode_sleep << PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT; } - } else { - if (reg_init->mode_sleep) { - reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK; - reg |= reg_init->mode_sleep << - PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT; - } - } + ret = palmas_smps_write(palmas, addr, reg); if (ret) return ret; @@ -665,10 +672,8 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->desc[id].name = palmas_regs_info[id].name; pmic->desc[id].id = id; - if (id != PALMAS_REG_SMPS10) { - pmic->desc[id].ops = &palmas_ops_smps; - pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; - } else { + switch (id) { + case PALMAS_REG_SMPS10: pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES; pmic->desc[id].ops = &palmas_ops_smps10; pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL; @@ -677,6 +682,12 @@ static __devinit int palmas_probe(struct platform_device *pdev) PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, PALMAS_SMPS10_STATUS); pmic->desc[id].enable_mask = SMPS10_BOOST_EN; + pmic->desc[id].min_uV = 3750000; + pmic->desc[id].uV_step = 1250000; + break; + default: + pmic->desc[id].ops = &palmas_ops_smps; + pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; } pmic->desc[id].type = REGULATOR_VOLTAGE; diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 8211101121f..68777acc099 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -18,80 +18,80 @@ #include <linux/regulator/machine.h> #include <linux/mfd/ezx-pcap.h> -static const u16 V1_table[] = { - 2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275, +static const unsigned int V1_table[] = { + 2775000, 1275000, 1600000, 1725000, 1825000, 1925000, 2075000, 2275000, }; -static const u16 V2_table[] = { - 2500, 2775, +static const unsigned int V2_table[] = { + 2500000, 2775000, }; -static const u16 V3_table[] = { - 1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275, +static const unsigned int V3_table[] = { + 1075000, 1275000, 1550000, 1725000, 1876000, 1950000, 2075000, 2275000, }; -static const u16 V4_table[] = { - 1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775, +static const unsigned int V4_table[] = { + 1275000, 1550000, 1725000, 1875000, 1950000, 2075000, 2275000, 2775000, }; -static const u16 V5_table[] = { - 1875, 2275, 2475, 2775, +static const unsigned int V5_table[] = { + 1875000, 2275000, 2475000, 2775000, }; -static const u16 V6_table[] = { - 2475, 2775, +static const unsigned int V6_table[] = { + 2475000, 2775000, }; -static const u16 V7_table[] = { - 1875, 2775, +static const unsigned int V7_table[] = { + 1875000, 2775000, }; #define V8_table V4_table -static const u16 V9_table[] = { - 1575, 1875, 2475, 2775, +static const unsigned int V9_table[] = { + 1575000, 1875000, 2475000, 2775000, }; -static const u16 V10_table[] = { - 5000, +static const unsigned int V10_table[] = { + 5000000, }; -static const u16 VAUX1_table[] = { - 1875, 2475, 2775, 3000, +static const unsigned int VAUX1_table[] = { + 1875000, 2475000, 2775000, 3000000, }; #define VAUX2_table VAUX1_table -static const u16 VAUX3_table[] = { - 1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000, - 2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600, +static const unsigned int VAUX3_table[] = { + 1200000, 1200000, 1200000, 1200000, 1400000, 1600000, 1800000, 2000000, + 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 3600000, }; -static const u16 VAUX4_table[] = { - 1800, 1800, 3000, 5000, +static const unsigned int VAUX4_table[] = { + 1800000, 1800000, 3000000, 5000000, }; -static const u16 VSIM_table[] = { - 1875, 3000, +static const unsigned int VSIM_table[] = { + 1875000, 3000000, }; -static const u16 VSIM2_table[] = { - 1875, +static const unsigned int VSIM2_table[] = { + 1875000, }; -static const u16 VVIB_table[] = { - 1300, 1800, 2000, 3000, +static const unsigned int VVIB_table[] = { + 1300000, 1800000, 2000000, 3000000, }; -static const u16 SW1_table[] = { - 900, 950, 1000, 1050, 1100, 1150, 1200, 1250, - 1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250, +static const unsigned int SW1_table[] = { + 900000, 950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, + 1300000, 1350000, 1400000, 1450000, 1500000, 1600000, 1875000, 2250000, }; #define SW2_table SW1_table -static const u16 SW3_table[] = { - 4000, 4500, 5000, 5500, +static const unsigned int SW3_table[] = { + 4000000, 4500000, 5000000, 5500000, }; struct pcap_regulator { @@ -100,8 +100,6 @@ struct pcap_regulator { const u8 index; const u8 stby; const u8 lowpwr; - const u8 n_voltages; - const u16 *voltage_table; }; #define NA 0xff @@ -113,8 +111,6 @@ struct pcap_regulator { .index = _index, \ .stby = _stby, \ .lowpwr = _lowpwr, \ - .n_voltages = ARRAY_SIZE(_vreg##_table), \ - .voltage_table = _vreg##_table, \ } static struct pcap_regulator vreg_table[] = { @@ -157,11 +153,11 @@ static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev, void *pcap = rdev_get_drvdata(rdev); /* the regulator doesn't support voltage switching */ - if (vreg->n_voltages == 1) + if (rdev->desc->n_voltages == 1) return -EINVAL; return ezx_pcap_set_bits(pcap, vreg->reg, - (vreg->n_voltages - 1) << vreg->index, + (rdev->desc->n_voltages - 1) << vreg->index, selector << vreg->index); } @@ -171,11 +167,11 @@ static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev) void *pcap = rdev_get_drvdata(rdev); u32 tmp; - if (vreg->n_voltages == 1) + if (rdev->desc->n_voltages == 1) return 0; ezx_pcap_read(pcap, vreg->reg, &tmp); - tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1)); + tmp = ((tmp >> vreg->index) & (rdev->desc->n_voltages - 1)); return tmp; } @@ -214,16 +210,8 @@ static int pcap_regulator_is_enabled(struct regulator_dev *rdev) return (tmp >> vreg->en) & 1; } -static int pcap_regulator_list_voltage(struct regulator_dev *rdev, - unsigned int index) -{ - struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; - - return vreg->voltage_table[index] * 1000; -} - static struct regulator_ops pcap_regulator_ops = { - .list_voltage = pcap_regulator_list_voltage, + .list_voltage = regulator_list_voltage_table, .set_voltage_sel = pcap_regulator_set_voltage_sel, .get_voltage_sel = pcap_regulator_get_voltage_sel, .enable = pcap_regulator_enable, @@ -236,6 +224,7 @@ static struct regulator_ops pcap_regulator_ops = { .name = #_vreg, \ .id = _vreg, \ .n_voltages = ARRAY_SIZE(_vreg##_table), \ + .volt_table = _vreg##_table, \ .ops = &pcap_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 3c9d14c0017..092e5cb848a 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -100,13 +100,12 @@ static unsigned int ldo_voltage_value(u8 bits) return 900 + (bits * 100); } -static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) +static int pcf50633_regulator_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { struct pcf50633 *pcf; int regulator_id, millivolts; - u8 volt_bits, regnr; + u8 volt_bits; pcf = rdev_get_drvdata(rdev); @@ -116,15 +115,11 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, millivolts = min_uV / 1000; - regnr = rdev->desc->vsel_reg; - switch (regulator_id) { case PCF50633_REGULATOR_AUTO: volt_bits = auto_voltage_bits(millivolts); break; case PCF50633_REGULATOR_DOWN1: - volt_bits = down_voltage_bits(millivolts); - break; case PCF50633_REGULATOR_DOWN2: volt_bits = down_voltage_bits(millivolts); break; @@ -142,9 +137,7 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, return -EINVAL; } - *selector = volt_bits; - - return pcf50633_reg_write(pcf, regnr, volt_bits); + return volt_bits; } static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, @@ -159,8 +152,6 @@ static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, millivolts = auto_voltage_value(index); break; case PCF50633_REGULATOR_DOWN1: - millivolts = down_voltage_value(index); - break; case PCF50633_REGULATOR_DOWN2: millivolts = down_voltage_value(index); break; @@ -182,9 +173,10 @@ static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, } static struct regulator_ops pcf50633_regulator_ops = { - .set_voltage = pcf50633_regulator_set_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = pcf50633_regulator_list_voltage, + .map_voltage = pcf50633_regulator_map_voltage, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 1d34e64a130..8bf4e8c9de9 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -42,7 +42,6 @@ struct rc5t583_regulator_info { /* Regulator specific turn-on delay and voltage settling time*/ int enable_uv_per_us; - int change_uv_per_us; /* Used by regulator core */ struct regulator_desc desc; @@ -66,25 +65,6 @@ static int rc5t583_regulator_enable_time(struct regulator_dev *rdev) return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us); } -static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev, - unsigned int old_selector, unsigned int new_selector) -{ - struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); - int old_uV, new_uV; - old_uV = regulator_list_voltage_linear(rdev, old_selector); - - if (old_uV < 0) - return old_uV; - - new_uV = regulator_list_voltage_linear(rdev, new_selector); - if (new_uV < 0) - return new_uV; - - return DIV_ROUND_UP(abs(old_uV - new_uV), - reg->reg_info->change_uv_per_us); -} - - static struct regulator_ops rc5t583_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, @@ -94,7 +74,7 @@ static struct regulator_ops rc5t583_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, - .set_voltage_time_sel = rc5t583_set_voltage_time_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, }; #define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, \ @@ -104,7 +84,6 @@ static struct regulator_ops rc5t583_ops = { .disc_bit = _disc_bit, \ .deepsleep_reg = RC5T583_REG_##_id##DAC_DS, \ .enable_uv_per_us = _enable_mv * 1000, \ - .change_uv_per_us = 40 * 1000, \ .deepsleep_id = RC5T583_DS_##_id, \ .desc = { \ .name = "rc5t583-regulator-"#_id, \ @@ -119,6 +98,7 @@ static struct regulator_ops rc5t583_ops = { .enable_mask = BIT(_en_bit), \ .min_uV = _min_mv * 1000, \ .uV_step = _step_uV, \ + .ramp_delay = 40 * 1000, \ }, \ } diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c new file mode 100644 index 00000000000..4669dc9ac74 --- /dev/null +++ b/drivers/regulator/s2mps11.c @@ -0,0 +1,363 @@ +/* + * s2mps11.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/s2mps11.h> + +struct s2mps11_info { + struct regulator_dev **rdev; + + int ramp_delay2; + int ramp_delay34; + int ramp_delay5; + int ramp_delay16; + int ramp_delay7810; + int ramp_delay9; + + bool buck6_ramp; + bool buck2_ramp; + bool buck3_ramp; + bool buck4_ramp; +}; + +static int get_ramp_delay(int ramp_delay) +{ + unsigned char cnt = 0; + + ramp_delay /= 6; + + while (true) { + ramp_delay = ramp_delay >> 1; + if (ramp_delay == 0) + break; + cnt++; + } + return cnt; +} + +static struct regulator_ops s2mps11_ldo_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops s2mps11_buck_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +#define regulator_desc_ldo1(num) { \ + .name = "LDO"#num, \ + .id = S2MPS11_LDO##num, \ + .ops = &s2mps11_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS11_LDO_MIN, \ + .uV_step = S2MPS11_LDO_STEP1, \ + .n_voltages = S2MPS11_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS11_LDO_VSEL_MASK, \ + .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS11_ENABLE_MASK \ +} +#define regulator_desc_ldo2(num) { \ + .name = "LDO"#num, \ + .id = S2MPS11_LDO##num, \ + .ops = &s2mps11_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS11_LDO_MIN, \ + .uV_step = S2MPS11_LDO_STEP2, \ + .n_voltages = S2MPS11_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS11_LDO_VSEL_MASK, \ + .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS11_ENABLE_MASK \ +} + +#define regulator_desc_buck1_4(num) { \ + .name = "BUCK"#num, \ + .id = S2MPS11_BUCK##num, \ + .ops = &s2mps11_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS11_BUCK_MIN1, \ + .uV_step = S2MPS11_BUCK_STEP1, \ + .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \ + .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS11_REG_B1CTRL1 + (num - 1) * 2, \ + .enable_mask = S2MPS11_ENABLE_MASK \ +} + +#define regulator_desc_buck5 { \ + .name = "BUCK5", \ + .id = S2MPS11_BUCK5, \ + .ops = &s2mps11_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS11_BUCK_MIN1, \ + .uV_step = S2MPS11_BUCK_STEP1, \ + .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .vsel_reg = S2MPS11_REG_B5CTRL2, \ + .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS11_REG_B5CTRL1, \ + .enable_mask = S2MPS11_ENABLE_MASK \ +} + +#define regulator_desc_buck6_8(num) { \ + .name = "BUCK"#num, \ + .id = S2MPS11_BUCK##num, \ + .ops = &s2mps11_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS11_BUCK_MIN1, \ + .uV_step = S2MPS11_BUCK_STEP1, \ + .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \ + .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS11_REG_B6CTRL1 + (num - 6) * 2, \ + .enable_mask = S2MPS11_ENABLE_MASK \ +} + +#define regulator_desc_buck9 { \ + .name = "BUCK9", \ + .id = S2MPS11_BUCK9, \ + .ops = &s2mps11_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS11_BUCK_MIN3, \ + .uV_step = S2MPS11_BUCK_STEP3, \ + .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .vsel_reg = S2MPS11_REG_B9CTRL2, \ + .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS11_REG_B9CTRL1, \ + .enable_mask = S2MPS11_ENABLE_MASK \ +} + +#define regulator_desc_buck10 { \ + .name = "BUCK10", \ + .id = S2MPS11_BUCK10, \ + .ops = &s2mps11_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS11_BUCK_MIN2, \ + .uV_step = S2MPS11_BUCK_STEP2, \ + .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .vsel_reg = S2MPS11_REG_B9CTRL2, \ + .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS11_REG_B9CTRL1, \ + .enable_mask = S2MPS11_ENABLE_MASK \ +} + +static struct regulator_desc regulators[] = { + regulator_desc_ldo2(1), + regulator_desc_ldo1(2), + regulator_desc_ldo1(3), + regulator_desc_ldo1(4), + regulator_desc_ldo1(5), + regulator_desc_ldo2(6), + regulator_desc_ldo1(7), + regulator_desc_ldo1(8), + regulator_desc_ldo1(9), + regulator_desc_ldo1(10), + regulator_desc_ldo2(11), + regulator_desc_ldo1(12), + regulator_desc_ldo1(13), + regulator_desc_ldo1(14), + regulator_desc_ldo1(15), + regulator_desc_ldo1(16), + regulator_desc_ldo1(17), + regulator_desc_ldo1(18), + regulator_desc_ldo1(19), + regulator_desc_ldo1(20), + regulator_desc_ldo1(21), + regulator_desc_ldo2(22), + regulator_desc_ldo2(23), + regulator_desc_ldo1(24), + regulator_desc_ldo1(25), + regulator_desc_ldo1(26), + regulator_desc_ldo2(27), + regulator_desc_ldo1(28), + regulator_desc_ldo1(29), + regulator_desc_ldo1(30), + regulator_desc_ldo1(31), + regulator_desc_ldo1(32), + regulator_desc_ldo1(33), + regulator_desc_ldo1(34), + regulator_desc_ldo1(35), + regulator_desc_ldo1(36), + regulator_desc_ldo1(37), + regulator_desc_ldo1(38), + regulator_desc_buck1_4(1), + regulator_desc_buck1_4(2), + regulator_desc_buck1_4(3), + regulator_desc_buck1_4(4), + regulator_desc_buck5, + regulator_desc_buck6_8(6), + regulator_desc_buck6_8(7), + regulator_desc_buck6_8(8), + regulator_desc_buck9, + regulator_desc_buck10, +}; + +static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) +{ + struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); + struct regulator_config config = { }; + struct regulator_dev **rdev; + struct s2mps11_info *s2mps11; + int i, ret, size; + unsigned char ramp_enable, ramp_reg = 0; + + if (!pdata) { + dev_err(pdev->dev.parent, "Platform data not supplied\n"); + return -ENODEV; + } + + s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), + GFP_KERNEL); + if (!s2mps11) + return -ENOMEM; + + size = sizeof(struct regulator_dev *) * S2MPS11_REGULATOR_MAX; + s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!s2mps11->rdev) { + return -ENOMEM; + } + + rdev = s2mps11->rdev; + platform_set_drvdata(pdev, s2mps11); + + s2mps11->ramp_delay2 = pdata->buck2_ramp_delay; + s2mps11->ramp_delay34 = pdata->buck34_ramp_delay; + s2mps11->ramp_delay5 = pdata->buck5_ramp_delay; + s2mps11->ramp_delay16 = pdata->buck16_ramp_delay; + s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay; + s2mps11->ramp_delay9 = pdata->buck9_ramp_delay; + + s2mps11->buck6_ramp = pdata->buck6_ramp_enable; + s2mps11->buck2_ramp = pdata->buck2_ramp_enable; + s2mps11->buck3_ramp = pdata->buck3_ramp_enable; + s2mps11->buck4_ramp = pdata->buck4_ramp_enable; + + ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) | + (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ; + + if (ramp_enable) { + if (s2mps11->buck2_ramp) + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) >> 6; + if (s2mps11->buck3_ramp || s2mps11->buck4_ramp) + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) >> 4; + sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable); + } + + ramp_reg &= 0x00; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) >> 6; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) >> 4; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) >> 2; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9); + sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg); + + for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { + + config.dev = &pdev->dev; + config.regmap = iodev->regmap; + config.init_data = pdata->regulators[i].initdata; + config.driver_data = s2mps11; + + rdev[i] = regulator_register(®ulators[i], &config); + if (IS_ERR(rdev[i])) { + ret = PTR_ERR(rdev[i]); + dev_err(&pdev->dev, "regulator init failed for %d\n", + i); + rdev[i] = NULL; + goto err; + } + } + + return 0; +err: + for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + + return ret; +} + +static int __devexit s2mps11_pmic_remove(struct platform_device *pdev) +{ + struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); + struct regulator_dev **rdev = s2mps11->rdev; + int i; + + for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + + return 0; +} + +static const struct platform_device_id s2mps11_pmic_id[] = { + { "s2mps11-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id); + +static struct platform_driver s2mps11_pmic_driver = { + .driver = { + .name = "s2mps11-pmic", + .owner = THIS_MODULE, + }, + .probe = s2mps11_pmic_probe, + .remove = __devexit_p(s2mps11_pmic_remove), + .id_table = s2mps11_pmic_id, +}; + +static int __init s2mps11_pmic_init(void) +{ + return platform_driver_register(&s2mps11_pmic_driver); +} +subsys_initcall(s2mps11_pmic_init); + +static void __exit s2mps11_pmic_exit(void) +{ + platform_driver_unregister(&s2mps11_pmic_driver); +} +module_exit(s2mps11_pmic_exit); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 9caadb48217..102287fa7ec 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -41,6 +41,7 @@ struct s5m8767_info { u8 buck3_vol[8]; u8 buck4_vol[8]; int buck_gpios[3]; + int buck_ds[3]; int buck_gpioindex; }; @@ -120,27 +121,6 @@ static const struct s5m_voltage_desc *reg_voltage_map[] = { [S5M8767_BUCK9] = &buck_voltage_val3, }; -static int s5m8767_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - const struct s5m_voltage_desc *desc; - int reg_id = rdev_get_id(rdev); - int val; - - if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0) - return -EINVAL; - - desc = reg_voltage_map[reg_id]; - if (desc == NULL) - return -EINVAL; - - val = desc->min + desc->step * selector; - if (val > desc->max) - return -EINVAL; - - return val; -} - static unsigned int s5m8767_opmode_reg[][4] = { /* {OFF, ON, LOWPOWER, SUSPEND} */ /* LDO1 ... LDO28 */ @@ -283,17 +263,17 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) reg = S5M8767_REG_BUCK1CTRL2; break; case S5M8767_BUCK2: - reg = S5M8767_REG_BUCK2DVS1; + reg = S5M8767_REG_BUCK2DVS2; if (s5m8767->buck2_gpiodvs) reg += s5m8767->buck_gpioindex; break; case S5M8767_BUCK3: - reg = S5M8767_REG_BUCK3DVS1; + reg = S5M8767_REG_BUCK3DVS2; if (s5m8767->buck3_gpiodvs) reg += s5m8767->buck_gpioindex; break; case S5M8767_BUCK4: - reg = S5M8767_REG_BUCK4DVS1; + reg = S5M8767_REG_BUCK4DVS2; if (s5m8767->buck4_gpiodvs) reg += s5m8767->buck_gpioindex; break; @@ -357,32 +337,34 @@ static int s5m8767_convert_voltage_to_sel( return selector; } -static inline void s5m8767_set_high(struct s5m8767_info *s5m8767) +static inline int s5m8767_set_high(struct s5m8767_info *s5m8767) { int temp_index = s5m8767->buck_gpioindex; gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); + + return 0; } -static inline void s5m8767_set_low(struct s5m8767_info *s5m8767) +static inline int s5m8767_set_low(struct s5m8767_info *s5m8767) { int temp_index = s5m8767->buck_gpioindex; gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); + + return 0; } -static int s5m8767_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - const struct s5m_voltage_desc *desc; int reg_id = rdev_get_id(rdev); - int sel, reg, mask, ret = 0, old_index, index = 0; - u8 val; + int reg, mask, ret = 0, old_index, index = 0; u8 *buck234_vol = NULL; switch (reg_id) { @@ -407,15 +389,9 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev, return -EINVAL; } - desc = reg_voltage_map[reg_id]; - - sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV); - if (sel < 0) - return sel; - /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */ if (buck234_vol) { - while (*buck234_vol != sel) { + while (*buck234_vol != selector) { buck234_vol++; index++; } @@ -423,22 +399,16 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev, s5m8767->buck_gpioindex = index; if (index > old_index) - s5m8767_set_high(s5m8767); + return s5m8767_set_high(s5m8767); else - s5m8767_set_low(s5m8767); + return s5m8767_set_low(s5m8767); } else { ret = s5m8767_get_voltage_register(rdev, ®); if (ret) return ret; - s5m_reg_read(s5m8767->iodev, reg, &val); - val = (val & ~mask) | sel; - - ret = s5m_reg_write(s5m8767->iodev, reg, val); + return s5m_reg_update(s5m8767->iodev, reg, selector, mask); } - - *selector = sel; - return ret; } static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, @@ -458,15 +428,21 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, } static struct regulator_ops s5m8767_ops = { - .list_voltage = s5m8767_list_voltage, + .list_voltage = regulator_list_voltage_linear, .is_enabled = s5m8767_reg_is_enabled, .enable = s5m8767_reg_enable, .disable = s5m8767_reg_disable, .get_voltage_sel = s5m8767_get_voltage_sel, - .set_voltage = s5m8767_set_voltage, + .set_voltage_sel = s5m8767_set_voltage_sel, .set_voltage_time_sel = s5m8767_set_voltage_time_sel, }; +static struct regulator_ops s5m8767_buck78_ops = { + .is_enabled = s5m8767_reg_is_enabled, + .enable = s5m8767_reg_enable, + .disable = s5m8767_reg_disable, +}; + #define s5m8767_regulator_desc(_name) { \ .name = #_name, \ .id = S5M8767_##_name, \ @@ -475,6 +451,14 @@ static struct regulator_ops s5m8767_ops = { .owner = THIS_MODULE, \ } +#define s5m8767_regulator_buck78_desc(_name) { \ + .name = #_name, \ + .id = S5M8767_##_name, \ + .ops = &s5m8767_buck78_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ +} + static struct regulator_desc regulators[] = { s5m8767_regulator_desc(LDO1), s5m8767_regulator_desc(LDO2), @@ -510,8 +494,8 @@ static struct regulator_desc regulators[] = { s5m8767_regulator_desc(BUCK4), s5m8767_regulator_desc(BUCK5), s5m8767_regulator_desc(BUCK6), - s5m8767_regulator_desc(BUCK7), - s5m8767_regulator_desc(BUCK8), + s5m8767_regulator_buck78_desc(BUCK7), + s5m8767_regulator_buck78_desc(BUCK8), s5m8767_regulator_desc(BUCK9), }; @@ -522,7 +506,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) struct regulator_config config = { }; struct regulator_dev **rdev; struct s5m8767_info *s5m8767; - int i, ret, size; + int i, ret, size, buck_init; if (!pdata) { dev_err(pdev->dev.parent, "Platform data not supplied\n"); @@ -573,12 +557,37 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; + s5m8767->buck_ds[0] = pdata->buck_ds[0]; + s5m8767->buck_ds[1] = pdata->buck_ds[1]; + s5m8767->buck_ds[2] = pdata->buck_ds[2]; + s5m8767->ramp_delay = pdata->buck_ramp_delay; s5m8767->buck2_ramp = pdata->buck2_ramp_enable; s5m8767->buck3_ramp = pdata->buck3_ramp_enable; s5m8767->buck4_ramp = pdata->buck4_ramp_enable; s5m8767->opmode = pdata->opmode; + buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, + pdata->buck2_init, + pdata->buck2_init + + buck_voltage_val2.step); + + s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); + + buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, + pdata->buck3_init, + pdata->buck3_init + + buck_voltage_val2.step); + + s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); + + buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, + pdata->buck4_init, + pdata->buck4_init + + buck_voltage_val2.step); + + s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); + for (i = 0; i < 8; i++) { if (s5m8767->buck2_gpiodvs) { s5m8767->buck2_vol[i] = @@ -608,48 +617,70 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) } } - if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || - pdata->buck4_gpiodvs) { - if (gpio_is_valid(pdata->buck_gpios[0]) && - gpio_is_valid(pdata->buck_gpios[1]) && - gpio_is_valid(pdata->buck_gpios[2])) { - ret = gpio_request(pdata->buck_gpios[0], - "S5M8767 SET1"); - if (ret == -EBUSY) - dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n"); - - ret = gpio_request(pdata->buck_gpios[1], - "S5M8767 SET2"); - if (ret == -EBUSY) - dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n"); - - ret = gpio_request(pdata->buck_gpios[2], - "S5M8767 SET3"); - if (ret == -EBUSY) - dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n"); - /* SET1 GPIO */ - gpio_direction_output(pdata->buck_gpios[0], - (s5m8767->buck_gpioindex >> 2) & 0x1); - /* SET2 GPIO */ - gpio_direction_output(pdata->buck_gpios[1], - (s5m8767->buck_gpioindex >> 1) & 0x1); - /* SET3 GPIO */ - gpio_direction_output(pdata->buck_gpios[2], - (s5m8767->buck_gpioindex >> 0) & 0x1); - ret = 0; - } else { - dev_err(&pdev->dev, "GPIO NOT VALID\n"); - ret = -EINVAL; + if (gpio_is_valid(pdata->buck_gpios[0]) && + gpio_is_valid(pdata->buck_gpios[1]) && + gpio_is_valid(pdata->buck_gpios[2])) { + ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0], + "S5M8767 SET1"); + if (ret) return ret; - } + + ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1], + "S5M8767 SET2"); + if (ret) + return ret; + + ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2], + "S5M8767 SET3"); + if (ret) + return ret; + + /* SET1 GPIO */ + gpio_direction_output(pdata->buck_gpios[0], + (s5m8767->buck_gpioindex >> 2) & 0x1); + /* SET2 GPIO */ + gpio_direction_output(pdata->buck_gpios[1], + (s5m8767->buck_gpioindex >> 1) & 0x1); + /* SET3 GPIO */ + gpio_direction_output(pdata->buck_gpios[2], + (s5m8767->buck_gpioindex >> 0) & 0x1); + } else { + dev_err(&pdev->dev, "GPIO NOT VALID\n"); + ret = -EINVAL; + return ret; } - s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, - (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); - s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, - (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); - s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, - (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); + ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2"); + if (ret) + return ret; + + ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3"); + if (ret) + return ret; + + ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4"); + if (ret) + return ret; + + /* DS2 GPIO */ + gpio_direction_output(pdata->buck_ds[0], 0x0); + /* DS3 GPIO */ + gpio_direction_output(pdata->buck_ds[1], 0x0); + /* DS4 GPIO */ + gpio_direction_output(pdata->buck_ds[2], 0x0); + + if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || + pdata->buck4_gpiodvs) { + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, + (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), + 1 << 1); + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, + (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), + 1 << 1); + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, + (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), + 1 << 1); + } /* Initialize GPIO DVS registers */ for (i = 0; i < 8; i++) { @@ -668,9 +699,6 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) s5m8767->buck4_vol[i]); } } - s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff); - s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff); - s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff); if (s5m8767->buck2_ramp) s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08); @@ -684,9 +712,13 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) if (s5m8767->buck2_ramp || s5m8767->buck3_ramp || s5m8767->buck4_ramp) { switch (s5m8767->ramp_delay) { - case 15: + case 5: s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0xc0, 0xf0); + 0x40, 0xf0); + break; + case 10: + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, + 0x90, 0xf0); break; case 25: s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, @@ -711,9 +743,12 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) int id = pdata->regulators[i].id; desc = reg_voltage_map[id]; - if (desc) + if (desc) { regulators[id].n_voltages = (desc->max - desc->min) / desc->step + 1; + regulators[id].min_uV = desc->min; + regulators[id].uV_step = desc->step; + } config.dev = s5m8767->dev; config.init_data = pdata->regulators[i].initdata; diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index d840d8440a9..1378409efae 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -20,7 +20,7 @@ #include <linux/mfd/core.h> #include <linux/mfd/tps6105x.h> -static const int tps6105x_voltages[] = { +static const unsigned int tps6105x_voltages[] = { 4500000, 5000000, 5250000, @@ -105,22 +105,13 @@ static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev, return 0; } -static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector >= ARRAY_SIZE(tps6105x_voltages)) - return -EINVAL; - - return tps6105x_voltages[selector]; -} - static struct regulator_ops tps6105x_regulator_ops = { .enable = tps6105x_regulator_enable, .disable = tps6105x_regulator_disable, .is_enabled = tps6105x_regulator_is_enabled, .get_voltage_sel = tps6105x_regulator_get_voltage_sel, .set_voltage_sel = tps6105x_regulator_set_voltage_sel, - .list_voltage = tps6105x_regulator_list_voltage, + .list_voltage = regulator_list_voltage_table, }; static const struct regulator_desc tps6105x_regulator_desc = { @@ -130,6 +121,7 @@ static const struct regulator_desc tps6105x_regulator_desc = { .id = 0, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(tps6105x_voltages), + .volt_table = tps6105x_voltages, }; /* diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index e534269ed44..68729a7c870 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -65,10 +65,8 @@ struct tps62360_chip { struct regulator_desc desc; struct regulator_dev *rdev; struct regmap *regmap; - int chip_id; int vsel0_gpio; int vsel1_gpio; - int voltage_base; u8 voltage_reg_mask; bool en_internal_pulldn; bool en_discharge; @@ -76,7 +74,6 @@ struct tps62360_chip { int lru_index[4]; int curr_vset_vsel[4]; int curr_vset_id; - int change_uv_per_us; }; /* @@ -175,23 +172,6 @@ static int tps62360_dcdc_set_voltage_sel(struct regulator_dev *dev, return 0; } -static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev, - unsigned int old_selector, unsigned int new_selector) -{ - struct tps62360_chip *tps = rdev_get_drvdata(rdev); - int old_uV, new_uV; - - old_uV = regulator_list_voltage_linear(rdev, old_selector); - if (old_uV < 0) - return old_uV; - - new_uV = regulator_list_voltage_linear(rdev, new_selector); - if (new_uV < 0) - return new_uV; - - return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us); -} - static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct tps62360_chip *tps = rdev_get_drvdata(rdev); @@ -258,7 +238,7 @@ static struct regulator_ops tps62360_dcdc_ops = { .set_voltage_sel = tps62360_dcdc_set_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, - .set_voltage_time_sel = tps62360_set_voltage_time_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_mode = tps62360_set_mode, .get_mode = tps62360_get_mode, }; @@ -301,7 +281,7 @@ static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, ramp_ctrl = (ramp_ctrl >> 4) & 0x7; /* ramp mV/us = 32/(2^ramp_ctrl) */ - tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl)); + tps->desc.ramp_delay = DIV_ROUND_UP(32000, BIT(ramp_ctrl)); return ret; } @@ -408,13 +388,13 @@ static int __devinit tps62360_probe(struct i2c_client *client, switch (chip_id) { case TPS62360: case TPS62362: - tps->voltage_base = TPS62360_BASE_VOLTAGE; + tps->desc.min_uV = TPS62360_BASE_VOLTAGE; tps->voltage_reg_mask = 0x3F; tps->desc.n_voltages = TPS62360_N_VOLTAGES; break; case TPS62361: case TPS62363: - tps->voltage_base = TPS62361_BASE_VOLTAGE; + tps->desc.min_uV = TPS62361_BASE_VOLTAGE; tps->voltage_reg_mask = 0x7F; tps->desc.n_voltages = TPS62361_N_VOLTAGES; break; @@ -427,7 +407,6 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->desc.ops = &tps62360_dcdc_ops; tps->desc.type = REGULATOR_VOLTAGE; tps->desc.owner = THIS_MODULE; - tps->desc.min_uV = tps->voltage_base; tps->desc.uV_step = 10000; tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config); @@ -449,24 +428,24 @@ static int __devinit tps62360_probe(struct i2c_client *client, int gpio_flags; gpio_flags = (pdata->vsel0_def_state) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - ret = gpio_request_one(tps->vsel0_gpio, + ret = devm_gpio_request_one(&client->dev, tps->vsel0_gpio, gpio_flags, "tps62360-vsel0"); if (ret) { dev_err(&client->dev, "%s(): Could not obtain vsel0 GPIO %d: %d\n", __func__, tps->vsel0_gpio, ret); - goto err_gpio0; + return ret; } gpio_flags = (pdata->vsel1_def_state) ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - ret = gpio_request_one(tps->vsel1_gpio, + ret = devm_gpio_request_one(&client->dev, tps->vsel1_gpio, gpio_flags, "tps62360-vsel1"); if (ret) { dev_err(&client->dev, "%s(): Could not obtain vsel1 GPIO %d: %d\n", __func__, tps->vsel1_gpio, ret); - goto err_gpio1; + return ret; } tps->valid_gpios = true; @@ -484,7 +463,7 @@ static int __devinit tps62360_probe(struct i2c_client *client, if (ret < 0) { dev_err(tps->dev, "%s(): Init failed with err = %d\n", __func__, ret); - goto err_init; + return ret; } config.dev = &client->dev; @@ -498,21 +477,11 @@ static int __devinit tps62360_probe(struct i2c_client *client, dev_err(tps->dev, "%s(): regulator register failed with err %s\n", __func__, id->name); - ret = PTR_ERR(rdev); - goto err_init; + return PTR_ERR(rdev); } tps->rdev = rdev; return 0; - -err_init: - if (gpio_is_valid(tps->vsel1_gpio)) - gpio_free(tps->vsel1_gpio); -err_gpio1: - if (gpio_is_valid(tps->vsel0_gpio)) - gpio_free(tps->vsel0_gpio); -err_gpio0: - return ret; } /** @@ -525,12 +494,6 @@ static int __devexit tps62360_remove(struct i2c_client *client) { struct tps62360_chip *tps = i2c_get_clientdata(client); - if (gpio_is_valid(tps->vsel1_gpio)) - gpio_free(tps->vsel1_gpio); - - if (gpio_is_valid(tps->vsel0_gpio)) - gpio_free(tps->vsel0_gpio); - regulator_unregister(tps->rdev); return 0; } diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 8f1be8586c7..6998d579d07 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -69,10 +69,6 @@ #define TPS65023_REG_CTRL2_DCDC1 BIT(1) #define TPS65023_REG_CTRL2_DCDC3 BIT(0) -/* LDO_CTRL bitfields */ -#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4) -#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0x07 << ((ldo_id)*4)) - /* Number of step-down converters available */ #define TPS65023_NUM_DCDC 3 /* Number of LDO voltage regulators available */ @@ -91,48 +87,53 @@ #define TPS65023_MAX_REG_ID TPS65023_LDO_2 /* Supported voltage values for regulators */ -static const u16 VCORE_VSEL_table[] = { - 800, 825, 850, 875, - 900, 925, 950, 975, - 1000, 1025, 1050, 1075, - 1100, 1125, 1150, 1175, - 1200, 1225, 1250, 1275, - 1300, 1325, 1350, 1375, - 1400, 1425, 1450, 1475, - 1500, 1525, 1550, 1600, +static const unsigned int VCORE_VSEL_table[] = { + 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, + 1000000, 1025000, 1050000, 1075000, + 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, + 1300000, 1325000, 1350000, 1375000, + 1400000, 1425000, 1450000, 1475000, + 1500000, 1525000, 1550000, 1600000, +}; + +static const unsigned int DCDC_FIXED_3300000_VSEL_table[] = { + 3300000, +}; + +static const unsigned int DCDC_FIXED_1800000_VSEL_table[] = { + 1800000, }; /* Supported voltage values for LDO regulators for tps65020 */ -static const u16 TPS65020_LDO1_VSEL_table[] = { - 1000, 1050, 1100, 1300, - 1800, 2500, 3000, 3300, +static const unsigned int TPS65020_LDO1_VSEL_table[] = { + 1000000, 1050000, 1100000, 1300000, + 1800000, 2500000, 3000000, 3300000, }; -static const u16 TPS65020_LDO2_VSEL_table[] = { - 1000, 1050, 1100, 1300, - 1800, 2500, 3000, 3300, +static const unsigned int TPS65020_LDO2_VSEL_table[] = { + 1000000, 1050000, 1100000, 1300000, + 1800000, 2500000, 3000000, 3300000, }; /* Supported voltage values for LDO regulators * for tps65021 and tps65023 */ -static const u16 TPS65023_LDO1_VSEL_table[] = { - 1000, 1100, 1300, 1800, - 2200, 2600, 2800, 3150, +static const unsigned int TPS65023_LDO1_VSEL_table[] = { + 1000000, 1100000, 1300000, 1800000, + 2200000, 2600000, 2800000, 3150000, }; -static const u16 TPS65023_LDO2_VSEL_table[] = { - 1050, 1200, 1300, 1800, - 2500, 2800, 3000, 3300, +static const unsigned int TPS65023_LDO2_VSEL_table[] = { + 1050000, 1200000, 1300000, 1800000, + 2500000, 2800000, 3000000, 3300000, }; /* Regulator specific details */ struct tps_info { const char *name; - unsigned min_uV; - unsigned max_uV; - bool fixed; u8 table_len; - const u16 *table; + const unsigned int *table; }; /* PMIC details */ @@ -150,7 +151,7 @@ struct tps_driver_data { u8 core_regulator; }; -static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) +static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct tps_pmic *tps = rdev_get_drvdata(dev); int ret; @@ -164,9 +165,9 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) if (ret != 0) return ret; data &= (tps->info[dcdc]->table_len - 1); - return tps->info[dcdc]->table[data] * 1000; + return data; } else - return tps->info[dcdc]->min_uV; + return 0; } static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev, @@ -193,76 +194,14 @@ out: return ret; } -static int tps65023_ldo_get_voltage(struct regulator_dev *dev) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int data, ldo = rdev_get_id(dev); - int ret; - - if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) - return -EINVAL; - - ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data); - if (ret != 0) - return ret; - - data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)); - data &= (tps->info[ldo]->table_len - 1); - return tps->info[ldo]->table[data] * 1000; -} - -static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev, - unsigned selector) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1; - - return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL, - TPS65023_LDO_CTRL_LDOx_MASK(ldo_index), - selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index)); -} - -static int tps65023_dcdc_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int dcdc = rdev_get_id(dev); - - if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) - return -EINVAL; - - if (dcdc == tps->core_regulator) { - if (selector >= tps->info[dcdc]->table_len) - return -EINVAL; - else - return tps->info[dcdc]->table[selector] * 1000; - } else - return tps->info[dcdc]->min_uV; -} - -static int tps65023_ldo_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev); - - if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) - return -EINVAL; - - if (selector >= tps->info[ldo]->table_len) - return -EINVAL; - else - return tps->info[ldo]->table[selector] * 1000; -} - /* Operations permitted on VDCDCx */ static struct regulator_ops tps65023_dcdc_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .get_voltage = tps65023_dcdc_get_voltage, + .get_voltage_sel = tps65023_dcdc_get_voltage_sel, .set_voltage_sel = tps65023_dcdc_set_voltage_sel, - .list_voltage = tps65023_dcdc_list_voltage, + .list_voltage = regulator_list_voltage_table, }; /* Operations permitted on LDOx */ @@ -270,9 +209,9 @@ static struct regulator_ops tps65023_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .get_voltage = tps65023_ldo_get_voltage, - .set_voltage_sel = tps65023_ldo_set_voltage_sel, - .list_voltage = tps65023_ldo_list_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_table, }; static struct regmap_config tps65023_regmap_config = { @@ -325,19 +264,28 @@ static int __devinit tps_65023_probe(struct i2c_client *client, tps->desc[i].name = info->name; tps->desc[i].id = i; tps->desc[i].n_voltages = info->table_len; + tps->desc[i].volt_table = info->table; tps->desc[i].ops = (i > TPS65023_DCDC_3 ? &tps65023_ldo_ops : &tps65023_dcdc_ops); tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].owner = THIS_MODULE; tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL; - if (i == TPS65023_LDO_1) + switch (i) { + case TPS65023_LDO_1: + tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL; + tps->desc[i].vsel_mask = 0x07; tps->desc[i].enable_mask = 1 << 1; - else if (i == TPS65023_LDO_2) + break; + case TPS65023_LDO_2: + tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL; + tps->desc[i].vsel_mask = 0x70; tps->desc[i].enable_mask = 1 << 2; - else /* DCDCx */ + break; + default: /* DCDCx */ tps->desc[i].enable_mask = 1 << (TPS65023_NUM_REGULATOR - i); + } config.dev = &client->dev; config.init_data = init_data; @@ -384,35 +332,26 @@ static int __devexit tps_65023_remove(struct i2c_client *client) static const struct tps_info tps65020_regs[] = { { .name = "VDCDC1", - .min_uV = 3300000, - .max_uV = 3300000, - .fixed = 1, + .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table), + .table = DCDC_FIXED_3300000_VSEL_table, }, { .name = "VDCDC2", - .min_uV = 1800000, - .max_uV = 1800000, - .fixed = 1, + .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table), + .table = DCDC_FIXED_1800000_VSEL_table, }, { .name = "VDCDC3", - .min_uV = 800000, - .max_uV = 1600000, .table_len = ARRAY_SIZE(VCORE_VSEL_table), .table = VCORE_VSEL_table, }, - { .name = "LDO1", - .min_uV = 1000000, - .max_uV = 3150000, .table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table), .table = TPS65020_LDO1_VSEL_table, }, { .name = "LDO2", - .min_uV = 1050000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table), .table = TPS65020_LDO2_VSEL_table, }, @@ -421,34 +360,26 @@ static const struct tps_info tps65020_regs[] = { static const struct tps_info tps65021_regs[] = { { .name = "VDCDC1", - .min_uV = 3300000, - .max_uV = 3300000, - .fixed = 1, + .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table), + .table = DCDC_FIXED_3300000_VSEL_table, }, { .name = "VDCDC2", - .min_uV = 1800000, - .max_uV = 1800000, - .fixed = 1, + .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table), + .table = DCDC_FIXED_1800000_VSEL_table, }, { .name = "VDCDC3", - .min_uV = 800000, - .max_uV = 1600000, .table_len = ARRAY_SIZE(VCORE_VSEL_table), .table = VCORE_VSEL_table, }, { .name = "LDO1", - .min_uV = 1000000, - .max_uV = 3150000, .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table), .table = TPS65023_LDO1_VSEL_table, }, { .name = "LDO2", - .min_uV = 1050000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table), .table = TPS65023_LDO2_VSEL_table, }, @@ -457,34 +388,26 @@ static const struct tps_info tps65021_regs[] = { static const struct tps_info tps65023_regs[] = { { .name = "VDCDC1", - .min_uV = 800000, - .max_uV = 1600000, .table_len = ARRAY_SIZE(VCORE_VSEL_table), .table = VCORE_VSEL_table, }, { .name = "VDCDC2", - .min_uV = 3300000, - .max_uV = 3300000, - .fixed = 1, + .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table), + .table = DCDC_FIXED_3300000_VSEL_table, }, { .name = "VDCDC3", - .min_uV = 1800000, - .max_uV = 1800000, - .fixed = 1, + .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table), + .table = DCDC_FIXED_1800000_VSEL_table, }, { .name = "LDO1", - .min_uV = 1000000, - .max_uV = 3150000, .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table), .table = TPS65023_LDO1_VSEL_table, }, { .name = "LDO2", - .min_uV = 1050000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table), .table = TPS65023_LDO2_VSEL_table, }, diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index da38be1016a..07d01ccdf30 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -43,58 +43,40 @@ /* Number of total regulators available */ #define TPS6507X_NUM_REGULATOR (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO) -/* Supported voltage values for regulators (in milliVolts) */ -static const u16 VDCDCx_VSEL_table[] = { - 725, 750, 775, 800, - 825, 850, 875, 900, - 925, 950, 975, 1000, - 1025, 1050, 1075, 1100, - 1125, 1150, 1175, 1200, - 1225, 1250, 1275, 1300, - 1325, 1350, 1375, 1400, - 1425, 1450, 1475, 1500, - 1550, 1600, 1650, 1700, - 1750, 1800, 1850, 1900, - 1950, 2000, 2050, 2100, - 2150, 2200, 2250, 2300, - 2350, 2400, 2450, 2500, - 2550, 2600, 2650, 2700, - 2750, 2800, 2850, 2900, - 3000, 3100, 3200, 3300, +/* Supported voltage values for regulators (in microVolts) */ +static const unsigned int VDCDCx_VSEL_table[] = { + 725000, 750000, 775000, 800000, + 825000, 850000, 875000, 900000, + 925000, 950000, 975000, 1000000, + 1025000, 1050000, 1075000, 1100000, + 1125000, 1150000, 1175000, 1200000, + 1225000, 1250000, 1275000, 1300000, + 1325000, 1350000, 1375000, 1400000, + 1425000, 1450000, 1475000, 1500000, + 1550000, 1600000, 1650000, 1700000, + 1750000, 1800000, 1850000, 1900000, + 1950000, 2000000, 2050000, 2100000, + 2150000, 2200000, 2250000, 2300000, + 2350000, 2400000, 2450000, 2500000, + 2550000, 2600000, 2650000, 2700000, + 2750000, 2800000, 2850000, 2900000, + 3000000, 3100000, 3200000, 3300000, }; -static const u16 LDO1_VSEL_table[] = { - 1000, 1100, 1200, 1250, - 1300, 1350, 1400, 1500, - 1600, 1800, 2500, 2750, - 2800, 3000, 3100, 3300, +static const unsigned int LDO1_VSEL_table[] = { + 1000000, 1100000, 1200000, 1250000, + 1300000, 1350000, 1400000, 1500000, + 1600000, 1800000, 2500000, 2750000, + 2800000, 3000000, 3100000, 3300000, }; -static const u16 LDO2_VSEL_table[] = { - 725, 750, 775, 800, - 825, 850, 875, 900, - 925, 950, 975, 1000, - 1025, 1050, 1075, 1100, - 1125, 1150, 1175, 1200, - 1225, 1250, 1275, 1300, - 1325, 1350, 1375, 1400, - 1425, 1450, 1475, 1500, - 1550, 1600, 1650, 1700, - 1750, 1800, 1850, 1900, - 1950, 2000, 2050, 2100, - 2150, 2200, 2250, 2300, - 2350, 2400, 2450, 2500, - 2550, 2600, 2650, 2700, - 2750, 2800, 2850, 2900, - 3000, 3100, 3200, 3300, -}; +/* The voltage mapping table for LDO2 is the same as VDCDCx */ +#define LDO2_VSEL_table VDCDCx_VSEL_table struct tps_info { const char *name; - unsigned min_uV; - unsigned max_uV; u8 table_len; - const u16 *table; + const unsigned int *table; /* Does DCDC high or the low register defines output voltage? */ bool defdcdc_default; @@ -103,36 +85,26 @@ struct tps_info { static struct tps_info tps6507x_pmic_regs[] = { { .name = "VDCDC1", - .min_uV = 725000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), .table = VDCDCx_VSEL_table, }, { .name = "VDCDC2", - .min_uV = 725000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), .table = VDCDCx_VSEL_table, }, { .name = "VDCDC3", - .min_uV = 725000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), .table = VDCDCx_VSEL_table, }, { .name = "LDO1", - .min_uV = 1000000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(LDO1_VSEL_table), .table = LDO1_VSEL_table, }, { .name = "LDO2", - .min_uV = 725000, - .max_uV = 3300000, .table_len = ARRAY_SIZE(LDO2_VSEL_table), .table = LDO2_VSEL_table, }, @@ -375,28 +347,13 @@ static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev, return tps6507x_pmic_reg_write(tps, reg, data); } -static int tps6507x_pmic_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int rid = rdev_get_id(dev); - - if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) - return -EINVAL; - - if (selector >= tps->info[rid]->table_len) - return -EINVAL; - else - return tps->info[rid]->table[selector] * 1000; -} - static struct regulator_ops tps6507x_pmic_ops = { .is_enabled = tps6507x_pmic_is_enabled, .enable = tps6507x_pmic_enable, .disable = tps6507x_pmic_disable, .get_voltage_sel = tps6507x_pmic_get_voltage_sel, .set_voltage_sel = tps6507x_pmic_set_voltage_sel, - .list_voltage = tps6507x_pmic_list_voltage, + .list_voltage = regulator_list_voltage_table, }; static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) @@ -449,6 +406,7 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) tps->desc[i].name = info->name; tps->desc[i].id = i; tps->desc[i].n_voltages = info->table_len; + tps->desc[i].volt_table = info->table; tps->desc[i].ops = &tps6507x_pmic_ops; tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].owner = THIS_MODULE; diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 9d371d2cbca..6caa222af77 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -26,7 +26,7 @@ #include <linux/regulator/machine.h> #include <linux/mfd/tps65217.h> -#define TPS65217_REGULATOR(_name, _id, _ops, _n) \ +#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t) \ { \ .name = _name, \ .id = _id, \ @@ -34,23 +34,23 @@ .n_voltages = _n, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ + .vsel_reg = _vr, \ + .vsel_mask = _vm, \ + .enable_reg = TPS65217_REG_ENABLE, \ + .enable_mask = _em, \ + .volt_table = _t, \ } \ -#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm) \ +#define TPS65217_INFO(_nm, _min, _max, _f1, _f2) \ { \ .name = _nm, \ .min_uV = _min, \ .max_uV = _max, \ .vsel_to_uv = _f1, \ .uv_to_vsel = _f2, \ - .table = _t, \ - .table_len = _n, \ - .enable_mask = _em, \ - .set_vout_reg = _vr, \ - .set_vout_mask = _vm, \ } -static const int LDO1_VSEL_table[] = { +static const unsigned int LDO1_VSEL_table[] = { 1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1800000, 2500000, 2750000, @@ -78,7 +78,7 @@ static int tps65217_vsel_to_uv1(unsigned int vsel) static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel) { - if ((uV < 0) && (uV > 3300000)) + if (uV < 0 || uV > 3300000) return -EINVAL; if (uV <= 1500000) @@ -112,7 +112,7 @@ static int tps65217_vsel_to_uv2(unsigned int vsel) static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel) { - if ((uV < 0) && (uV > 3300000)) + if (uV < 0 || uV > 3300000) return -EINVAL; if (uV <= 1900000) @@ -127,46 +127,20 @@ static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel) static struct tps_info tps65217_pmic_regs[] = { TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC1_EN, - TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK), + tps65217_uv_to_vsel1), TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC2_EN, - TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK), + tps65217_uv_to_vsel1), TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC3_EN, - TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK), - TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL, LDO1_VSEL_table, - 16, TPS65217_ENABLE_LDO1_EN, TPS65217_REG_DEFLDO1, - TPS65217_DEFLDO1_LDO1_MASK), + tps65217_uv_to_vsel1), + TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL), TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_LDO2_EN, - TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK), + tps65217_uv_to_vsel1), TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2, - tps65217_uv_to_vsel2, NULL, 32, - TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, - TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK), + tps65217_uv_to_vsel2), TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2, - tps65217_uv_to_vsel2, NULL, 32, - TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, - TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK), + tps65217_uv_to_vsel2), }; -static int tps65217_pmic_is_enabled(struct regulator_dev *dev) -{ - int ret; - struct tps65217 *tps = rdev_get_drvdata(dev); - unsigned int data, rid = rdev_get_id(dev); - - if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) - return -EINVAL; - - ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data); - if (ret) - return ret; - - return (data & tps->info[rid]->enable_mask) ? 1 : 0; -} - static int tps65217_pmic_enable(struct regulator_dev *dev) { struct tps65217 *tps = rdev_get_drvdata(dev); @@ -177,9 +151,8 @@ static int tps65217_pmic_enable(struct regulator_dev *dev) /* Enable the regulator and password protection is level 1 */ return tps65217_set_bits(tps, TPS65217_REG_ENABLE, - tps->info[rid]->enable_mask, - tps->info[rid]->enable_mask, - TPS65217_PROTECT_L1); + dev->desc->enable_mask, dev->desc->enable_mask, + TPS65217_PROTECT_L1); } static int tps65217_pmic_disable(struct regulator_dev *dev) @@ -192,25 +165,7 @@ static int tps65217_pmic_disable(struct regulator_dev *dev) /* Disable the regulator and password protection is level 1 */ return tps65217_clear_bits(tps, TPS65217_REG_ENABLE, - tps->info[rid]->enable_mask, TPS65217_PROTECT_L1); -} - -static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev) -{ - int ret; - struct tps65217 *tps = rdev_get_drvdata(dev); - unsigned int selector, rid = rdev_get_id(dev); - - if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) - return -EINVAL; - - ret = tps65217_reg_read(tps, tps->info[rid]->set_vout_reg, &selector); - if (ret) - return ret; - - selector &= tps->info[rid]->set_vout_mask; - - return selector; + dev->desc->enable_mask, TPS65217_PROTECT_L1); } static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev, @@ -221,8 +176,7 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev, unsigned int rid = rdev_get_id(dev); /* Set the voltage based on vsel value and write protect level is 2 */ - ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg, - tps->info[rid]->set_vout_mask, + ret = tps65217_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask, selector, TPS65217_PROTECT_L2); /* Set GO bit for DCDCx to initiate voltage transistion */ @@ -252,10 +206,10 @@ static int tps65217_pmic_map_voltage(struct regulator_dev *dev, if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) return -EINVAL; - if (min_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV) - return -EINVAL; + if (min_uV < tps->info[rid]->min_uV) + min_uV = tps->info[rid]->min_uV; - if (max_uV < tps->info[rid]->min_uV || max_uV > tps->info[rid]->max_uV) + if (max_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV) return -EINVAL; ret = tps->info[rid]->uv_to_vsel(min_uV, &sel); @@ -274,21 +228,18 @@ static int tps65217_pmic_list_voltage(struct regulator_dev *dev, if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) return -EINVAL; - if (selector >= tps->info[rid]->table_len) + if (selector >= dev->desc->n_voltages) return -EINVAL; - if (tps->info[rid]->table) - return tps->info[rid]->table[selector]; - return tps->info[rid]->vsel_to_uv(selector); } /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ static struct regulator_ops tps65217_pmic_ops = { - .is_enabled = tps65217_pmic_is_enabled, + .is_enabled = regulator_is_enabled_regmap, .enable = tps65217_pmic_enable, .disable = tps65217_pmic_disable, - .get_voltage_sel = tps65217_pmic_get_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = tps65217_pmic_list_voltage, .map_voltage = tps65217_pmic_map_voltage, @@ -296,22 +247,38 @@ static struct regulator_ops tps65217_pmic_ops = { /* Operations permitted on LDO1 */ static struct regulator_ops tps65217_pmic_ldo1_ops = { - .is_enabled = tps65217_pmic_is_enabled, + .is_enabled = regulator_is_enabled_regmap, .enable = tps65217_pmic_enable, .disable = tps65217_pmic_disable, - .get_voltage_sel = tps65217_pmic_get_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = tps65217_pmic_set_voltage_sel, - .list_voltage = tps65217_pmic_list_voltage, + .list_voltage = regulator_list_voltage_table, }; static const struct regulator_desc regulators[] = { - TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64), - TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64), - TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64), - TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16), - TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64), - TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32), - TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32), + TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64, + TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK, + TPS65217_ENABLE_DC1_EN, NULL), + TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64, + TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK, + TPS65217_ENABLE_DC2_EN, NULL), + TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64, + TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK, + TPS65217_ENABLE_DC3_EN, NULL), + TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16, + TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK, + TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table), + TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64, + TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK, + TPS65217_ENABLE_LDO2_EN, NULL), + TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32, + TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK, + TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, + NULL), + TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32, + TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK, + TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, + NULL), }; static int __devinit tps65217_regulator_probe(struct platform_device *pdev) @@ -326,6 +293,7 @@ static int __devinit tps65217_regulator_probe(struct platform_device *pdev) tps->info[pdev->id] = info; config.dev = &pdev->dev; + config.of_node = pdev->dev.of_node; config.init_data = pdev->dev.platform_data; config.driver_data = tps; diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 1b299aacf22..947ece933d9 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -110,9 +110,6 @@ #define N_SWITCH 2 #define N_REGULATORS (N_DCDC + N_LDO + N_SWITCH) -#define FIXED_ILIMSEL BIT(0) -#define FIXED_VOLTAGE BIT(1) - #define CMD_READ(reg) ((reg) << 6) #define CMD_WRITE(reg) (BIT(5) | (reg) << 6) #define STAT_CLK BIT(3) @@ -129,12 +126,9 @@ struct field { struct supply_info { const char *name; int n_voltages; - const int *voltages; - int fixed_voltage; + const unsigned int *voltages; int n_ilimsels; - const int *ilimsels; - int fixed_ilimsel; - int flags; + const unsigned int *ilimsels; struct field enable, voltage, ilimsel; }; @@ -307,7 +301,7 @@ static int write_field(struct tps6524x *hw, const struct field *field, val << field->shift); } -static const int dcdc1_voltages[] = { +static const unsigned int dcdc1_voltages[] = { 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, @@ -318,7 +312,7 @@ static const int dcdc1_voltages[] = { 1500000, 1525000, 1550000, 1575000, }; -static const int dcdc2_voltages[] = { +static const unsigned int dcdc2_voltages[] = { 1400000, 1450000, 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, @@ -329,7 +323,7 @@ static const int dcdc2_voltages[] = { 2800000, 2850000, 2900000, 2950000, }; -static const int dcdc3_voltages[] = { +static const unsigned int dcdc3_voltages[] = { 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000, 2900000, 2950000, 3000000, 3050000, 3100000, @@ -337,38 +331,54 @@ static const int dcdc3_voltages[] = { 3400000, 3450000, 3500000, 3550000, 3600000, }; -static const int ldo1_voltages[] = { +static const unsigned int ldo1_voltages[] = { 4300000, 4350000, 4400000, 4450000, 4500000, 4550000, 4600000, 4650000, 4700000, 4750000, 4800000, 4850000, 4900000, 4950000, 5000000, 5050000, }; -static const int ldo2_voltages[] = { +static const unsigned int ldo2_voltages[] = { 1100000, 1150000, 1200000, 1250000, 1300000, 1700000, 1750000, 1800000, 1850000, 1900000, 3150000, 3200000, 3250000, 3300000, 3350000, 3400000, }; -static const int ldo_ilimsel[] = { +static const unsigned int fixed_5000000_voltage[] = { + 5000000 +}; + +static const unsigned int ldo_ilimsel[] = { 400000, 1500000 }; -static const int usb_ilimsel[] = { +static const unsigned int usb_ilimsel[] = { 200000, 400000, 800000, 1000000 }; +static const unsigned int fixed_2400000_ilimsel[] = { + 2400000 +}; + +static const unsigned int fixed_1200000_ilimsel[] = { + 1200000 +}; + +static const unsigned int fixed_400000_ilimsel[] = { + 400000 +}; + #define __MK_FIELD(_reg, _mask, _shift) \ { .reg = (_reg), .mask = (_mask), .shift = (_shift), } static const struct supply_info supply_info[N_REGULATORS] = { { .name = "DCDC1", - .flags = FIXED_ILIMSEL, .n_voltages = ARRAY_SIZE(dcdc1_voltages), .voltages = dcdc1_voltages, - .fixed_ilimsel = 2400000, + .n_ilimsels = ARRAY_SIZE(fixed_2400000_ilimsel), + .ilimsels = fixed_2400000_ilimsel, .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, DCDCDCDC1_EN_SHIFT), .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, @@ -376,10 +386,10 @@ static const struct supply_info supply_info[N_REGULATORS] = { }, { .name = "DCDC2", - .flags = FIXED_ILIMSEL, .n_voltages = ARRAY_SIZE(dcdc2_voltages), .voltages = dcdc2_voltages, - .fixed_ilimsel = 1200000, + .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), + .ilimsels = fixed_1200000_ilimsel, .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, DCDCDCDC2_EN_SHIFT), .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, @@ -387,10 +397,10 @@ static const struct supply_info supply_info[N_REGULATORS] = { }, { .name = "DCDC3", - .flags = FIXED_ILIMSEL, .n_voltages = ARRAY_SIZE(dcdc3_voltages), .voltages = dcdc3_voltages, - .fixed_ilimsel = 1200000, + .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), + .ilimsels = fixed_1200000_ilimsel, .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, DCDCDCDC3_EN_SHIFT), .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, @@ -424,8 +434,8 @@ static const struct supply_info supply_info[N_REGULATORS] = { }, { .name = "USB", - .flags = FIXED_VOLTAGE, - .fixed_voltage = 5000000, + .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), + .voltages = fixed_5000000_voltage, .n_ilimsels = ARRAY_SIZE(usb_ilimsel), .ilimsels = usb_ilimsel, .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, @@ -435,29 +445,15 @@ static const struct supply_info supply_info[N_REGULATORS] = { }, { .name = "LCD", - .flags = FIXED_VOLTAGE | FIXED_ILIMSEL, - .fixed_voltage = 5000000, - .fixed_ilimsel = 400000, + .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), + .voltages = fixed_5000000_voltage, + .n_ilimsels = ARRAY_SIZE(fixed_400000_ilimsel), + .ilimsels = fixed_400000_ilimsel, .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, BLOCK_LCD_SHIFT), }, }; -static int list_voltage(struct regulator_dev *rdev, unsigned selector) -{ - const struct supply_info *info; - struct tps6524x *hw; - - hw = rdev_get_drvdata(rdev); - info = &supply_info[rdev_get_id(rdev)]; - - if (info->flags & FIXED_VOLTAGE) - return selector ? -EINVAL : info->fixed_voltage; - - return ((selector < info->n_voltages) ? - info->voltages[selector] : -EINVAL); -} - static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { const struct supply_info *info; @@ -466,7 +462,7 @@ static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector) hw = rdev_get_drvdata(rdev); info = &supply_info[rdev_get_id(rdev)]; - if (info->flags & FIXED_VOLTAGE) + if (rdev->desc->n_voltages == 1) return -EINVAL; return write_field(hw, &info->voltage, selector); @@ -481,7 +477,7 @@ static int get_voltage_sel(struct regulator_dev *rdev) hw = rdev_get_drvdata(rdev); info = &supply_info[rdev_get_id(rdev)]; - if (info->flags & FIXED_VOLTAGE) + if (rdev->desc->n_voltages == 1) return 0; ret = read_field(hw, &info->voltage); @@ -503,7 +499,7 @@ static int set_current_limit(struct regulator_dev *rdev, int min_uA, hw = rdev_get_drvdata(rdev); info = &supply_info[rdev_get_id(rdev)]; - if (info->flags & FIXED_ILIMSEL) + if (info->n_ilimsels == 1) return -EINVAL; for (i = 0; i < info->n_ilimsels; i++) @@ -526,8 +522,8 @@ static int get_current_limit(struct regulator_dev *rdev) hw = rdev_get_drvdata(rdev); info = &supply_info[rdev_get_id(rdev)]; - if (info->flags & FIXED_ILIMSEL) - return info->fixed_ilimsel; + if (info->n_ilimsels == 1) + return info->ilimsels[0]; ret = read_field(hw, &info->ilimsel); if (ret < 0) @@ -577,7 +573,7 @@ static struct regulator_ops regulator_ops = { .disable = disable_supply, .get_voltage_sel = get_voltage_sel, .set_voltage_sel = set_voltage_sel, - .list_voltage = list_voltage, + .list_voltage = regulator_list_voltage_table, .set_current_limit = set_current_limit, .get_current_limit = get_current_limit, }; @@ -629,13 +625,11 @@ static int __devinit pmic_probe(struct spi_device *spi) hw->desc[i].name = info->name; hw->desc[i].id = i; hw->desc[i].n_voltages = info->n_voltages; + hw->desc[i].volt_table = info->voltages; hw->desc[i].ops = ®ulator_ops; hw->desc[i].type = REGULATOR_VOLTAGE; hw->desc[i].owner = THIS_MODULE; - if (info->flags & FIXED_VOLTAGE) - hw->desc[i].n_voltages = 1; - config.dev = dev; config.init_data = init_data; config.driver_data = hw; diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index c0a21457538..e6da90ab515 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -63,8 +63,6 @@ struct tps6586x_regulator { int enable_bit[2]; int enable_reg[2]; - int *voltages; - /* for DVM regulators */ int go_reg; int go_bit; @@ -72,22 +70,9 @@ struct tps6586x_regulator { static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) { - return rdev_get_dev(rdev)->parent->parent; + return rdev_get_dev(rdev)->parent; } -static int tps6586x_list_voltage(struct regulator_dev *rdev, unsigned selector) -{ - struct tps6586x_regulator *info = rdev_get_drvdata(rdev); - int rid = rdev_get_id(rdev); - - /* LDO0 has minimal voltage 1.2V rather than 1.25V */ - if ((rid == TPS6586X_ID_LDO_0) && (selector == 0)) - return (info->voltages[0] - 50) * 1000; - - return info->voltages[selector] * 1000; -} - - static int tps6586x_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { @@ -168,7 +153,7 @@ static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev) } static struct regulator_ops tps6586x_regulator_ops = { - .list_voltage = tps6586x_list_voltage, + .list_voltage = regulator_list_voltage_table, .get_voltage_sel = tps6586x_get_voltage_sel, .set_voltage_sel = tps6586x_set_voltage_sel, @@ -177,39 +162,45 @@ static struct regulator_ops tps6586x_regulator_ops = { .disable = tps6586x_regulator_disable, }; -static int tps6586x_ldo_voltages[] = { - 1250, 1500, 1800, 2500, 2700, 2850, 3100, 3300, +static const unsigned int tps6586x_ldo0_voltages[] = { + 1200000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000, +}; + +static const unsigned int tps6586x_ldo4_voltages[] = { + 1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000, + 1900000, 1925000, 1950000, 1975000, 2000000, 2025000, 2050000, 2075000, + 2100000, 2125000, 2150000, 2175000, 2200000, 2225000, 2250000, 2275000, + 2300000, 2325000, 2350000, 2375000, 2400000, 2425000, 2450000, 2475000, }; -static int tps6586x_ldo4_voltages[] = { - 1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875, - 1900, 1925, 1950, 1975, 2000, 2025, 2050, 2075, - 2100, 2125, 2150, 2175, 2200, 2225, 2250, 2275, - 2300, 2325, 2350, 2375, 2400, 2425, 2450, 2475, +static const unsigned int tps6586x_ldo_voltages[] = { + 1250000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000, }; -static int tps6586x_sm2_voltages[] = { - 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, - 3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750, - 3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150, - 4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550, +static const unsigned int tps6586x_sm2_voltages[] = { + 3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000, 3350000, + 3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000, 3750000, + 3800000, 3850000, 3900000, 3950000, 4000000, 4050000, 4100000, 4150000, + 4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000, }; -static int tps6586x_dvm_voltages[] = { - 725, 750, 775, 800, 825, 850, 875, 900, - 925, 950, 975, 1000, 1025, 1050, 1075, 1100, - 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, - 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, +static const unsigned int tps6586x_dvm_voltages[] = { + 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, + 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, + 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, + 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, }; -#define TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \ +#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ .desc = { \ + .supply_name = _pin_name, \ .name = "REG-" #_id, \ .ops = &tps6586x_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .id = TPS6586X_ID_##_id, \ .n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages), \ + .volt_table = tps6586x_##vdata##_voltages, \ .owner = THIS_MODULE, \ }, \ .volt_reg = TPS6586X_##vreg, \ @@ -218,44 +209,45 @@ static int tps6586x_dvm_voltages[] = { .enable_reg[0] = TPS6586X_SUPPLY##ereg0, \ .enable_bit[0] = (ebit0), \ .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ - .enable_bit[1] = (ebit1), \ - .voltages = tps6586x_##vdata##_voltages, + .enable_bit[1] = (ebit1), #define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ .go_reg = TPS6586X_##goreg, \ .go_bit = (gobit), -#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \ +#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ { \ - TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \ + TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ } -#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \ +#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ { \ - TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \ + TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ } static struct tps6586x_regulator tps6586x_regulator[] = { - TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0), - TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2), - TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), - TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), - TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), - TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), - TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), - TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), - TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), - TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), - - TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6), - TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6), - TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2), - TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0), + TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0), + TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2), + TPS6586X_LDO(LDO_5, NULL, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), + TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), + TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), + TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), + TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), + TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), + TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), + TPS6586X_LDO(SM_2, "sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), + + TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3, + ENB, 3, VCC2, 6), + TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3, + END, 3, VCC1, 6), + TPS6586X_DVM(SM_0, "sm0", dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2), + TPS6586X_DVM(SM_1, "sm1", dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0), }; /* @@ -362,7 +354,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) if (err) return err; - config.dev = &pdev->dev; + config.dev = pdev->dev.parent; config.of_node = pdev->dev.of_node; config.init_data = pdev->dev.platform_data; config.driver_data = ri; diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 6bf864b4bdf..793adda560c 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -31,160 +31,147 @@ TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \ TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) -/* supported VIO voltages in millivolts */ -static const u16 VIO_VSEL_table[] = { - 1500, 1800, 2500, 3300, +/* supported VIO voltages in microvolts */ +static const unsigned int VIO_VSEL_table[] = { + 1500000, 1800000, 2500000, 3300000, }; /* VSEL tables for TPS65910 specific LDOs and dcdc's */ -/* supported VDD3 voltages in millivolts */ -static const u16 VDD3_VSEL_table[] = { - 5000, +/* supported VDD3 voltages in microvolts */ +static const unsigned int VDD3_VSEL_table[] = { + 5000000, }; -/* supported VDIG1 voltages in millivolts */ -static const u16 VDIG1_VSEL_table[] = { - 1200, 1500, 1800, 2700, +/* supported VDIG1 voltages in microvolts */ +static const unsigned int VDIG1_VSEL_table[] = { + 1200000, 1500000, 1800000, 2700000, }; -/* supported VDIG2 voltages in millivolts */ -static const u16 VDIG2_VSEL_table[] = { - 1000, 1100, 1200, 1800, +/* supported VDIG2 voltages in microvolts */ +static const unsigned int VDIG2_VSEL_table[] = { + 1000000, 1100000, 1200000, 1800000, }; -/* supported VPLL voltages in millivolts */ -static const u16 VPLL_VSEL_table[] = { - 1000, 1100, 1800, 2500, +/* supported VPLL voltages in microvolts */ +static const unsigned int VPLL_VSEL_table[] = { + 1000000, 1100000, 1800000, 2500000, }; -/* supported VDAC voltages in millivolts */ -static const u16 VDAC_VSEL_table[] = { - 1800, 2600, 2800, 2850, +/* supported VDAC voltages in microvolts */ +static const unsigned int VDAC_VSEL_table[] = { + 1800000, 2600000, 2800000, 2850000, }; -/* supported VAUX1 voltages in millivolts */ -static const u16 VAUX1_VSEL_table[] = { - 1800, 2500, 2800, 2850, +/* supported VAUX1 voltages in microvolts */ +static const unsigned int VAUX1_VSEL_table[] = { + 1800000, 2500000, 2800000, 2850000, }; -/* supported VAUX2 voltages in millivolts */ -static const u16 VAUX2_VSEL_table[] = { - 1800, 2800, 2900, 3300, +/* supported VAUX2 voltages in microvolts */ +static const unsigned int VAUX2_VSEL_table[] = { + 1800000, 2800000, 2900000, 3300000, }; -/* supported VAUX33 voltages in millivolts */ -static const u16 VAUX33_VSEL_table[] = { - 1800, 2000, 2800, 3300, +/* supported VAUX33 voltages in microvolts */ +static const unsigned int VAUX33_VSEL_table[] = { + 1800000, 2000000, 2800000, 3300000, }; -/* supported VMMC voltages in millivolts */ -static const u16 VMMC_VSEL_table[] = { - 1800, 2800, 3000, 3300, +/* supported VMMC voltages in microvolts */ +static const unsigned int VMMC_VSEL_table[] = { + 1800000, 2800000, 3000000, 3300000, }; struct tps_info { const char *name; - unsigned min_uV; - unsigned max_uV; + const char *vin_name; u8 n_voltages; - const u16 *voltage_table; + const unsigned int *voltage_table; int enable_time_us; }; static struct tps_info tps65910_regs[] = { { .name = "vrtc", + .vin_name = "vcc7", .enable_time_us = 2200, }, { .name = "vio", - .min_uV = 1500000, - .max_uV = 3300000, + .vin_name = "vccio", .n_voltages = ARRAY_SIZE(VIO_VSEL_table), .voltage_table = VIO_VSEL_table, .enable_time_us = 350, }, { .name = "vdd1", - .min_uV = 600000, - .max_uV = 4500000, + .vin_name = "vcc1", .enable_time_us = 350, }, { .name = "vdd2", - .min_uV = 600000, - .max_uV = 4500000, + .vin_name = "vcc2", .enable_time_us = 350, }, { .name = "vdd3", - .min_uV = 5000000, - .max_uV = 5000000, .n_voltages = ARRAY_SIZE(VDD3_VSEL_table), .voltage_table = VDD3_VSEL_table, .enable_time_us = 200, }, { .name = "vdig1", - .min_uV = 1200000, - .max_uV = 2700000, + .vin_name = "vcc6", .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table), .voltage_table = VDIG1_VSEL_table, .enable_time_us = 100, }, { .name = "vdig2", - .min_uV = 1000000, - .max_uV = 1800000, + .vin_name = "vcc6", .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table), .voltage_table = VDIG2_VSEL_table, .enable_time_us = 100, }, { .name = "vpll", - .min_uV = 1000000, - .max_uV = 2500000, + .vin_name = "vcc5", .n_voltages = ARRAY_SIZE(VPLL_VSEL_table), .voltage_table = VPLL_VSEL_table, .enable_time_us = 100, }, { .name = "vdac", - .min_uV = 1800000, - .max_uV = 2850000, + .vin_name = "vcc5", .n_voltages = ARRAY_SIZE(VDAC_VSEL_table), .voltage_table = VDAC_VSEL_table, .enable_time_us = 100, }, { .name = "vaux1", - .min_uV = 1800000, - .max_uV = 2850000, + .vin_name = "vcc4", .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table), .voltage_table = VAUX1_VSEL_table, .enable_time_us = 100, }, { .name = "vaux2", - .min_uV = 1800000, - .max_uV = 3300000, + .vin_name = "vcc4", .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table), .voltage_table = VAUX2_VSEL_table, .enable_time_us = 100, }, { .name = "vaux33", - .min_uV = 1800000, - .max_uV = 3300000, + .vin_name = "vcc3", .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table), .voltage_table = VAUX33_VSEL_table, .enable_time_us = 100, }, { .name = "vmmc", - .min_uV = 1800000, - .max_uV = 3300000, + .vin_name = "vcc3", .n_voltages = ARRAY_SIZE(VMMC_VSEL_table), .voltage_table = VMMC_VSEL_table, .enable_time_us = 100, @@ -194,91 +181,79 @@ static struct tps_info tps65910_regs[] = { static struct tps_info tps65911_regs[] = { { .name = "vrtc", + .vin_name = "vcc7", .enable_time_us = 2200, }, { .name = "vio", - .min_uV = 1500000, - .max_uV = 3300000, + .vin_name = "vccio", .n_voltages = ARRAY_SIZE(VIO_VSEL_table), .voltage_table = VIO_VSEL_table, .enable_time_us = 350, }, { .name = "vdd1", - .min_uV = 600000, - .max_uV = 4500000, - .n_voltages = 73, + .vin_name = "vcc1", + .n_voltages = 0x4C, .enable_time_us = 350, }, { .name = "vdd2", - .min_uV = 600000, - .max_uV = 4500000, - .n_voltages = 73, + .vin_name = "vcc2", + .n_voltages = 0x4C, .enable_time_us = 350, }, { .name = "vddctrl", - .min_uV = 600000, - .max_uV = 1400000, - .n_voltages = 65, + .n_voltages = 0x44, .enable_time_us = 900, }, { .name = "ldo1", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 47, + .vin_name = "vcc6", + .n_voltages = 0x33, .enable_time_us = 420, }, { .name = "ldo2", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 47, + .vin_name = "vcc6", + .n_voltages = 0x33, .enable_time_us = 420, }, { .name = "ldo3", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 24, + .vin_name = "vcc5", + .n_voltages = 0x1A, .enable_time_us = 230, }, { .name = "ldo4", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 47, + .vin_name = "vcc5", + .n_voltages = 0x33, .enable_time_us = 230, }, { .name = "ldo5", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 24, + .vin_name = "vcc4", + .n_voltages = 0x1A, .enable_time_us = 230, }, { .name = "ldo6", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 24, + .vin_name = "vcc3", + .n_voltages = 0x1A, .enable_time_us = 230, }, { .name = "ldo7", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 24, + .vin_name = "vcc3", + .n_voltages = 0x1A, .enable_time_us = 230, }, { .name = "ldo8", - .min_uV = 1000000, - .max_uV = 3300000, - .n_voltages = 24, + .vin_name = "vcc3", + .n_voltages = 0x1A, .enable_time_us = 230, }, }; @@ -321,7 +296,6 @@ struct tps65910_reg { struct tps65910 *mfd; struct regulator_dev **rdev; struct tps_info **info; - struct mutex mutex; int num_regulators; int mode; int (*get_ctrl_reg)(int); @@ -329,71 +303,6 @@ struct tps65910_reg { unsigned int board_ext_control[TPS65910_NUM_REGS]; }; -static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) -{ - unsigned int val; - int err; - - err = tps65910_reg_read(pmic->mfd, reg, &val); - if (err) - return err; - - return val; -} - -static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, - u8 set_mask, u8 clear_mask) -{ - int err, data; - - mutex_lock(&pmic->mutex); - - data = tps65910_read(pmic, reg); - if (data < 0) { - dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); - err = data; - goto out; - } - - data &= ~clear_mask; - data |= set_mask; - err = tps65910_reg_write(pmic->mfd, reg, data); - if (err) - dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); - -out: - mutex_unlock(&pmic->mutex); - return err; -} - -static int tps65910_reg_read_locked(struct tps65910_reg *pmic, u8 reg) -{ - int data; - - mutex_lock(&pmic->mutex); - - data = tps65910_read(pmic, reg); - if (data < 0) - dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); - - mutex_unlock(&pmic->mutex); - return data; -} - -static int tps65910_reg_write_locked(struct tps65910_reg *pmic, u8 reg, u8 val) -{ - int err; - - mutex_lock(&pmic->mutex); - - err = tps65910_reg_write(pmic->mfd, reg, val); - if (err < 0) - dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); - - mutex_unlock(&pmic->mutex); - return err; -} - static int tps65910_get_ctrl_register(int id) { switch (id) { @@ -462,13 +371,6 @@ static int tps65911_get_ctrl_register(int id) } } -static int tps65910_enable_time(struct regulator_dev *dev) -{ - struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev); - return pmic->info[id]->enable_time_us; -} - static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); @@ -481,8 +383,9 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) switch (mode) { case REGULATOR_MODE_NORMAL: - return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT, - LDO_ST_MODE_BIT); + return tps65910_reg_update_bits(pmic->mfd, reg, + LDO_ST_MODE_BIT | LDO_ST_ON_BIT, + LDO_ST_ON_BIT); case REGULATOR_MODE_IDLE: value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT; return tps65910_reg_set_bits(mfd, reg, value); @@ -496,15 +399,15 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) static unsigned int tps65910_get_mode(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int reg, value, id = rdev_get_id(dev); + int ret, reg, value, id = rdev_get_id(dev); reg = pmic->get_ctrl_reg(id); if (reg < 0) return reg; - value = tps65910_reg_read_locked(pmic, reg); - if (value < 0) - return value; + ret = tps65910_reg_read(pmic->mfd, reg, &value); + if (ret < 0) + return ret; if (!(value & LDO_ST_ON_BIT)) return REGULATOR_MODE_STANDBY; @@ -517,33 +420,51 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev); + int ret, id = rdev_get_id(dev); int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0; switch (id) { case TPS65910_REG_VDD1: - opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_OP); - mult = tps65910_reg_read_locked(pmic, TPS65910_VDD1); + ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1_OP, &opvsel); + if (ret < 0) + return ret; + ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1, &mult); + if (ret < 0) + return ret; mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_SR); + ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1_SR, &srvsel); + if (ret < 0) + return ret; sr = opvsel & VDD1_OP_CMD_MASK; opvsel &= VDD1_OP_SEL_MASK; srvsel &= VDD1_SR_SEL_MASK; vselmax = 75; break; case TPS65910_REG_VDD2: - opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_OP); - mult = tps65910_reg_read_locked(pmic, TPS65910_VDD2); + ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2_OP, &opvsel); + if (ret < 0) + return ret; + ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2, &mult); + if (ret < 0) + return ret; mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_SR); + ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2_SR, &srvsel); + if (ret < 0) + return ret; sr = opvsel & VDD2_OP_CMD_MASK; opvsel &= VDD2_OP_SEL_MASK; srvsel &= VDD2_SR_SEL_MASK; vselmax = 75; break; case TPS65911_REG_VDDCTRL: - opvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_OP); - srvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_SR); + ret = tps65910_reg_read(pmic->mfd, TPS65911_VDDCTRL_OP, + &opvsel); + if (ret < 0) + return ret; + ret = tps65910_reg_read(pmic->mfd, TPS65911_VDDCTRL_SR, + &srvsel); + if (ret < 0) + return ret; sr = opvsel & VDDCTRL_OP_CMD_MASK; opvsel &= VDDCTRL_OP_SEL_MASK; srvsel &= VDDCTRL_SR_SEL_MASK; @@ -577,15 +498,15 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) static int tps65910_get_voltage_sel(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int reg, value, id = rdev_get_id(dev); + int ret, reg, value, id = rdev_get_id(dev); reg = pmic->get_ctrl_reg(id); if (reg < 0) return reg; - value = tps65910_reg_read_locked(pmic, reg); - if (value < 0) - return value; + ret = tps65910_reg_read(pmic->mfd, reg, &value); + if (ret < 0) + return ret; switch (id) { case TPS65910_REG_VIO: @@ -609,18 +530,20 @@ static int tps65910_get_voltage_sel(struct regulator_dev *dev) static int tps65910_get_voltage_vdd3(struct regulator_dev *dev) { - return 5 * 1000 * 1000; + return dev->desc->volt_table[0]; } static int tps65911_get_voltage_sel(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev); - u8 value, reg; + int ret, id = rdev_get_id(dev); + unsigned int value, reg; reg = pmic->get_ctrl_reg(id); - value = tps65910_reg_read_locked(pmic, reg); + ret = tps65910_reg_read(pmic->mfd, reg, &value); + if (ret < 0) + return ret; switch (id) { case TPS65911_REG_LDO1: @@ -662,10 +585,10 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, dcdc_mult--; vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; - tps65910_modify_bits(pmic, TPS65910_VDD1, - (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), - VDD1_VGAIN_SEL_MASK); - tps65910_reg_write_locked(pmic, TPS65910_VDD1_OP, vsel); + tps65910_reg_update_bits(pmic->mfd, TPS65910_VDD1, + VDD1_VGAIN_SEL_MASK, + dcdc_mult << VDD1_VGAIN_SEL_SHIFT); + tps65910_reg_write(pmic->mfd, TPS65910_VDD1_OP, vsel); break; case TPS65910_REG_VDD2: dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; @@ -673,14 +596,14 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, dcdc_mult--; vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; - tps65910_modify_bits(pmic, TPS65910_VDD2, - (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), - VDD1_VGAIN_SEL_MASK); - tps65910_reg_write_locked(pmic, TPS65910_VDD2_OP, vsel); + tps65910_reg_update_bits(pmic->mfd, TPS65910_VDD2, + VDD1_VGAIN_SEL_MASK, + dcdc_mult << VDD2_VGAIN_SEL_SHIFT); + tps65910_reg_write(pmic->mfd, TPS65910_VDD2_OP, vsel); break; case TPS65911_REG_VDDCTRL: vsel = selector + 3; - tps65910_reg_write_locked(pmic, TPS65911_VDDCTRL_OP, vsel); + tps65910_reg_write(pmic->mfd, TPS65911_VDDCTRL_OP, vsel); } return 0; @@ -706,8 +629,8 @@ static int tps65910_set_voltage_sel(struct regulator_dev *dev, case TPS65910_REG_VAUX2: case TPS65910_REG_VAUX33: case TPS65910_REG_VMMC: - return tps65910_modify_bits(pmic, reg, - (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); + return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK, + selector << LDO_SEL_SHIFT); } return -EINVAL; @@ -727,18 +650,18 @@ static int tps65911_set_voltage_sel(struct regulator_dev *dev, case TPS65911_REG_LDO1: case TPS65911_REG_LDO2: case TPS65911_REG_LDO4: - return tps65910_modify_bits(pmic, reg, - (selector << LDO_SEL_SHIFT), LDO1_SEL_MASK); + return tps65910_reg_update_bits(pmic->mfd, reg, LDO1_SEL_MASK, + selector << LDO_SEL_SHIFT); case TPS65911_REG_LDO3: case TPS65911_REG_LDO5: case TPS65911_REG_LDO6: case TPS65911_REG_LDO7: case TPS65911_REG_LDO8: - return tps65910_modify_bits(pmic, reg, - (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK); + return tps65910_reg_update_bits(pmic->mfd, reg, LDO3_SEL_MASK, + selector << LDO_SEL_SHIFT); case TPS65910_REG_VIO: - return tps65910_modify_bits(pmic, reg, - (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); + return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK, + selector << LDO_SEL_SHIFT); } return -EINVAL; @@ -768,23 +691,6 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, return volt * 100 * mult; } -static int tps65910_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev), voltage; - - if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC) - return -EINVAL; - - if (selector >= pmic->info[id]->n_voltages) - return -EINVAL; - else - voltage = pmic->info[id]->voltage_table[selector] * 1000; - - return voltage; -} - static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); @@ -816,7 +722,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) step_mv = 100; break; case TPS65910_REG_VIO: - return pmic->info[id]->voltage_table[selector] * 1000; + return pmic->info[id]->voltage_table[selector]; default: return -EINVAL; } @@ -824,42 +730,16 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) return (LDO_MIN_VOLT + selector * step_mv) * 1000; } -static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev, - unsigned int old_selector, unsigned int new_selector) -{ - int id = rdev_get_id(dev); - int old_volt, new_volt; - - old_volt = tps65910_list_voltage_dcdc(dev, old_selector); - if (old_volt < 0) - return old_volt; - - new_volt = tps65910_list_voltage_dcdc(dev, new_selector); - if (new_volt < 0) - return new_volt; - - /* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */ - switch (id) { - case TPS65910_REG_VDD1: - case TPS65910_REG_VDD2: - return DIV_ROUND_UP(abs(old_volt - new_volt), 12500); - case TPS65911_REG_VDDCTRL: - return DIV_ROUND_UP(abs(old_volt - new_volt), 5000); - } - return -EINVAL; -} - /* Regulator ops (except VRTC) */ static struct regulator_ops tps65910_ops_dcdc = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage_sel = tps65910_get_voltage_dcdc_sel, .set_voltage_sel = tps65910_set_voltage_dcdc_sel, - .set_voltage_time_sel = tps65910_set_voltage_dcdc_time_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, .list_voltage = tps65910_list_voltage_dcdc, }; @@ -867,30 +747,27 @@ static struct regulator_ops tps65910_ops_vdd3 = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage = tps65910_get_voltage_vdd3, - .list_voltage = tps65910_list_voltage, + .list_voltage = regulator_list_voltage_table, }; static struct regulator_ops tps65910_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage_sel = tps65910_get_voltage_sel, .set_voltage_sel = tps65910_set_voltage_sel, - .list_voltage = tps65910_list_voltage, + .list_voltage = regulator_list_voltage_table, }; static struct regulator_ops tps65911_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage_sel = tps65911_get_voltage_sel, @@ -996,19 +873,27 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, (tps65910_chip_id(mfd) == TPS65911))) { int op_reg_add = pmic->get_ctrl_reg(id) + 1; int sr_reg_add = pmic->get_ctrl_reg(id) + 2; - int opvsel = tps65910_reg_read_locked(pmic, op_reg_add); - int srvsel = tps65910_reg_read_locked(pmic, sr_reg_add); + int opvsel, srvsel; + + ret = tps65910_reg_read(pmic->mfd, op_reg_add, &opvsel); + if (ret < 0) + return ret; + ret = tps65910_reg_read(pmic->mfd, sr_reg_add, &srvsel); + if (ret < 0) + return ret; + if (opvsel & VDD1_OP_CMD_MASK) { u8 reg_val = srvsel & VDD1_OP_SEL_MASK; - ret = tps65910_reg_write_locked(pmic, op_reg_add, - reg_val); + + ret = tps65910_reg_write(pmic->mfd, op_reg_add, + reg_val); if (ret < 0) { dev_err(mfd->dev, "Error in configuring op register\n"); return ret; } } - ret = tps65910_reg_write_locked(pmic, sr_reg_add, 0); + ret = tps65910_reg_write(pmic->mfd, sr_reg_add, 0); if (ret < 0) { dev_err(mfd->dev, "Error in settting sr register\n"); return ret; @@ -1126,6 +1011,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( "ti,regulator-ext-sleep-control", &prop); if (!ret) pmic_plat_data->regulator_ext_sleep_control[idx] = prop; + } return pmic_plat_data; @@ -1136,7 +1022,7 @@ static inline struct tps65910_board *tps65910_parse_dt_reg_data( struct of_regulator_match **tps65910_reg_matches) { *tps65910_reg_matches = NULL; - return 0; + return NULL; } #endif @@ -1168,7 +1054,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev) return -ENOMEM; } - mutex_init(&pmic->mutex); pmic->mfd = tps65910; platform_set_drvdata(pdev, pmic); @@ -1229,23 +1114,31 @@ static __devinit int tps65910_probe(struct platform_device *pdev) pmic->info[i] = info; pmic->desc[i].name = info->name; + pmic->desc[i].supply_name = info->vin_name; pmic->desc[i].id = i; pmic->desc[i].n_voltages = info->n_voltages; + pmic->desc[i].enable_time = info->enable_time_us; if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) { pmic->desc[i].ops = &tps65910_ops_dcdc; pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE * VDD1_2_NUM_VOLT_COARSE; + pmic->desc[i].ramp_delay = 12500; } else if (i == TPS65910_REG_VDD3) { - if (tps65910_chip_id(tps65910) == TPS65910) + if (tps65910_chip_id(tps65910) == TPS65910) { pmic->desc[i].ops = &tps65910_ops_vdd3; - else + pmic->desc[i].volt_table = info->voltage_table; + } else { pmic->desc[i].ops = &tps65910_ops_dcdc; + pmic->desc[i].ramp_delay = 5000; + } } else { - if (tps65910_chip_id(tps65910) == TPS65910) + if (tps65910_chip_id(tps65910) == TPS65910) { pmic->desc[i].ops = &tps65910_ops; - else + pmic->desc[i].volt_table = info->voltage_table; + } else { pmic->desc[i].ops = &tps65911_ops; + } } err = tps65910_set_ext_sleep_config(pmic, i, diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index c7390711d95..242fe90dc56 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -43,9 +43,6 @@ struct twlreg_info { u8 table_len; const u16 *table; - /* regulator specific turn-on delay */ - u16 delay; - /* State REMAP default configuration */ u8 remap; @@ -223,20 +220,6 @@ static int twl6030reg_enable(struct regulator_dev *rdev) return ret; } -static int twl4030reg_enable_time(struct regulator_dev *rdev) -{ - struct twlreg_info *info = rdev_get_drvdata(rdev); - - return info->delay; -} - -static int twl6030reg_enable_time(struct regulator_dev *rdev) -{ - struct twlreg_info *info = rdev_get_drvdata(rdev); - - return info->delay; -} - static int twl4030reg_disable(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); @@ -508,7 +491,6 @@ static struct regulator_ops twl4030ldo_ops = { .enable = twl4030reg_enable, .disable = twl4030reg_disable, .is_enabled = twl4030reg_is_enabled, - .enable_time = twl4030reg_enable_time, .set_mode = twl4030reg_set_mode, @@ -577,59 +559,53 @@ static struct regulator_ops twl6030coresmps_ops = { .get_voltage = twl6030coresmps_get_voltage, }; -static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) +static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned sel) { - struct twlreg_info *info = rdev_get_drvdata(rdev); + struct twlreg_info *info = rdev_get_drvdata(rdev); - return ((info->min_mV + (index * 100)) * 1000); + switch (sel) { + case 0: + return 0; + case 1 ... 24: + /* Linear mapping from 00000001 to 00011000: + * Absolute voltage value = 1.0 V + 0.1 V × (sel – 00000001) + */ + return (info->min_mV + 100 * (sel - 1)) * 1000; + case 25 ... 30: + return -EINVAL; + case 31: + return 2750000; + default: + return -EINVAL; + } } static int -twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, - unsigned *selector) +twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); - int vsel; - - if ((min_uV/1000 < info->min_mV) || (max_uV/1000 > info->max_mV)) - return -EDOM; - - /* - * Use the below formula to calculate vsel - * mV = 1000mv + 100mv * (vsel - 1) - */ - vsel = (min_uV/1000 - 1000)/100 + 1; - *selector = vsel; - return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel); + return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, + selector); } -static int twl6030ldo_get_voltage(struct regulator_dev *rdev) +static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); - int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, - VREG_VOLTAGE); - - if (vsel < 0) - return vsel; + int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE); - /* - * Use the below formula to calculate vsel - * mV = 1000mv + 100mv * (vsel - 1) - */ - return (1000 + (100 * (vsel - 1))) * 1000; + return vsel; } static struct regulator_ops twl6030ldo_ops = { .list_voltage = twl6030ldo_list_voltage, - .set_voltage = twl6030ldo_set_voltage, - .get_voltage = twl6030ldo_get_voltage, + .set_voltage_sel = twl6030ldo_set_voltage_sel, + .get_voltage_sel = twl6030ldo_get_voltage_sel, .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, - .enable_time = twl6030reg_enable_time, .set_mode = twl6030reg_set_mode, @@ -663,7 +639,6 @@ static struct regulator_ops twl4030fixed_ops = { .enable = twl4030reg_enable, .disable = twl4030reg_disable, .is_enabled = twl4030reg_is_enabled, - .enable_time = twl4030reg_enable_time, .set_mode = twl4030reg_set_mode, @@ -678,7 +653,6 @@ static struct regulator_ops twl6030fixed_ops = { .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, - .enable_time = twl6030reg_enable_time, .set_mode = twl6030reg_set_mode, @@ -689,7 +663,6 @@ static struct regulator_ops twl6030_fixed_resource = { .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, - .enable_time = twl6030reg_enable_time, .get_status = twl6030reg_get_status, }; @@ -886,7 +859,6 @@ static struct regulator_ops twlsmps_ops = { .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, - .enable_time = twl6030reg_enable_time, .set_mode = twl6030reg_set_mode, @@ -909,7 +881,6 @@ static struct twlreg_info TWL4030_INFO_##label = { \ .id = num, \ .table_len = ARRAY_SIZE(label##_VSEL_table), \ .table = label##_VSEL_table, \ - .delay = turnon_delay, \ .remap = remap_conf, \ .desc = { \ .name = #label, \ @@ -918,6 +889,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \ .ops = &twl4030ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ + .enable_time = turnon_delay, \ }, \ } @@ -925,7 +897,6 @@ static struct twlreg_info TWL4030_INFO_##label = { \ static struct twlreg_info TWL4030_INFO_##label = { \ .base = offset, \ .id = num, \ - .delay = turnon_delay, \ .remap = remap_conf, \ .desc = { \ .name = #label, \ @@ -933,6 +904,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \ .ops = &twl4030smps_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ + .enable_time = turnon_delay, \ }, \ } @@ -955,7 +927,7 @@ static struct twlreg_info TWL6030_INFO_##label = { \ .desc = { \ .name = #label, \ .id = TWL6030_REG_##label, \ - .n_voltages = (max_mVolts - min_mVolts)/100 + 1, \ + .n_voltages = 32, \ .ops = &twl6030ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -970,7 +942,7 @@ static struct twlreg_info TWL6025_INFO_##label = { \ .desc = { \ .name = #label, \ .id = TWL6025_REG_##label, \ - .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \ + .n_voltages = 32, \ .ops = &twl6030ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -983,7 +955,6 @@ static struct twlreg_info TWLFIXED_INFO_##label = { \ .base = offset, \ .id = num, \ .min_mV = mVolts, \ - .delay = turnon_delay, \ .remap = remap_conf, \ .desc = { \ .name = #label, \ @@ -992,19 +963,20 @@ static struct twlreg_info TWLFIXED_INFO_##label = { \ .ops = &operations, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ + .enable_time = turnon_delay, \ }, \ } #define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \ static struct twlreg_info TWLRES_INFO_##label = { \ .base = offset, \ - .delay = turnon_delay, \ .desc = { \ .name = #label, \ .id = TWL6030_REG_##label, \ .ops = &twl6030_fixed_resource, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ + .enable_time = turnon_delay, \ }, \ } @@ -1109,7 +1081,6 @@ static u8 twl_get_smps_mult(void) #define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label) #define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label) #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label) -#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label) #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label) static const struct of_device_id twl_of_match[] __devinitconst = { @@ -1157,7 +1128,6 @@ static const struct of_device_id twl_of_match[] __devinitconst = { TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB), TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8), TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1), - TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG), TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3), TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4), TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO), diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 099da11e989..7413885be01 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -215,8 +215,8 @@ static int wm831x_buckv_list_voltage(struct regulator_dev *rdev, return -EINVAL; } -static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) +static int wm831x_buckv_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { u16 vsel; @@ -251,20 +251,14 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) return 0; } -static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev, + unsigned vsel) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG; int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL; - int vsel, ret; - - vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV); - if (vsel < 0) - return vsel; - - *selector = vsel; + int ret; /* If this value is already set then do a GPIO update if we can */ if (dcdc->dvs_gpio && dcdc->on_vsel == vsel) @@ -315,7 +309,7 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev, u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL; int vsel; - vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV); + vsel = wm831x_buckv_map_voltage(rdev, uV, uV); if (vsel < 0) return vsel; @@ -373,9 +367,10 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) } static struct regulator_ops wm831x_buckv_ops = { - .set_voltage = wm831x_buckv_set_voltage, + .set_voltage_sel = wm831x_buckv_set_voltage_sel, .get_voltage_sel = wm831x_buckv_get_voltage_sel, .list_voltage = wm831x_buckv_list_voltage, + .map_voltage = wm831x_buckv_map_voltage, .set_suspend_voltage = wm831x_buckv_set_suspend_voltage, .set_current_limit = wm831x_buckv_set_current_limit, .get_current_limit = wm831x_buckv_get_current_limit, @@ -599,60 +594,25 @@ static struct platform_driver wm831x_buckv_driver = { * BUCKP specifics */ -static int wm831x_buckp_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector <= WM831X_BUCKP_MAX_SELECTOR) - return 850000 + (selector * 25000); - else - return -EINVAL; -} - -static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV, int *selector) +static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; - u16 vsel; - - if (min_uV <= 34000000) - vsel = (min_uV - 850000) / 25000; - else - return -EINVAL; - - if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV) - return -EINVAL; - - *selector = vsel; - - return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel); -} - -static int wm831x_buckp_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG; - - return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV, - selector); -} - -static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, - int uV) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL; - unsigned selector; + int sel; + + sel = regulator_map_voltage_linear(rdev, uV, uV); + if (sel < 0) + return sel; - return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector); + return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, sel); } static struct regulator_ops wm831x_buckp_ops = { - .set_voltage = wm831x_buckp_set_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .list_voltage = wm831x_buckp_list_voltage, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .set_suspend_voltage = wm831x_buckp_set_suspend_voltage, .is_enabled = regulator_is_enabled_regmap, @@ -715,6 +675,8 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) dcdc->desc.vsel_mask = WM831X_DC3_ON_VSEL_MASK; dcdc->desc.enable_reg = WM831X_DCDC_ENABLE; dcdc->desc.enable_mask = 1 << id; + dcdc->desc.min_uV = 850000; + dcdc->desc.uV_step = 25000; config.dev = pdev->dev.parent; if (pdata) diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index a9a28d8ac18..5cb70ca1e98 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -78,13 +78,10 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, return -EINVAL; } -static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV, - unsigned *selector) +static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int vsel, ret; + int volt, vsel; if (min_uV < 900000) vsel = 0; @@ -94,36 +91,25 @@ static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, vsel = ((min_uV - 1700000) / 100000) + WM831X_GP_LDO_SELECTOR_LOW + 1; - ret = wm831x_gp_ldo_list_voltage(rdev, vsel); - if (ret < 0) - return ret; - if (ret < min_uV || ret > max_uV) + volt = wm831x_gp_ldo_list_voltage(rdev, vsel); + if (volt < min_uV || volt > max_uV) return -EINVAL; - *selector = vsel; - - return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel); -} - -static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - int reg = ldo->base + WM831X_LDO_ON_CONTROL; - - return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, - selector); + return vsel; } static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - unsigned int selector; + struct wm831x *wm831x = ldo->wm831x; + int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); + sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV); + if (sel < 0) + return sel; + + return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, sel); } static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev) @@ -243,8 +229,9 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { .list_voltage = wm831x_gp_ldo_list_voltage, + .map_voltage = wm831x_gp_ldo_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage = wm831x_gp_ldo_set_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, .get_mode = wm831x_gp_ldo_get_mode, .set_mode = wm831x_gp_ldo_set_mode, @@ -384,13 +371,10 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, return -EINVAL; } -static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV, - unsigned *selector) +static int wm831x_aldo_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int vsel, ret; + int volt, vsel; if (min_uV < 1000000) vsel = 0; @@ -400,35 +384,26 @@ static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, vsel = ((min_uV - 1700000) / 100000) + WM831X_ALDO_SELECTOR_LOW + 1; - ret = wm831x_aldo_list_voltage(rdev, vsel); - if (ret < 0) - return ret; - if (ret < min_uV || ret > max_uV) + volt = wm831x_aldo_list_voltage(rdev, vsel); + if (volt < min_uV || volt > max_uV) return -EINVAL; - *selector = vsel; - - return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel); -} - -static int wm831x_aldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - int reg = ldo->base + WM831X_LDO_ON_CONTROL; + return vsel; - return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV, - selector); } static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - unsigned int selector; + struct wm831x *wm831x = ldo->wm831x; + int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; + + sel = wm831x_aldo_map_voltage(rdev, uV, uV); + if (sel < 0) + return sel; - return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector); + return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel); } static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev) @@ -506,8 +481,9 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_aldo_ops = { .list_voltage = wm831x_aldo_list_voltage, + .map_voltage = wm831x_aldo_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage = wm831x_aldo_set_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, .get_mode = wm831x_aldo_get_mode, .set_mode = wm831x_aldo_set_mode, @@ -628,47 +604,18 @@ static struct platform_driver wm831x_aldo_driver = { #define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf -static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, - int reg, - int min_uV, int max_uV, - unsigned *selector) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int vsel, ret; - - vsel = (min_uV - 800000) / 50000; - - ret = regulator_list_voltage_linear(rdev, vsel); - if (ret < 0) - return ret; - if (ret < min_uV || ret > max_uV) - return -EINVAL; - - *selector = vsel; - - return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel); -} - -static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL; - - return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, - selector); -} - static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL; - unsigned selector; + struct wm831x *wm831x = ldo->wm831x; + int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL; + + sel = regulator_map_voltage_linear(rdev, uV, uV); + if (sel < 0) + return sel; - return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); + return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel); } static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) @@ -690,8 +637,9 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_alive_ldo_ops = { .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage = wm831x_alive_ldo_set_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage, .get_status = wm831x_alive_ldo_get_status, @@ -753,6 +701,7 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) ldo->desc.enable_mask = 1 << id; ldo->desc.min_uV = 800000; ldo->desc.uV_step = 50000; + ldo->desc.enable_time = 1000; config.dev = pdev->dev.parent; if (pdata) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 94e550dc70b..7f0fa22ef2a 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -108,33 +108,6 @@ static int get_isink_val(int min_uA, int max_uA, u16 *setting) return -EINVAL; } -static inline int wm8350_ldo_val_to_mvolts(unsigned int val) -{ - if (val < 16) - return (val * 50) + 900; - else - return ((val - 16) * 100) + 1800; - -} - -static inline unsigned int wm8350_ldo_mvolts_to_val(int mV) -{ - if (mV < 1800) - return (mV - 900) / 50; - else - return ((mV - 1800) / 100) + 16; -} - -static inline int wm8350_dcdc_val_to_mvolts(unsigned int val) -{ - return (val * 25) + 850; -} - -static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV) -{ - return (mV - 850) / 25; -} - static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA, int max_uA) { @@ -359,104 +332,13 @@ int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode, } EXPORT_SYMBOL_GPL(wm8350_isink_set_flash); -static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV, unsigned *selector) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int volt_reg, dcdc = rdev_get_id(rdev), mV, - min_mV = min_uV / 1000, max_mV = max_uV / 1000; - u16 val; - - if (min_mV < 850 || min_mV > 4025) - return -EINVAL; - if (max_mV < 850 || max_mV > 4025) - return -EINVAL; - - /* step size is 25mV */ - mV = (min_mV - 826) / 25; - if (wm8350_dcdc_val_to_mvolts(mV) > max_mV) - return -EINVAL; - BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV); - - switch (dcdc) { - case WM8350_DCDC_1: - volt_reg = WM8350_DCDC1_CONTROL; - break; - case WM8350_DCDC_3: - volt_reg = WM8350_DCDC3_CONTROL; - break; - case WM8350_DCDC_4: - volt_reg = WM8350_DCDC4_CONTROL; - break; - case WM8350_DCDC_6: - volt_reg = WM8350_DCDC6_CONTROL; - break; - case WM8350_DCDC_2: - case WM8350_DCDC_5: - default: - return -EINVAL; - } - - *selector = mV; - - /* all DCDCs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK; - wm8350_reg_write(wm8350, volt_reg, val | mV); - return 0; -} - -static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int volt_reg, dcdc = rdev_get_id(rdev); - - switch (dcdc) { - case WM8350_DCDC_1: - volt_reg = WM8350_DCDC1_CONTROL; - break; - case WM8350_DCDC_3: - volt_reg = WM8350_DCDC3_CONTROL; - break; - case WM8350_DCDC_4: - volt_reg = WM8350_DCDC4_CONTROL; - break; - case WM8350_DCDC_6: - volt_reg = WM8350_DCDC6_CONTROL; - break; - case WM8350_DCDC_2: - case WM8350_DCDC_5: - default: - return -EINVAL; - } - - /* all DCDCs have same mV bits */ - return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK; -} - -static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector > WM8350_DCDC_MAX_VSEL) - return -EINVAL; - return wm8350_dcdc_val_to_mvolts(selector) * 1000; -} - static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev); + int sel, volt_reg, dcdc = rdev_get_id(rdev); u16 val; - dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV); - - if (mV && (mV < 850 || mV > 4025)) { - dev_err(wm8350->dev, - "DCDC%d suspend voltage %d mV out of range\n", - dcdc, mV); - return -EINVAL; - } - if (mV == 0) - mV = 850; + dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, uV / 1000); switch (dcdc) { case WM8350_DCDC_1: @@ -477,10 +359,13 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV) return -EINVAL; } + sel = regulator_map_voltage_linear(rdev, uV, uV); + if (sel < 0) + return -EINVAL; + /* all DCDCs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK; - wm8350_reg_write(wm8350, volt_reg, - val | wm8350_dcdc_mvolts_to_val(mV)); + wm8350_reg_write(wm8350, volt_reg, val | sel); return 0; } @@ -657,19 +542,49 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev, return 0; } +static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + if (selector > WM8350_LDO1_VSEL_MASK) + return -EINVAL; + + if (selector < 16) + return (selector * 50000) + 900000; + else + return ((selector - 16) * 100000) + 1800000; +} + +static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV) +{ + int volt, sel; + int min_mV = min_uV / 1000; + int max_mV = max_uV / 1000; + + if (min_mV < 900 || min_mV > 3300) + return -EINVAL; + if (max_mV < 900 || max_mV > 3300) + return -EINVAL; + + if (min_mV < 1800) /* step size is 50mV < 1800mV */ + sel = DIV_ROUND_UP(min_uV - 900, 50); + else /* step size is 100mV > 1800mV */ + sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16; + + volt = wm8350_ldo_list_voltage(rdev, sel); + if (volt < min_uV || volt > max_uV) + return -EINVAL; + + return sel; +} + static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev); + int sel, volt_reg, ldo = rdev_get_id(rdev); u16 val; - dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV); - - if (mV < 900 || mV > 3300) { - dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n", - ldo, mV); - return -EINVAL; - } + dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, uV / 1000); switch (ldo) { case WM8350_LDO_1: @@ -688,10 +603,13 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) return -EINVAL; } + sel = wm8350_ldo_map_voltage(rdev, uV, uV); + if (sel < 0) + return -EINVAL; + /* all LDOs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK; - wm8350_reg_write(wm8350, volt_reg, - val | wm8350_ldo_mvolts_to_val(mV)); + wm8350_reg_write(wm8350, volt_reg, val | sel); return 0; } @@ -753,92 +671,6 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev) return 0; } -static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV, unsigned *selector) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000, - max_mV = max_uV / 1000; - u16 val; - - if (min_mV < 900 || min_mV > 3300) - return -EINVAL; - if (max_mV < 900 || max_mV > 3300) - return -EINVAL; - - if (min_mV < 1800) { - /* step size is 50mV < 1800mV */ - mV = (min_mV - 851) / 50; - if (wm8350_ldo_val_to_mvolts(mV) > max_mV) - return -EINVAL; - BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV); - } else { - /* step size is 100mV > 1800mV */ - mV = ((min_mV - 1701) / 100) + 16; - if (wm8350_ldo_val_to_mvolts(mV) > max_mV) - return -EINVAL; - BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV); - } - - switch (ldo) { - case WM8350_LDO_1: - volt_reg = WM8350_LDO1_CONTROL; - break; - case WM8350_LDO_2: - volt_reg = WM8350_LDO2_CONTROL; - break; - case WM8350_LDO_3: - volt_reg = WM8350_LDO3_CONTROL; - break; - case WM8350_LDO_4: - volt_reg = WM8350_LDO4_CONTROL; - break; - default: - return -EINVAL; - } - - *selector = mV; - - /* all LDOs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK; - wm8350_reg_write(wm8350, volt_reg, val | mV); - return 0; -} - -static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int volt_reg, ldo = rdev_get_id(rdev); - - switch (ldo) { - case WM8350_LDO_1: - volt_reg = WM8350_LDO1_CONTROL; - break; - case WM8350_LDO_2: - volt_reg = WM8350_LDO2_CONTROL; - break; - case WM8350_LDO_3: - volt_reg = WM8350_LDO3_CONTROL; - break; - case WM8350_LDO_4: - volt_reg = WM8350_LDO4_CONTROL; - break; - default: - return -EINVAL; - } - - /* all LDOs have same mV bits */ - return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK; -} - -static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector > WM8350_LDO1_VSEL_MASK) - return -EINVAL; - return wm8350_ldo_val_to_mvolts(selector) * 1000; -} - int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start, u16 stop, u16 fault) { @@ -959,63 +791,6 @@ int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode, } EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode); -static int wm8350_dcdc_enable(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int dcdc = rdev_get_id(rdev); - u16 shift; - - if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6) - return -EINVAL; - - shift = dcdc - WM8350_DCDC_1; - wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift); - return 0; -} - -static int wm8350_dcdc_disable(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int dcdc = rdev_get_id(rdev); - u16 shift; - - if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6) - return -EINVAL; - - shift = dcdc - WM8350_DCDC_1; - wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift); - - return 0; -} - -static int wm8350_ldo_enable(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int ldo = rdev_get_id(rdev); - u16 shift; - - if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4) - return -EINVAL; - - shift = (ldo - WM8350_LDO_1) + 8; - wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift); - return 0; -} - -static int wm8350_ldo_disable(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int ldo = rdev_get_id(rdev); - u16 shift; - - if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4) - return -EINVAL; - - shift = (ldo - WM8350_LDO_1) + 8; - wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift); - return 0; -} - static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable) { int reg = 0, ret; @@ -1197,42 +972,17 @@ static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev, return mode; } -static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int dcdc = rdev_get_id(rdev), shift; - - if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6) - return -EINVAL; - - shift = dcdc - WM8350_DCDC_1; - return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED) - & (1 << shift); -} - -static int wm8350_ldo_is_enabled(struct regulator_dev *rdev) -{ - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - int ldo = rdev_get_id(rdev), shift; - - if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4) - return -EINVAL; - - shift = (ldo - WM8350_LDO_1) + 8; - return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED) - & (1 << shift); -} - static struct regulator_ops wm8350_dcdc_ops = { - .set_voltage = wm8350_dcdc_set_voltage, - .get_voltage_sel = wm8350_dcdc_get_voltage_sel, - .list_voltage = wm8350_dcdc_list_voltage, - .enable = wm8350_dcdc_enable, - .disable = wm8350_dcdc_disable, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .get_mode = wm8350_dcdc_get_mode, .set_mode = wm8350_dcdc_set_mode, .get_optimum_mode = wm8350_dcdc_get_optimum_mode, - .is_enabled = wm8350_dcdc_is_enabled, .set_suspend_voltage = wm8350_dcdc_set_suspend_voltage, .set_suspend_enable = wm8350_dcdc_set_suspend_enable, .set_suspend_disable = wm8350_dcdc_set_suspend_disable, @@ -1240,20 +990,21 @@ static struct regulator_ops wm8350_dcdc_ops = { }; static struct regulator_ops wm8350_dcdc2_5_ops = { - .enable = wm8350_dcdc_enable, - .disable = wm8350_dcdc_disable, - .is_enabled = wm8350_dcdc_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .set_suspend_enable = wm8350_dcdc25_set_suspend_enable, .set_suspend_disable = wm8350_dcdc25_set_suspend_disable, }; static struct regulator_ops wm8350_ldo_ops = { - .set_voltage = wm8350_ldo_set_voltage, - .get_voltage_sel = wm8350_ldo_get_voltage_sel, + .map_voltage = wm8350_ldo_map_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = wm8350_ldo_list_voltage, - .enable = wm8350_ldo_enable, - .disable = wm8350_ldo_disable, - .is_enabled = wm8350_ldo_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .get_mode = wm8350_ldo_get_mode, .set_suspend_voltage = wm8350_ldo_set_suspend_voltage, .set_suspend_enable = wm8350_ldo_set_suspend_enable, @@ -1277,6 +1028,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_DC1, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_DCDC_MAX_VSEL + 1, + .min_uV = 850000, + .uV_step = 25000, + .vsel_reg = WM8350_DCDC1_CONTROL, + .vsel_mask = WM8350_DC1_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_DC1_ENA, .owner = THIS_MODULE, }, { @@ -1285,6 +1042,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .ops = &wm8350_dcdc2_5_ops, .irq = WM8350_IRQ_UV_DC2, .type = REGULATOR_VOLTAGE, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_DC2_ENA, .owner = THIS_MODULE, }, { @@ -1294,6 +1053,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_DC3, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_DCDC_MAX_VSEL + 1, + .min_uV = 850000, + .uV_step = 25000, + .vsel_reg = WM8350_DCDC3_CONTROL, + .vsel_mask = WM8350_DC3_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_DC3_ENA, .owner = THIS_MODULE, }, { @@ -1303,6 +1068,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_DC4, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_DCDC_MAX_VSEL + 1, + .min_uV = 850000, + .uV_step = 25000, + .vsel_reg = WM8350_DCDC4_CONTROL, + .vsel_mask = WM8350_DC4_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_DC4_ENA, .owner = THIS_MODULE, }, { @@ -1311,6 +1082,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .ops = &wm8350_dcdc2_5_ops, .irq = WM8350_IRQ_UV_DC5, .type = REGULATOR_VOLTAGE, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_DC5_ENA, .owner = THIS_MODULE, }, { @@ -1320,6 +1093,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_DC6, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_DCDC_MAX_VSEL + 1, + .min_uV = 850000, + .uV_step = 25000, + .vsel_reg = WM8350_DCDC6_CONTROL, + .vsel_mask = WM8350_DC6_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_DC6_ENA, .owner = THIS_MODULE, }, { @@ -1329,6 +1108,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO1, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO1_VSEL_MASK + 1, + .vsel_reg = WM8350_LDO1_CONTROL, + .vsel_mask = WM8350_LDO1_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_LDO1_ENA, .owner = THIS_MODULE, }, { @@ -1338,6 +1121,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO2, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO2_VSEL_MASK + 1, + .vsel_reg = WM8350_LDO2_CONTROL, + .vsel_mask = WM8350_LDO2_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_LDO2_ENA, .owner = THIS_MODULE, }, { @@ -1347,6 +1134,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO3, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO3_VSEL_MASK + 1, + .vsel_reg = WM8350_LDO3_CONTROL, + .vsel_mask = WM8350_LDO3_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_LDO3_ENA, .owner = THIS_MODULE, }, { @@ -1356,6 +1147,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO4, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO4_VSEL_MASK + 1, + .vsel_reg = WM8350_LDO4_CONTROL, + .vsel_mask = WM8350_LDO4_VSEL_MASK, + .enable_reg = WM8350_DCDC_LDO_REQUESTED, + .enable_mask = WM8350_LDO4_ENA, .owner = THIS_MODULE, }, { @@ -1429,6 +1224,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.init_data = pdev->dev.platform_data; config.driver_data = dev_get_drvdata(&pdev->dev); + config.regmap = wm8350->regmap; /* register regulator */ rdev = regulator_register(&wm8350_reg[pdev->id], &config); diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 69a2b7ce5e4..9035dd05361 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -28,34 +28,26 @@ static int wm8400_ldo_list_voltage(struct regulator_dev *dev, if (selector < 15) return 900000 + (selector * 50000); else - return 1600000 + ((selector - 14) * 100000); + return 1700000 + ((selector - 15) * 100000); } static int wm8400_ldo_map_voltage(struct regulator_dev *dev, int min_uV, int max_uV) { u16 val; + int volt; if (min_uV < 900000 || min_uV > 3300000) return -EINVAL; - if (min_uV < 1700000) { - /* Steps of 50mV from 900mV; */ + if (min_uV < 1700000) /* Steps of 50mV from 900mV; */ val = DIV_ROUND_UP(min_uV - 900000, 50000); + else /* Steps of 100mV from 1700mV */ + val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15; - if ((val * 50000) + 900000 > max_uV) - return -EINVAL; - BUG_ON((val * 50000) + 900000 < min_uV); - } else { - /* Steps of 100mV from 1700mV */ - val = DIV_ROUND_UP(min_uV - 1700000, 100000); - - if ((val * 100000) + 1700000 > max_uV) - return -EINVAL; - BUG_ON((val * 100000) + 1700000 < min_uV); - - val += 0xf; - } + volt = wm8400_ldo_list_voltage(dev, val); + if (volt < min_uV || volt > max_uV) + return -EINVAL; return val; } @@ -152,6 +144,7 @@ static struct regulator_ops wm8400_dcdc_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_mode = wm8400_dcdc_get_mode, diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 9a994316e63..86bb48db149 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -26,8 +26,6 @@ #include <linux/mfd/wm8994/pdata.h> struct wm8994_ldo { - int enable; - bool is_enabled; struct regulator_dev *regulator; struct wm8994 *wm8994; }; @@ -35,64 +33,9 @@ struct wm8994_ldo { #define WM8994_LDO1_MAX_SELECTOR 0x7 #define WM8994_LDO2_MAX_SELECTOR 0x3 -static int wm8994_ldo_enable(struct regulator_dev *rdev) -{ - struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - - /* If we have no soft control assume that the LDO is always enabled. */ - if (!ldo->enable) - return 0; - - gpio_set_value_cansleep(ldo->enable, 1); - ldo->is_enabled = true; - - return 0; -} - -static int wm8994_ldo_disable(struct regulator_dev *rdev) -{ - struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - - /* If we have no soft control assume that the LDO is always enabled. */ - if (!ldo->enable) - return -EINVAL; - - gpio_set_value_cansleep(ldo->enable, 0); - ldo->is_enabled = false; - - return 0; -} - -static int wm8994_ldo_is_enabled(struct regulator_dev *rdev) -{ - struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - - return ldo->is_enabled; -} - -static int wm8994_ldo_enable_time(struct regulator_dev *rdev) -{ - /* 3ms is fairly conservative but this shouldn't be too performance - * critical; can be tweaked per-system if required. */ - return 3000; -} - -static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - if (selector > WM8994_LDO1_MAX_SELECTOR) - return -EINVAL; - - return (selector * 100000) + 2400000; -} - static struct regulator_ops wm8994_ldo1_ops = { - .enable = wm8994_ldo_enable, - .disable = wm8994_ldo_disable, - .is_enabled = wm8994_ldo_is_enabled, - .enable_time = wm8994_ldo_enable_time, - - .list_voltage = wm8994_ldo1_list_voltage, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, }; @@ -124,11 +67,6 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, } static struct regulator_ops wm8994_ldo2_ops = { - .enable = wm8994_ldo_enable, - .disable = wm8994_ldo_disable, - .is_enabled = wm8994_ldo_is_enabled, - .enable_time = wm8994_ldo_enable_time, - .list_voltage = wm8994_ldo2_list_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -143,6 +81,9 @@ static const struct regulator_desc wm8994_ldo_desc[] = { .vsel_reg = WM8994_LDO_1, .vsel_mask = WM8994_LDO1_VSEL_MASK, .ops = &wm8994_ldo1_ops, + .min_uV = 2400000, + .uV_step = 100000, + .enable_time = 3000, .owner = THIS_MODULE, }, { @@ -153,6 +94,7 @@ static const struct regulator_desc wm8994_ldo_desc[] = { .vsel_reg = WM8994_LDO_2, .vsel_mask = WM8994_LDO2_VSEL_MASK, .ops = &wm8994_ldo2_ops, + .enable_time = 3000, .owner = THIS_MODULE, }, }; @@ -176,39 +118,26 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev) ldo->wm8994 = wm8994; - if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) { - ldo->enable = pdata->ldo[id].enable; - - ret = gpio_request_one(ldo->enable, 0, "WM8994 LDO enable"); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", - ret); - goto err; - } - } else - ldo->is_enabled = true; - config.dev = wm8994->dev; config.driver_data = ldo; config.regmap = wm8994->regmap; - if (pdata) + if (pdata) { config.init_data = pdata->ldo[id].init_data; + config.ena_gpio = pdata->ldo[id].enable; + } ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", id + 1, ret); - goto err_gpio; + goto err; } platform_set_drvdata(pdev, ldo); return 0; -err_gpio: - if (gpio_is_valid(ldo->enable)) - gpio_free(ldo->enable); err: return ret; } @@ -220,8 +149,6 @@ static __devexit int wm8994_ldo_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); regulator_unregister(ldo->regulator); - if (gpio_is_valid(ldo->enable)) - gpio_free(ldo->enable); return 0; } diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 39d3aa41add..f56c8ba3a86 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -1085,7 +1085,7 @@ static int __init rpmsg_init(void) return ret; } -module_init(rpmsg_init); +subsys_initcall(rpmsg_init); static void __exit rpmsg_fini(void) { diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 77759c78cc2..5b30132960c 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2643,19 +2643,9 @@ static void qlt_do_work(struct work_struct *work) spin_lock_irqsave(&ha->hardware_lock, flags); sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); - if (sess) { - if (unlikely(sess->tearing_down)) { - sess = NULL; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - goto out_term; - } else { - /* - * Do the extra kref_get() before dropping - * qla_hw_data->hardware_lock. - */ - kref_get(&sess->se_sess->sess_kref); - } - } + /* Do kref_get() before dropping qla_hw_data->hardware_lock. */ + if (sess) + kref_get(&sess->se_sess->sess_kref); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (unlikely(!sess)) { diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 9f9ef1644fd..170af157121 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -639,7 +639,7 @@ struct qla_tgt_func_tmpl { int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *, unsigned char *, uint32_t, int, int, int); - int (*handle_data)(struct qla_tgt_cmd *); + void (*handle_data)(struct qla_tgt_cmd *); int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, uint32_t, uint8_t, uint32_t); void (*free_cmd)(struct qla_tgt_cmd *); @@ -813,7 +813,6 @@ struct qla_tgt_sess { unsigned int conf_compl_supported:1; unsigned int deleted:1; unsigned int local:1; - unsigned int tearing_down:1; struct se_session *se_sess; struct scsi_qla_host *vha; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 6e64314dbbb..4752f65a927 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -38,8 +38,6 @@ #include <linux/string.h> #include <linux/configfs.h> #include <linux/ctype.h> -#include <linux/string.h> -#include <linux/ctype.h> #include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -466,8 +464,7 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess) vha = sess->vha; spin_lock_irqsave(&vha->hw->hardware_lock, flags); - sess->tearing_down = 1; - target_splice_sess_cmd_list(se_sess); + target_sess_cmd_list_set_waiting(se_sess); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); return 1; @@ -600,28 +597,15 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, return -EINVAL; } - target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], + return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], cmd->unpacked_lun, data_length, fcp_task_attr, data_dir, flags); - return 0; } -static void tcm_qla2xxx_do_rsp(struct work_struct *work) +static void tcm_qla2xxx_handle_data_work(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - /* - * Dispatch ->queue_status from workqueue process context - */ - transport_generic_request_failure(&cmd->se_cmd); -} -/* - * Called from qla_target.c:qlt_do_ctio_completion() - */ -static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) -{ - struct se_cmd *se_cmd = &cmd->se_cmd; - unsigned long flags; /* * Ensure that the complete FCP WRITE payload has been received. * Otherwise return an exception via CHECK_CONDITION status. @@ -631,24 +615,26 @@ static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) * Check if se_cmd has already been aborted via LUN_RESET, and * waiting upon completion in tcm_qla2xxx_write_pending_status() */ - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - if (se_cmd->transport_state & CMD_T_ABORTED) { - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - complete(&se_cmd->t_transport_stop_comp); - return 0; + if (cmd->se_cmd.transport_state & CMD_T_ABORTED) { + complete(&cmd->se_cmd.t_transport_stop_comp); + return; } - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - se_cmd->scsi_sense_reason = TCM_CHECK_CONDITION_ABORT_CMD; - INIT_WORK(&cmd->work, tcm_qla2xxx_do_rsp); - queue_work(tcm_qla2xxx_free_wq, &cmd->work); - return 0; + cmd->se_cmd.scsi_sense_reason = TCM_CHECK_CONDITION_ABORT_CMD; + transport_generic_request_failure(&cmd->se_cmd); + return; } - /* - * We now tell TCM to queue this WRITE CDB with TRANSPORT_PROCESS_WRITE - * status to the backstore processing thread. - */ - return transport_generic_handle_data(&cmd->se_cmd); + + return target_execute_cmd(&cmd->se_cmd); +} + +/* + * Called from qla_target.c:qlt_do_ctio_completion() + */ +static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) +{ + INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work); + queue_work(tcm_qla2xxx_free_wq, &cmd->work); } /* @@ -1690,7 +1676,6 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = { .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, - .new_cmd_map = NULL, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, .put_session = tcm_qla2xxx_put_session, diff --git a/drivers/scsi/scsi_wait_scan.c b/drivers/scsi/scsi_wait_scan.c index ae781487461..07273453887 100644 --- a/drivers/scsi/scsi_wait_scan.c +++ b/drivers/scsi/scsi_wait_scan.c @@ -22,11 +22,6 @@ static int __init wait_scan_init(void) * and might not yet have reached the scsi async scanning */ wait_for_device_probe(); - /* - * and then we wait for the actual asynchronous scsi scan - * to finish. - */ - scsi_complete_async_scans(); return 0; } diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 61648d84fbb..9fdcb561422 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -9,7 +9,8 @@ target_core_mod-y := target_core_configfs.o \ target_core_tmr.o \ target_core_tpg.o \ target_core_transport.o \ - target_core_cdb.o \ + target_core_sbc.o \ + target_core_spc.o \ target_core_ua.o \ target_core_rd.o \ target_core_stat.o diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d57d10cb2e4..97c0f78c3c9 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -429,19 +429,8 @@ int iscsit_reset_np_thread( int iscsit_del_np_comm(struct iscsi_np *np) { - if (!np->np_socket) - return 0; - - /* - * Some network transports allocate their own struct sock->file, - * see if we need to free any additional allocated resources. - */ - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(np->np_socket->file); - np->np_socket->file = NULL; - } - - sock_release(np->np_socket); + if (np->np_socket) + sock_release(np->np_socket); return 0; } @@ -1413,8 +1402,10 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) spin_unlock_bh(&cmd->istate_lock); iscsit_stop_dataout_timer(cmd); - return (!ooo_cmdsn) ? transport_generic_handle_data( - &cmd->se_cmd) : 0; + if (ooo_cmdsn) + return 0; + target_execute_cmd(&cmd->se_cmd); + return 0; } else /* DATAOUT_CANNOT_RECOVER */ return -1; @@ -2683,7 +2674,7 @@ static int iscsit_send_logout_response( */ logout_conn = iscsit_get_conn_from_cid_rcfr(sess, cmd->logout_cid); - if ((logout_conn)) { + if (logout_conn) { iscsit_connection_reinstatement_rcfr(logout_conn); iscsit_dec_conn_usage_count(logout_conn); } @@ -4077,13 +4068,8 @@ int iscsit_close_connection( kfree(conn->conn_ops); conn->conn_ops = NULL; - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } + if (conn->sock) sock_release(conn->sock); - } conn->thread_set = NULL; pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 69dc8e35c03..a7b25e783b5 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -47,28 +47,6 @@ struct lio_target_configfs_attribute { ssize_t (*store)(void *, const char *, size_t); }; -struct iscsi_portal_group *lio_get_tpg_from_tpg_item( - struct config_item *item, - struct iscsi_tiqn **tiqn_out) -{ - struct se_portal_group *se_tpg = container_of(to_config_group(item), - struct se_portal_group, tpg_group); - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - int ret; - - if (!tpg) { - pr_err("Unable to locate struct iscsi_portal_group " - "pointer\n"); - return NULL; - } - ret = iscsit_get_tpg(tpg); - if (ret < 0) - return NULL; - - *tiqn_out = tpg->tpg_tiqn; - return tpg; -} - /* Start items for lio_target_portal_cit */ static ssize_t lio_target_np_show_sctp( diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 1c70144cdaf..8a908b28d8b 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -224,7 +224,6 @@ enum iscsi_timer_flags_table { /* Used for struct iscsi_np->np_flags */ enum np_flags_table { NPF_IP_NETWORK = 0x00, - NPF_SCTP_STRUCT_FILE = 0x01 /* Bugfix */ }; /* Used for struct iscsi_np->np_thread_state */ @@ -481,6 +480,7 @@ struct iscsi_tmr_req { bool task_reassign:1; u32 ref_cmd_sn; u32 exp_data_sn; + struct iscsi_cmd *ref_cmd; struct iscsi_conn_recovery *conn_recovery; struct se_tmr_req *se_tmr_req; }; @@ -503,7 +503,6 @@ struct iscsi_conn { u16 local_port; int net_size; u32 auth_id; -#define CONNFLAG_SCTP_STRUCT_FILE 0x01 u32 conn_flags; /* Used for iscsi_tx_login_rsp() */ u32 login_itt; diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index ecdd46deedd..3df8a2cef86 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -965,8 +965,8 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) if (cmd->immediate_data) { if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { spin_unlock_bh(&cmd->istate_lock); - return transport_generic_handle_data( - &cmd->se_cmd); + target_execute_cmd(&cmd->se_cmd); + return 0; } spin_unlock_bh(&cmd->istate_lock); diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index a3656c9903a..0694d9b1bce 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -518,7 +518,7 @@ int iscsi_login_post_auth_non_zero_tsih( * initiator and release the new connection. */ conn_ptr = iscsit_get_conn_from_cid_rcfr(sess, cid); - if ((conn_ptr)) { + if (conn_ptr) { pr_err("Connection exists with CID %hu for %s," " performing connection reinstatement.\n", conn_ptr->cid, sess->sess_ops->InitiatorName); @@ -539,7 +539,7 @@ int iscsi_login_post_auth_non_zero_tsih( if (sess->sess_ops->ErrorRecoveryLevel == 2) { cr = iscsit_get_inactive_connection_recovery_entry( sess, cid); - if ((cr)) { + if (cr) { pr_debug("Performing implicit logout" " for connection recovery on CID: %hu\n", conn->cid); @@ -795,22 +795,6 @@ int iscsi_target_setup_login_socket( } np->np_socket = sock; /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!sock->file) { - sock->file = kzalloc(sizeof(struct file), GFP_KERNEL); - if (!sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - ret = -ENOMEM; - goto fail; - } - np->np_flags |= NPF_SCTP_STRUCT_FILE; - } - } - /* * Setup the np->np_sockaddr from the passed sockaddr setup * in iscsi_target_configfs.c code.. */ @@ -869,21 +853,15 @@ int iscsi_target_setup_login_socket( fail: np->np_socket = NULL; - if (sock) { - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(sock->file); - sock->file = NULL; - } - + if (sock) sock_release(sock); - } return ret; } static int __iscsi_target_login_thread(struct iscsi_np *np) { u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0; - int err, ret = 0, set_sctp_conn_flag, stop; + int err, ret = 0, stop; struct iscsi_conn *conn = NULL; struct iscsi_login *login; struct iscsi_portal_group *tpg = NULL; @@ -894,7 +872,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) struct sockaddr_in6 sock_in6; flush_signals(current); - set_sctp_conn_flag = 0; sock = np->np_socket; spin_lock_bh(&np->np_thread_lock); @@ -917,35 +894,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) spin_unlock_bh(&np->np_thread_lock); goto out; } - /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!new_sock->file) { - new_sock->file = kzalloc( - sizeof(struct file), GFP_KERNEL); - if (!new_sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - sock_release(new_sock); - /* Get another socket */ - return 1; - } - set_sctp_conn_flag = 1; - } - } - iscsi_start_login_thread_timer(np); conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); if (!conn) { pr_err("Could not allocate memory for" " new connection\n"); - if (set_sctp_conn_flag) { - kfree(new_sock->file); - new_sock->file = NULL; - } sock_release(new_sock); /* Get another socket */ return 1; @@ -955,9 +909,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) conn->conn_state = TARG_CONN_STATE_FREE; conn->sock = new_sock; - if (set_sctp_conn_flag) - conn->conn_flags |= CONNFLAG_SCTP_STRUCT_FILE; - pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); conn->conn_state = TARG_CONN_STATE_XPT_UP; @@ -1081,7 +1032,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) goto new_sess_out; zero_tsih = (pdu->tsih == 0x0000); - if ((zero_tsih)) { + if (zero_tsih) { /* * This is the leading connection of a new session. * We wait until after authentication to check for @@ -1205,13 +1156,8 @@ old_sess_out: iscsi_release_param_list(conn->param_list); conn->param_list = NULL; } - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } + if (conn->sock) sock_release(conn->sock); - } kfree(conn); if (tpg) { diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index ed5241e7f12..0c4760fabfc 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -681,7 +681,7 @@ int iscsi_update_param_value(struct iscsi_param *param, char *value) param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); if (!param->value) { pr_err("Unable to allocate memory for value.\n"); - return -1; + return -ENOMEM; } memcpy(param->value, value, strlen(value)); diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index f4e640b51fd..f62fe123d90 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -19,6 +19,7 @@ ******************************************************************************/ #include <asm/unaligned.h> +#include <scsi/scsi_device.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> @@ -61,7 +62,7 @@ u8 iscsit_tmr_abort_task( } se_tmr->ref_task_tag = hdr->rtt; - se_tmr->ref_cmd = &ref_cmd->se_cmd; + tmr_req->ref_cmd = ref_cmd; tmr_req->ref_cmd_sn = hdr->refcmdsn; tmr_req->exp_data_sn = hdr->exp_datasn; @@ -121,7 +122,7 @@ u8 iscsit_tmr_task_reassign( struct iscsi_tmr_req *tmr_req = cmd->tmr_req; struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; struct iscsi_tm *hdr = (struct iscsi_tm *) buf; - int ret; + int ret, ref_lun; pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x," " RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n", @@ -155,9 +156,16 @@ u8 iscsit_tmr_task_reassign( return ISCSI_TMF_RSP_REJECTED; } + ref_lun = scsilun_to_int(&hdr->lun); + if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) { + pr_err("Unable to perform connection recovery for" + " differing ref_lun: %d ref_cmd orig_fe_lun: %u\n", + ref_lun, ref_cmd->se_cmd.orig_fe_lun); + return ISCSI_TMF_RSP_REJECTED; + } + se_tmr->ref_task_tag = hdr->rtt; - se_tmr->ref_cmd = &ref_cmd->se_cmd; - se_tmr->ref_task_lun = get_unaligned_le64(&hdr->lun); + tmr_req->ref_cmd = ref_cmd; tmr_req->ref_cmd_sn = hdr->refcmdsn; tmr_req->exp_data_sn = hdr->exp_datasn; tmr_req->conn_recovery = cr; @@ -191,9 +199,7 @@ static int iscsit_task_reassign_complete_nop_out( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *cmd = tmr_req->ref_cmd; struct iscsi_conn_recovery *cr; if (!cmd->cr) { @@ -251,7 +257,8 @@ static int iscsit_task_reassign_complete_write( pr_debug("WRITE ITT: 0x%08x: t_state: %d" " never sent to transport\n", cmd->init_task_tag, cmd->se_cmd.t_state); - return transport_generic_handle_data(se_cmd); + target_execute_cmd(se_cmd); + return 0; } cmd->i_state = ISTATE_SEND_STATUS; @@ -360,9 +367,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *cmd = tmr_req->ref_cmd; struct iscsi_conn_recovery *cr; if (!cmd->cr) { @@ -385,7 +390,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd( list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); - if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { + if (cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION) { cmd->i_state = ISTATE_SEND_STATUS; iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); return 0; @@ -411,17 +416,14 @@ static int iscsit_task_reassign_complete( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd; struct iscsi_cmd *cmd; int ret = 0; - if (!se_tmr->ref_cmd) { + if (!tmr_req->ref_cmd) { pr_err("TMR Request is missing a RefCmd struct iscsi_cmd.\n"); return -1; } - se_cmd = se_tmr->ref_cmd; - cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + cmd = tmr_req->ref_cmd; cmd->conn = conn; @@ -547,9 +549,7 @@ int iscsit_task_reassign_prepare_write( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *cmd = tmr_req->ref_cmd; struct iscsi_pdu *pdu = NULL; struct iscsi_r2t *r2t = NULL, *r2t_tmp; int first_incomplete_r2t = 1, i = 0; @@ -782,14 +782,12 @@ int iscsit_check_task_reassign_expdatasn( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *ref_cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *ref_cmd = tmr_req->ref_cmd; if (ref_cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) return 0; - if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) + if (ref_cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION) return 0; if (ref_cmd->data_direction == DMA_NONE) diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 879d8d0fa3f..a38a3f8ab0d 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -303,6 +303,7 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) { struct iscsi_param *param; struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; + int ret; spin_lock(&tpg->tpg_state_lock); if (tpg->tpg_state == TPG_STATE_ACTIVE) { @@ -319,19 +320,19 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); if (!param) { spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; + return -EINVAL; } if (ISCSI_TPG_ATTRIB(tpg)->authentication) { - if (!strcmp(param->value, NONE)) - if (iscsi_update_param_value(param, CHAP) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; - } - if (iscsit_ta_authentication(tpg, 1) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; + if (!strcmp(param->value, NONE)) { + ret = iscsi_update_param_value(param, CHAP); + if (ret) + goto err; } + + ret = iscsit_ta_authentication(tpg, 1); + if (ret < 0) + goto err; } tpg->tpg_state = TPG_STATE_ACTIVE; @@ -344,6 +345,10 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) spin_unlock(&tiqn->tiqn_tpg_lock); return 0; + +err: + spin_unlock(&tpg->tpg_state_lock); + return ret; } int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) @@ -558,7 +563,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) if ((authentication != 1) && (authentication != 0)) { pr_err("Illegal value for authentication parameter:" " %u, ignoring request.\n", authentication); - return -1; + return -EINVAL; } memset(buf1, 0, sizeof(buf1)); @@ -593,7 +598,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) } else { snprintf(buf1, sizeof(buf1), "%s", param->value); none = strstr(buf1, NONE); - if ((none)) + if (none) goto out; strncat(buf1, ",", strlen(",")); strncat(buf1, NONE, strlen(NONE)); diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 38dfac2b0a1..5491c632a15 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -211,12 +211,11 @@ static void tcm_loop_submission_work(struct work_struct *work) /* * Because some userspace code via scsi-generic do not memset their * associated read buffers, go ahead and do that here for type - * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently - * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB - * by target core in target_setup_cmd_from_cdb() -> - * transport_generic_cmd_sequencer(). + * non-data CDBs. Also note that this is currently guaranteed to be a + * single SGL for this case by target core in + * target_setup_cmd_from_cdb() -> transport_generic_cmd_sequencer(). */ - if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && + if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && se_cmd->data_direction == DMA_FROM_DEVICE) { struct scatterlist *sg = scsi_sglist(sc); unsigned char *buf = kmap(sg_page(sg)) + sg->offset; @@ -779,7 +778,7 @@ static int tcm_loop_write_pending(struct se_cmd *se_cmd) * We now tell TCM to add this WRITE CDB directly into the TCM storage * object execution queue. */ - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); return 0; } diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 7e6136e2ce8..39ddba584b3 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1219,28 +1219,14 @@ static void sbp_handle_command(struct sbp_target_request *req) ret = sbp_fetch_command(req); if (ret) { pr_debug("sbp_handle_command: fetch command failed: %d\n", ret); - req->status.status |= cpu_to_be32( - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | - STATUS_BLOCK_DEAD(0) | - STATUS_BLOCK_LEN(1) | - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); - sbp_send_status(req); - sbp_free_request(req); - return; + goto err; } ret = sbp_fetch_page_table(req); if (ret) { pr_debug("sbp_handle_command: fetch page table failed: %d\n", ret); - req->status.status |= cpu_to_be32( - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | - STATUS_BLOCK_DEAD(0) | - STATUS_BLOCK_LEN(1) | - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); - sbp_send_status(req); - sbp_free_request(req); - return; + goto err; } unpacked_lun = req->login->lun->unpacked_lun; @@ -1249,9 +1235,21 @@ static void sbp_handle_command(struct sbp_target_request *req) pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", req->orb_pointer, unpacked_lun, data_length, data_dir); - target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, - req->sense_buf, unpacked_lun, data_length, - MSG_SIMPLE_TAG, data_dir, 0); + if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, + req->sense_buf, unpacked_lun, data_length, + MSG_SIMPLE_TAG, data_dir, 0)) + goto err; + + return; + +err: + req->status.status |= cpu_to_be32( + STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | + STATUS_BLOCK_DEAD(0) | + STATUS_BLOCK_LEN(1) | + STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); + sbp_send_status(req); + sbp_free_request(req); } /* @@ -1784,8 +1782,7 @@ static int sbp_write_pending(struct se_cmd *se_cmd) return ret; } - transport_generic_process_write(se_cmd); - + target_execute_cmd(se_cmd); return 0; } diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 5ad972856a8..cf2c66f3c11 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -300,8 +300,8 @@ int core_free_device_list_for_node( lun = deve->se_lun; spin_unlock_irq(&nacl->device_list_lock); - core_update_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); spin_lock_irq(&nacl->device_list_lock); } spin_unlock_irq(&nacl->device_list_lock); @@ -342,72 +342,46 @@ void core_update_device_list_access( spin_unlock_irq(&nacl->device_list_lock); } -/* core_update_device_list_for_node(): +/* core_enable_device_list_for_node(): * * */ -int core_update_device_list_for_node( +int core_enable_device_list_for_node( struct se_lun *lun, struct se_lun_acl *lun_acl, u32 mapped_lun, u32 lun_access, struct se_node_acl *nacl, - struct se_portal_group *tpg, - int enable) + struct se_portal_group *tpg) { struct se_port *port = lun->lun_sep; - struct se_dev_entry *deve = nacl->device_list[mapped_lun]; - int trans = 0; - /* - * If the MappedLUN entry is being disabled, the entry in - * port->sep_alua_list must be removed now before clearing the - * struct se_dev_entry pointers below as logic in - * core_alua_do_transition_tg_pt() depends on these being present. - */ - if (!enable) { - /* - * deve->se_lun_acl will be NULL for demo-mode created LUNs - * that have not been explicitly concerted to MappedLUNs -> - * struct se_lun_acl, but we remove deve->alua_port_list from - * port->sep_alua_list. This also means that active UAs and - * NodeACL context specific PR metadata for demo-mode - * MappedLUN *deve will be released below.. - */ - spin_lock_bh(&port->sep_alua_lock); - list_del(&deve->alua_port_list); - spin_unlock_bh(&port->sep_alua_lock); - } + struct se_dev_entry *deve; spin_lock_irq(&nacl->device_list_lock); - if (enable) { - /* - * Check if the call is handling demo mode -> explict LUN ACL - * transition. This transition must be for the same struct se_lun - * + mapped_lun that was setup in demo mode.. - */ - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - if (deve->se_lun_acl != NULL) { - pr_err("struct se_dev_entry->se_lun_acl" - " already set for demo mode -> explict" - " LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); - return -EINVAL; - } - if (deve->se_lun != lun) { - pr_err("struct se_dev_entry->se_lun does" - " match passed struct se_lun for demo mode" - " -> explict LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); - return -EINVAL; - } - deve->se_lun_acl = lun_acl; - trans = 1; - } else { - deve->se_lun = lun; - deve->se_lun_acl = lun_acl; - deve->mapped_lun = mapped_lun; - deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS; + + deve = nacl->device_list[mapped_lun]; + + /* + * Check if the call is handling demo mode -> explict LUN ACL + * transition. This transition must be for the same struct se_lun + * + mapped_lun that was setup in demo mode.. + */ + if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { + if (deve->se_lun_acl != NULL) { + pr_err("struct se_dev_entry->se_lun_acl" + " already set for demo mode -> explict" + " LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); + return -EINVAL; } + if (deve->se_lun != lun) { + pr_err("struct se_dev_entry->se_lun does" + " match passed struct se_lun for demo mode" + " -> explict LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); + return -EINVAL; + } + deve->se_lun_acl = lun_acl; if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; @@ -417,27 +391,72 @@ int core_update_device_list_for_node( deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; } - if (trans) { - spin_unlock_irq(&nacl->device_list_lock); - return 0; - } - deve->creation_time = get_jiffies_64(); - deve->attach_count++; spin_unlock_irq(&nacl->device_list_lock); + return 0; + } - spin_lock_bh(&port->sep_alua_lock); - list_add_tail(&deve->alua_port_list, &port->sep_alua_list); - spin_unlock_bh(&port->sep_alua_lock); + deve->se_lun = lun; + deve->se_lun_acl = lun_acl; + deve->mapped_lun = mapped_lun; + deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS; - return 0; + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + } else { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; } + + deve->creation_time = get_jiffies_64(); + deve->attach_count++; + spin_unlock_irq(&nacl->device_list_lock); + + spin_lock_bh(&port->sep_alua_lock); + list_add_tail(&deve->alua_port_list, &port->sep_alua_list); + spin_unlock_bh(&port->sep_alua_lock); + + return 0; +} + +/* core_disable_device_list_for_node(): + * + * + */ +int core_disable_device_list_for_node( + struct se_lun *lun, + struct se_lun_acl *lun_acl, + u32 mapped_lun, + u32 lun_access, + struct se_node_acl *nacl, + struct se_portal_group *tpg) +{ + struct se_port *port = lun->lun_sep; + struct se_dev_entry *deve = nacl->device_list[mapped_lun]; + + /* + * If the MappedLUN entry is being disabled, the entry in + * port->sep_alua_list must be removed now before clearing the + * struct se_dev_entry pointers below as logic in + * core_alua_do_transition_tg_pt() depends on these being present. + * + * deve->se_lun_acl will be NULL for demo-mode created LUNs + * that have not been explicitly converted to MappedLUNs -> + * struct se_lun_acl, but we remove deve->alua_port_list from + * port->sep_alua_list. This also means that active UAs and + * NodeACL context specific PR metadata for demo-mode + * MappedLUN *deve will be released below.. + */ + spin_lock_bh(&port->sep_alua_lock); + list_del(&deve->alua_port_list); + spin_unlock_bh(&port->sep_alua_lock); /* * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE * PR operation to complete. */ - spin_unlock_irq(&nacl->device_list_lock); while (atomic_read(&deve->pr_ref_count) != 0) cpu_relax(); + spin_lock_irq(&nacl->device_list_lock); /* * Disable struct se_dev_entry LUN ACL mapping @@ -475,9 +494,9 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) continue; spin_unlock_irq(&nacl->device_list_lock); - core_update_device_list_for_node(lun, NULL, + core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS, - nacl, tpg, 0); + nacl, tpg); spin_lock_irq(&nacl->device_list_lock); } @@ -715,7 +734,7 @@ void se_release_device_for_hba(struct se_device *dev) se_dev_stop(dev); if (dev->dev_ptr) { - kthread_stop(dev->process_thread); + destroy_workqueue(dev->tmr_wq); if (dev->transport->free_device) dev->transport->free_device(dev->dev_ptr); } @@ -822,7 +841,7 @@ int se_dev_check_shutdown(struct se_device *dev) return ret; } -u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) +static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) { u32 tmp, aligned_max_sectors; /* @@ -1273,7 +1292,6 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size) struct se_lun *core_dev_add_lun( struct se_portal_group *tpg, - struct se_hba *hba, struct se_device *dev, u32 lun) { @@ -1298,7 +1316,7 @@ struct se_lun *core_dev_add_lun( pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun_p->unpacked_lun, - tpg->se_tpg_tfo->get_fabric_name(), hba->hba_id); + tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id); /* * Update LUN maps for dynamically added initiators when * generate_node_acl is enabled. @@ -1470,8 +1488,8 @@ int core_dev_add_initiator_node_lun_acl( lacl->se_lun = lun; - if (core_update_device_list_for_node(lun, lacl, lacl->mapped_lun, - lun_access, nacl, tpg, 1) < 0) + if (core_enable_device_list_for_node(lun, lacl, lacl->mapped_lun, + lun_access, nacl, tpg) < 0) return -EINVAL; spin_lock(&lun->lun_acl_lock); @@ -1514,8 +1532,8 @@ int core_dev_del_initiator_node_lun_acl( smp_mb__after_atomic_dec(); spin_unlock(&lun->lun_acl_lock); - core_update_device_list_for_node(lun, NULL, lacl->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); lacl->se_lun = NULL; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 405cc98eaed..ea479e54f5f 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -764,8 +764,7 @@ static int target_fabric_port_link( goto out; } - lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev, - lun->unpacked_lun); + lun_p = core_dev_add_lun(se_tpg, dev, lun->unpacked_lun); if (IS_ERR(lun_p)) { pr_err("core_dev_add_lun() failed\n"); ret = PTR_ERR(lun_p); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 9f99d040490..9e2100551c7 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -331,7 +331,7 @@ static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl, return 1; } -static void fd_emulate_sync_cache(struct se_cmd *cmd) +static int fd_execute_sync_cache(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct fd_dev *fd_dev = dev->dev_ptr; @@ -365,7 +365,7 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd) pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret); if (immed) - return; + return 0; if (ret) { cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -373,11 +373,15 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd) } else { target_complete_cmd(cmd, SAM_STAT_GOOD); } + + return 0; } -static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +static int fd_execute_rw(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct se_device *dev = cmd->se_dev; int ret = 0; @@ -550,6 +554,16 @@ static sector_t fd_get_blocks(struct se_device *dev) return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size); } +static struct spc_ops fd_spc_ops = { + .execute_rw = fd_execute_rw, + .execute_sync_cache = fd_execute_sync_cache, +}; + +static int fd_parse_cdb(struct se_cmd *cmd) +{ + return sbc_parse_cdb(cmd, &fd_spc_ops); +} + static struct se_subsystem_api fileio_template = { .name = "fileio", .owner = THIS_MODULE, @@ -561,8 +575,7 @@ static struct se_subsystem_api fileio_template = { .allocate_virtdevice = fd_allocate_virtdevice, .create_virtdevice = fd_create_virtdevice, .free_device = fd_free_device, - .execute_cmd = fd_execute_cmd, - .do_sync_cache = fd_emulate_sync_cache, + .parse_cdb = fd_parse_cdb, .check_configfs_dev_params = fd_check_configfs_dev_params, .set_configfs_dev_params = fd_set_configfs_dev_params, .show_configfs_dev_params = fd_show_configfs_dev_params, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index fd47950727b..76db75e836e 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -40,6 +40,7 @@ #include <linux/module.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> +#include <asm/unaligned.h> #include <target/target_core_base.h> #include <target/target_core_backend.h> @@ -96,6 +97,7 @@ static struct se_device *iblock_create_virtdevice( struct request_queue *q; struct queue_limits *limits; u32 dev_flags = 0; + fmode_t mode; int ret = -EINVAL; if (!ib_dev) { @@ -117,8 +119,11 @@ static struct se_device *iblock_create_virtdevice( pr_debug( "IBLOCK: Claiming struct block_device: %s\n", ib_dev->ibd_udev_path); - bd = blkdev_get_by_path(ib_dev->ibd_udev_path, - FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); + mode = FMODE_READ|FMODE_EXCL; + if (!ib_dev->ibd_readonly) + mode |= FMODE_WRITE; + + bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev); if (IS_ERR(bd)) { ret = PTR_ERR(bd); goto failed; @@ -292,7 +297,7 @@ static void iblock_end_io_flush(struct bio *bio, int err) * Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must * always flush the whole cache. */ -static void iblock_emulate_sync_cache(struct se_cmd *cmd) +static int iblock_execute_sync_cache(struct se_cmd *cmd) { struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; int immed = (cmd->t_task_cdb[1] & 0x2); @@ -311,23 +316,98 @@ static void iblock_emulate_sync_cache(struct se_cmd *cmd) if (!immed) bio->bi_private = cmd; submit_bio(WRITE_FLUSH, bio); + return 0; } -static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) +static int iblock_execute_unmap(struct se_cmd *cmd) { + struct se_device *dev = cmd->se_dev; struct iblock_dev *ibd = dev->dev_ptr; - struct block_device *bd = ibd->ibd_bd; - int barrier = 0; + unsigned char *buf, *ptr = NULL; + sector_t lba; + int size = cmd->data_length; + u32 range; + int ret = 0; + int dl, bd_dl; + + buf = transport_kmap_data_sg(cmd); + + dl = get_unaligned_be16(&buf[0]); + bd_dl = get_unaligned_be16(&buf[2]); + + size = min(size - 8, bd_dl); + if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; + goto err; + } + + /* First UNMAP block descriptor starts at 8 byte offset */ + ptr = &buf[8]; + pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" + " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); + + while (size >= 16) { + lba = get_unaligned_be64(&ptr[0]); + range = get_unaligned_be32(&ptr[8]); + pr_debug("UNMAP: Using lba: %llu and range: %u\n", + (unsigned long long)lba, range); + + if (range > dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count) { + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; + goto err; + } + + if (lba + range > dev->transport->get_blocks(dev) + 1) { + cmd->scsi_sense_reason = TCM_ADDRESS_OUT_OF_RANGE; + ret = -EINVAL; + goto err; + } - return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier); + ret = blkdev_issue_discard(ibd->ibd_bd, lba, range, + GFP_KERNEL, 0); + if (ret < 0) { + pr_err("blkdev_issue_discard() failed: %d\n", + ret); + goto err; + } + + ptr += 16; + size -= 16; + } + +err: + transport_kunmap_data_sg(cmd); + if (!ret) + target_complete_cmd(cmd, GOOD); + return ret; +} + +static int iblock_execute_write_same(struct se_cmd *cmd) +{ + struct iblock_dev *ibd = cmd->se_dev->dev_ptr; + int ret; + + ret = blkdev_issue_discard(ibd->ibd_bd, cmd->t_task_lba, + spc_get_write_same_sectors(cmd), GFP_KERNEL, + 0); + if (ret < 0) { + pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); + return ret; + } + + target_complete_cmd(cmd, GOOD); + return 0; } enum { - Opt_udev_path, Opt_force, Opt_err + Opt_udev_path, Opt_readonly, Opt_force, Opt_err }; static match_table_t tokens = { {Opt_udev_path, "udev_path=%s"}, + {Opt_readonly, "readonly=%d"}, {Opt_force, "force=%d"}, {Opt_err, NULL} }; @@ -340,6 +420,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, token; + unsigned long tmp_readonly; opts = kstrdup(page, GFP_KERNEL); if (!opts) @@ -372,6 +453,22 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, ib_dev->ibd_udev_path); ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; break; + case Opt_readonly: + arg_p = match_strdup(&args[0]); + if (!arg_p) { + ret = -ENOMEM; + break; + } + ret = strict_strtoul(arg_p, 0, &tmp_readonly); + kfree(arg_p); + if (ret < 0) { + pr_err("strict_strtoul() failed for" + " readonly=\n"); + goto out; + } + ib_dev->ibd_readonly = tmp_readonly; + pr_debug("IBLOCK: readonly: %d\n", ib_dev->ibd_readonly); + break; case Opt_force: break; default: @@ -411,11 +508,10 @@ static ssize_t iblock_show_configfs_dev_params( if (bd) bl += sprintf(b + bl, "iBlock device: %s", bdevname(bd, buf)); - if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) { - bl += sprintf(b + bl, " UDEV PATH: %s\n", + if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) + bl += sprintf(b + bl, " UDEV PATH: %s", ibd->ibd_udev_path); - } else - bl += sprintf(b + bl, "\n"); + bl += sprintf(b + bl, " readonly: %d\n", ibd->ibd_readonly); bl += sprintf(b + bl, " "); if (bd) { @@ -493,9 +589,11 @@ static void iblock_submit_bios(struct bio_list *list, int rw) blk_finish_plug(&plug); } -static int iblock_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +static int iblock_execute_rw(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct se_device *dev = cmd->se_dev; struct iblock_req *ibr; struct bio *bio; @@ -642,6 +740,18 @@ static void iblock_bio_done(struct bio *bio, int err) iblock_complete_cmd(cmd); } +static struct spc_ops iblock_spc_ops = { + .execute_rw = iblock_execute_rw, + .execute_sync_cache = iblock_execute_sync_cache, + .execute_write_same = iblock_execute_write_same, + .execute_unmap = iblock_execute_unmap, +}; + +static int iblock_parse_cdb(struct se_cmd *cmd) +{ + return sbc_parse_cdb(cmd, &iblock_spc_ops); +} + static struct se_subsystem_api iblock_template = { .name = "iblock", .owner = THIS_MODULE, @@ -653,9 +763,7 @@ static struct se_subsystem_api iblock_template = { .allocate_virtdevice = iblock_allocate_virtdevice, .create_virtdevice = iblock_create_virtdevice, .free_device = iblock_free_device, - .execute_cmd = iblock_execute_cmd, - .do_discard = iblock_do_discard, - .do_sync_cache = iblock_emulate_sync_cache, + .parse_cdb = iblock_parse_cdb, .check_configfs_dev_params = iblock_check_configfs_dev_params, .set_configfs_dev_params = iblock_set_configfs_dev_params, .show_configfs_dev_params = iblock_show_configfs_dev_params, diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index 66cf7b9e205..533627ae79e 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -18,6 +18,7 @@ struct iblock_dev { u32 ibd_flags; struct bio_set *ibd_bio_set; struct block_device *ibd_bd; + bool ibd_readonly; } ____cacheline_aligned; #endif /* TARGET_CORE_IBLOCK_H */ diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 165e8242968..0fd428225d1 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -4,25 +4,16 @@ /* target_core_alua.c */ extern struct t10_alua_lu_gp *default_lu_gp; -/* target_core_cdb.c */ -int target_emulate_inquiry(struct se_cmd *cmd); -int target_emulate_readcapacity(struct se_cmd *cmd); -int target_emulate_readcapacity_16(struct se_cmd *cmd); -int target_emulate_modesense(struct se_cmd *cmd); -int target_emulate_request_sense(struct se_cmd *cmd); -int target_emulate_unmap(struct se_cmd *cmd); -int target_emulate_write_same(struct se_cmd *cmd); -int target_emulate_synchronize_cache(struct se_cmd *cmd); -int target_emulate_noop(struct se_cmd *cmd); - /* target_core_device.c */ struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); int core_free_device_list_for_node(struct se_node_acl *, struct se_portal_group *); void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *); void core_update_device_list_access(u32, u32, struct se_node_acl *); -int core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *, - u32, u32, struct se_node_acl *, struct se_portal_group *, int); +int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, + u32, u32, struct se_node_acl *, struct se_portal_group *); +int core_disable_device_list_for_node(struct se_lun *, struct se_lun_acl *, + u32, u32, struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); @@ -56,8 +47,7 @@ int se_dev_set_max_sectors(struct se_device *, u32); int se_dev_set_fabric_max_sectors(struct se_device *, u32); int se_dev_set_optimal_sectors(struct se_device *, u32); int se_dev_set_block_size(struct se_device *, u32); -struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *, - struct se_device *, u32); +struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u32); int core_dev_del_lun(struct se_portal_group *, u32); struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, @@ -104,7 +94,6 @@ void release_se_kmem_caches(void); u32 scsi_get_new_index(scsi_index_t); void transport_subsystem_check_init(void); void transport_cmd_finish_abort(struct se_cmd *, int); -void __target_remove_from_execute_list(struct se_cmd *); unsigned char *transport_dump_cmd_direction(struct se_cmd *); void transport_dump_dev_state(struct se_device *, char *, int *); void transport_dump_dev_info(struct se_device *, struct se_lun *, @@ -116,6 +105,7 @@ int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags); int transport_clear_lun_from_sessions(struct se_lun *); void transport_send_task_abort(struct se_cmd *); +int target_cmd_size_check(struct se_cmd *cmd, unsigned int size); /* target_core_stat.c */ void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 85564998500..1e946502c37 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -507,7 +507,7 @@ static int core_scsi3_pr_seq_non_holder( * Check if write exclusive initiator ports *NOT* holding the * WRITE_EXCLUSIVE_* reservation. */ - if ((we) && !(registered_nexus)) { + if (we && !registered_nexus) { if (cmd->data_direction == DMA_TO_DEVICE) { /* * Conflict for write exclusive @@ -2031,7 +2031,7 @@ static int __core_scsi3_write_aptpl_to_file( if (IS_ERR(file) || !file || !file->f_dentry) { pr_err("filp_open(%s) for APTPL metadata" " failed\n", path); - return (PTR_ERR(file) < 0 ? PTR_ERR(file) : -ENOENT); + return IS_ERR(file) ? PTR_ERR(file) : -ENOENT; } iov[0].iov_base = &buf[0]; @@ -2486,7 +2486,7 @@ static int core_scsi3_pro_reserve( */ spin_lock(&dev->dev_reservation_lock); pr_res_holder = dev->dev_pr_res_holder; - if ((pr_res_holder)) { + if (pr_res_holder) { /* * From spc4r17 Section 5.7.9: Reserving: * @@ -3818,7 +3818,7 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd) " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = EINVAL; + ret = -EINVAL; goto out; } @@ -3828,7 +3828,8 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd) */ if (!cmd->se_sess) { cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + ret = -EINVAL; + goto out; } if (cmd->data_length < 24) { @@ -4029,7 +4030,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) spin_lock(&se_dev->dev_reservation_lock); pr_reg = se_dev->dev_pr_res_holder; - if ((pr_reg)) { + if (pr_reg) { /* * Set the hardcoded Additional Length */ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 4ce2cf642fc..6e32ff6f2fa 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -35,8 +35,10 @@ #include <linux/spinlock.h> #include <linux/genhd.h> #include <linux/cdrom.h> -#include <linux/file.h> +#include <linux/ratelimit.h> #include <linux/module.h> +#include <asm/unaligned.h> + #include <scsi/scsi.h> #include <scsi/scsi_device.h> #include <scsi/scsi_cmnd.h> @@ -46,12 +48,14 @@ #include <target/target_core_base.h> #include <target/target_core_backend.h> +#include "target_core_alua.h" #include "target_core_pscsi.h" #define ISPRINT(a) ((a >= ' ') && (a <= '~')) static struct se_subsystem_api pscsi_template; +static int pscsi_execute_cmd(struct se_cmd *cmd); static void pscsi_req_done(struct request *, int); /* pscsi_attach_hba(): @@ -1019,9 +1023,79 @@ fail: return -ENOMEM; } -static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +/* + * Clear a lun set in the cdb if the initiator talking to use spoke + * and old standards version, as we can't assume the underlying device + * won't choke up on it. + */ +static inline void pscsi_clear_cdb_lun(unsigned char *cdb) +{ + switch (cdb[0]) { + case READ_10: /* SBC - RDProtect */ + case READ_12: /* SBC - RDProtect */ + case READ_16: /* SBC - RDProtect */ + case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ + case VERIFY: /* SBC - VRProtect */ + case VERIFY_16: /* SBC - VRProtect */ + case WRITE_VERIFY: /* SBC - VRProtect */ + case WRITE_VERIFY_12: /* SBC - VRProtect */ + case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ + break; + default: + cdb[1] &= 0x1f; /* clear logical unit number */ + break; + } +} + +static int pscsi_parse_cdb(struct se_cmd *cmd) +{ + unsigned char *cdb = cmd->t_task_cdb; + unsigned int dummy_size; + int ret; + + if (cmd->se_cmd_flags & SCF_BIDI) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -EINVAL; + } + + pscsi_clear_cdb_lun(cdb); + + /* + * For REPORT LUNS we always need to emulate the response, for everything + * else the default for pSCSI is to pass the command to the underlying + * LLD / physical hardware. + */ + switch (cdb[0]) { + case REPORT_LUNS: + ret = spc_parse_cdb(cmd, &dummy_size); + if (ret) + return ret; + break; + case READ_6: + case READ_10: + case READ_12: + case READ_16: + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + case WRITE_VERIFY: + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + /* FALLTHROUGH*/ + default: + cmd->execute_cmd = pscsi_execute_cmd; + break; + } + + return 0; +} + +static int pscsi_execute_cmd(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; struct pscsi_plugin_task *pt; struct request *req; @@ -1042,7 +1116,7 @@ static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, memcpy(pt->pscsi_cdb, cmd->t_task_cdb, scsi_command_size(cmd->t_task_cdb)); - if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) { + if (!sgl) { req = blk_get_request(pdv->pdv_sd->request_queue, (data_direction == DMA_TO_DEVICE), GFP_KERNEL); @@ -1188,7 +1262,7 @@ static struct se_subsystem_api pscsi_template = { .create_virtdevice = pscsi_create_virtdevice, .free_device = pscsi_free_device, .transport_complete = pscsi_transport_complete, - .execute_cmd = pscsi_execute_cmd, + .parse_cdb = pscsi_parse_cdb, .check_configfs_dev_params = pscsi_check_configfs_dev_params, .set_configfs_dev_params = pscsi_set_configfs_dev_params, .show_configfs_dev_params = pscsi_show_configfs_dev_params, diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d0ceb873c0e..d00bbe33ff8 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -284,9 +284,11 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) return NULL; } -static int rd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +static int rd_execute_rw(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct se_device *se_dev = cmd->se_dev; struct rd_dev *dev = se_dev->dev_ptr; struct rd_dev_sg_table *table; @@ -460,6 +462,15 @@ static sector_t rd_get_blocks(struct se_device *dev) return blocks_long; } +static struct spc_ops rd_spc_ops = { + .execute_rw = rd_execute_rw, +}; + +static int rd_parse_cdb(struct se_cmd *cmd) +{ + return sbc_parse_cdb(cmd, &rd_spc_ops); +} + static struct se_subsystem_api rd_mcp_template = { .name = "rd_mcp", .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV, @@ -468,7 +479,7 @@ static struct se_subsystem_api rd_mcp_template = { .allocate_virtdevice = rd_allocate_virtdevice, .create_virtdevice = rd_create_virtdevice, .free_device = rd_free_device, - .execute_cmd = rd_execute_cmd, + .parse_cdb = rd_parse_cdb, .check_configfs_dev_params = rd_check_configfs_dev_params, .set_configfs_dev_params = rd_set_configfs_dev_params, .show_configfs_dev_params = rd_show_configfs_dev_params, diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c new file mode 100644 index 00000000000..a9dd9469e3b --- /dev/null +++ b/drivers/target/target_core_sbc.c @@ -0,0 +1,581 @@ +/* + * SCSI Block Commands (SBC) parsing and emulation. + * + * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger <nab@kernel.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/ratelimit.h> +#include <asm/unaligned.h> +#include <scsi/scsi.h> + +#include <target/target_core_base.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> + +#include "target_core_internal.h" +#include "target_core_ua.h" + + +static int sbc_emulate_readcapacity(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf; + unsigned long long blocks_long = dev->transport->get_blocks(dev); + u32 blocks; + + if (blocks_long >= 0x00000000ffffffff) + blocks = 0xffffffff; + else + blocks = (u32)blocks_long; + + buf = transport_kmap_data_sg(cmd); + + buf[0] = (blocks >> 24) & 0xff; + buf[1] = (blocks >> 16) & 0xff; + buf[2] = (blocks >> 8) & 0xff; + buf[3] = blocks & 0xff; + buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; + buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; + buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; + buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; + + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + +static int sbc_emulate_readcapacity_16(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf; + unsigned long long blocks = dev->transport->get_blocks(dev); + + buf = transport_kmap_data_sg(cmd); + + buf[0] = (blocks >> 56) & 0xff; + buf[1] = (blocks >> 48) & 0xff; + buf[2] = (blocks >> 40) & 0xff; + buf[3] = (blocks >> 32) & 0xff; + buf[4] = (blocks >> 24) & 0xff; + buf[5] = (blocks >> 16) & 0xff; + buf[6] = (blocks >> 8) & 0xff; + buf[7] = blocks & 0xff; + buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; + buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; + buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; + buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; + /* + * Set Thin Provisioning Enable bit following sbc3r22 in section + * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled. + */ + if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) + buf[14] = 0x80; + + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + +int spc_get_write_same_sectors(struct se_cmd *cmd) +{ + u32 num_blocks; + + if (cmd->t_task_cdb[0] == WRITE_SAME) + num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); + else if (cmd->t_task_cdb[0] == WRITE_SAME_16) + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); + else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */ + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); + + /* + * Use the explicit range when non zero is supplied, otherwise calculate + * the remaining range based on ->get_blocks() - starting LBA. + */ + if (num_blocks) + return num_blocks; + + return cmd->se_dev->transport->get_blocks(cmd->se_dev) - + cmd->t_task_lba + 1; +} +EXPORT_SYMBOL(spc_get_write_same_sectors); + +static int sbc_emulate_verify(struct se_cmd *cmd) +{ + target_complete_cmd(cmd, GOOD); + return 0; +} + +static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) +{ + return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors; +} + +static int sbc_check_valid_sectors(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + unsigned long long end_lba; + u32 sectors; + + sectors = cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size; + end_lba = dev->transport->get_blocks(dev) + 1; + + if (cmd->t_task_lba + sectors > end_lba) { + pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n", + cmd->t_task_lba, sectors, end_lba); + return -EINVAL; + } + + return 0; +} + +static inline u32 transport_get_sectors_6(unsigned char *cdb) +{ + /* + * Use 8-bit sector value. SBC-3 says: + * + * A TRANSFER LENGTH field set to zero specifies that 256 + * logical blocks shall be written. Any other value + * specifies the number of logical blocks that shall be + * written. + */ + return cdb[4] ? : 256; +} + +static inline u32 transport_get_sectors_10(unsigned char *cdb) +{ + return (u32)(cdb[7] << 8) + cdb[8]; +} + +static inline u32 transport_get_sectors_12(unsigned char *cdb) +{ + return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; +} + +static inline u32 transport_get_sectors_16(unsigned char *cdb) +{ + return (u32)(cdb[10] << 24) + (cdb[11] << 16) + + (cdb[12] << 8) + cdb[13]; +} + +/* + * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants + */ +static inline u32 transport_get_sectors_32(unsigned char *cdb) +{ + return (u32)(cdb[28] << 24) + (cdb[29] << 16) + + (cdb[30] << 8) + cdb[31]; + +} + +static inline u32 transport_lba_21(unsigned char *cdb) +{ + return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; +} + +static inline u32 transport_lba_32(unsigned char *cdb) +{ + return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; +} + +static inline unsigned long long transport_lba_64(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +/* + * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs + */ +static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; + __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +static int sbc_write_same_supported(struct se_device *dev, + unsigned char *flags) +{ + if ((flags[0] & 0x04) || (flags[0] & 0x02)) { + pr_err("WRITE_SAME PBDATA and LBDATA" + " bits not supported for Block Discard" + " Emulation\n"); + return -ENOSYS; + } + + /* + * Currently for the emulated case we only accept + * tpws with the UNMAP=1 bit set. + */ + if (!(flags[0] & 0x08)) { + pr_err("WRITE_SAME w/o UNMAP bit not" + " supported for Block Discard Emulation\n"); + return -ENOSYS; + } + + return 0; +} + +static void xdreadwrite_callback(struct se_cmd *cmd) +{ + unsigned char *buf, *addr; + struct scatterlist *sg; + unsigned int offset; + int i; + int count; + /* + * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command + * + * 1) read the specified logical block(s); + * 2) transfer logical blocks from the data-out buffer; + * 3) XOR the logical blocks transferred from the data-out buffer with + * the logical blocks read, storing the resulting XOR data in a buffer; + * 4) if the DISABLE WRITE bit is set to zero, then write the logical + * blocks transferred from the data-out buffer; and + * 5) transfer the resulting XOR data to the data-in buffer. + */ + buf = kmalloc(cmd->data_length, GFP_KERNEL); + if (!buf) { + pr_err("Unable to allocate xor_callback buf\n"); + return; + } + /* + * Copy the scatterlist WRITE buffer located at cmd->t_data_sg + * into the locally allocated *buf + */ + sg_copy_to_buffer(cmd->t_data_sg, + cmd->t_data_nents, + buf, + cmd->data_length); + + /* + * Now perform the XOR against the BIDI read memory located at + * cmd->t_mem_bidi_list + */ + + offset = 0; + for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { + addr = kmap_atomic(sg_page(sg)); + if (!addr) + goto out; + + for (i = 0; i < sg->length; i++) + *(addr + sg->offset + i) ^= *(buf + offset + i); + + offset += sg->length; + kunmap_atomic(addr); + } + +out: + kfree(buf); +} + +int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) +{ + struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + struct se_device *dev = cmd->se_dev; + unsigned char *cdb = cmd->t_task_cdb; + unsigned int size; + u32 sectors = 0; + int ret; + + switch (cdb[0]) { + case READ_6: + sectors = transport_get_sectors_6(cdb); + cmd->t_task_lba = transport_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case READ_10: + sectors = transport_get_sectors_10(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case READ_12: + sectors = transport_get_sectors_12(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case READ_16: + sectors = transport_get_sectors_16(cdb); + cmd->t_task_lba = transport_lba_64(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case WRITE_6: + sectors = transport_get_sectors_6(cdb); + cmd->t_task_lba = transport_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case WRITE_10: + case WRITE_VERIFY: + sectors = transport_get_sectors_10(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case WRITE_12: + sectors = transport_get_sectors_12(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case WRITE_16: + sectors = transport_get_sectors_16(cdb); + cmd->t_task_lba = transport_lba_64(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; + break; + case XDWRITEREAD_10: + if ((cmd->data_direction != DMA_TO_DEVICE) || + !(cmd->se_cmd_flags & SCF_BIDI)) + goto out_invalid_cdb_field; + sectors = transport_get_sectors_10(cdb); + + cmd->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + + /* + * Setup BIDI XOR callback to be run after I/O completion. + */ + cmd->execute_cmd = ops->execute_rw; + cmd->transport_complete_callback = &xdreadwrite_callback; + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + break; + case VARIABLE_LENGTH_CMD: + { + u16 service_action = get_unaligned_be16(&cdb[8]); + switch (service_action) { + case XDWRITEREAD_32: + sectors = transport_get_sectors_32(cdb); + + /* + * Use WRITE_32 and READ_32 opcodes for the emulated + * XDWRITE_READ_32 logic. + */ + cmd->t_task_lba = transport_lba_64_ext(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + + /* + * Setup BIDI XOR callback to be run during after I/O + * completion. + */ + cmd->execute_cmd = ops->execute_rw; + cmd->transport_complete_callback = &xdreadwrite_callback; + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + break; + case WRITE_SAME_32: + if (!ops->execute_write_same) + goto out_unsupported_cdb; + + sectors = transport_get_sectors_32(cdb); + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" + " supported\n"); + goto out_invalid_cdb_field; + } + + size = sbc_get_size(cmd, 1); + cmd->t_task_lba = get_unaligned_be64(&cdb[12]); + + if (sbc_write_same_supported(dev, &cdb[10]) < 0) + goto out_unsupported_cdb; + cmd->execute_cmd = ops->execute_write_same; + break; + default: + pr_err("VARIABLE_LENGTH_CMD service action" + " 0x%04x not supported\n", service_action); + goto out_unsupported_cdb; + } + break; + } + case READ_CAPACITY: + size = READ_CAP_LEN; + cmd->execute_cmd = sbc_emulate_readcapacity; + break; + case SERVICE_ACTION_IN: + switch (cmd->t_task_cdb[1] & 0x1f) { + case SAI_READ_CAPACITY_16: + cmd->execute_cmd = sbc_emulate_readcapacity_16; + break; + default: + pr_err("Unsupported SA: 0x%02x\n", + cmd->t_task_cdb[1] & 0x1f); + goto out_invalid_cdb_field; + } + size = (cdb[10] << 24) | (cdb[11] << 16) | + (cdb[12] << 8) | cdb[13]; + break; + case SYNCHRONIZE_CACHE: + case SYNCHRONIZE_CACHE_16: + if (!ops->execute_sync_cache) + goto out_unsupported_cdb; + + /* + * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE + */ + if (cdb[0] == SYNCHRONIZE_CACHE) { + sectors = transport_get_sectors_10(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + } else { + sectors = transport_get_sectors_16(cdb); + cmd->t_task_lba = transport_lba_64(cdb); + } + + size = sbc_get_size(cmd, sectors); + + /* + * Check to ensure that LBA + Range does not exceed past end of + * device for IBLOCK and FILEIO ->do_sync_cache() backend calls + */ + if (cmd->t_task_lba || sectors) { + if (sbc_check_valid_sectors(cmd) < 0) + goto out_invalid_cdb_field; + } + cmd->execute_cmd = ops->execute_sync_cache; + break; + case UNMAP: + if (!ops->execute_unmap) + goto out_unsupported_cdb; + + size = get_unaligned_be16(&cdb[7]); + cmd->execute_cmd = ops->execute_unmap; + break; + case WRITE_SAME_16: + if (!ops->execute_write_same) + goto out_unsupported_cdb; + + sectors = transport_get_sectors_16(cdb); + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); + goto out_invalid_cdb_field; + } + + size = sbc_get_size(cmd, 1); + cmd->t_task_lba = get_unaligned_be64(&cdb[2]); + + if (sbc_write_same_supported(dev, &cdb[1]) < 0) + goto out_unsupported_cdb; + cmd->execute_cmd = ops->execute_write_same; + break; + case WRITE_SAME: + if (!ops->execute_write_same) + goto out_unsupported_cdb; + + sectors = transport_get_sectors_10(cdb); + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); + goto out_invalid_cdb_field; + } + + size = sbc_get_size(cmd, 1); + cmd->t_task_lba = get_unaligned_be32(&cdb[2]); + + /* + * Follow sbcr26 with WRITE_SAME (10) and check for the existence + * of byte 1 bit 3 UNMAP instead of original reserved field + */ + if (sbc_write_same_supported(dev, &cdb[1]) < 0) + goto out_unsupported_cdb; + cmd->execute_cmd = ops->execute_write_same; + break; + case VERIFY: + size = 0; + cmd->execute_cmd = sbc_emulate_verify; + break; + default: + ret = spc_parse_cdb(cmd, &size); + if (ret) + return ret; + } + + /* reject any command that we don't have a handler for */ + if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->execute_cmd) + goto out_unsupported_cdb; + + if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { + unsigned long long end_lba; + + if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds fabric_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.fabric_max_sectors); + goto out_invalid_cdb_field; + } + if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds backend hw_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.hw_max_sectors); + goto out_invalid_cdb_field; + } + + end_lba = dev->transport->get_blocks(dev) + 1; + if (cmd->t_task_lba + sectors > end_lba) { + pr_err("cmd exceeds last lba %llu " + "(lba %llu, sectors %u)\n", + end_lba, cmd->t_task_lba, sectors); + goto out_invalid_cdb_field; + } + + size = sbc_get_size(cmd, sectors); + } + + ret = target_cmd_size_check(cmd, size); + if (ret < 0) + return ret; + + return 0; + +out_unsupported_cdb: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -EINVAL; +out_invalid_cdb_field: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; +} +EXPORT_SYMBOL(sbc_parse_cdb); diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_spc.c index 9888693a18f..4c861de538c 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_spc.c @@ -1,5 +1,5 @@ /* - * CDB emulation for non-READ/WRITE commands. + * SCSI Primary Commands (SPC) parsing and emulation. * * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. * Copyright (c) 2005, 2006, 2007 SBE, Inc. @@ -26,17 +26,21 @@ #include <linux/kernel.h> #include <linux/module.h> #include <asm/unaligned.h> + #include <scsi/scsi.h> +#include <scsi/scsi_tcq.h> #include <target/target_core_base.h> #include <target/target_core_backend.h> #include <target/target_core_fabric.h> #include "target_core_internal.h" +#include "target_core_alua.h" +#include "target_core_pr.h" #include "target_core_ua.h" -static void -target_fill_alua_data(struct se_port *port, unsigned char *buf) + +static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) { struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; @@ -65,8 +69,7 @@ target_fill_alua_data(struct se_port *port, unsigned char *buf) spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); } -static int -target_emulate_inquiry_std(struct se_cmd *cmd, char *buf) +static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) { struct se_lun *lun = cmd->se_lun; struct se_device *dev = cmd->se_dev; @@ -93,7 +96,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd, char *buf) * Enable SCCS and TPGS fields for Emulated ALUA */ if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) - target_fill_alua_data(lun->lun_sep, buf); + spc_fill_alua_data(lun->lun_sep, buf); buf[7] = 0x2; /* CmdQue=1 */ @@ -106,8 +109,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd, char *buf) } /* unit serial number */ -static int -target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) +static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; u16 len = 0; @@ -127,8 +129,8 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) return 0; } -static void -target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf) +static void spc_parse_naa_6h_vendor_specific(struct se_device *dev, + unsigned char *buf) { unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; int cnt; @@ -162,8 +164,7 @@ target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf) * Device identification VPD, for a complete list of * DESIGNATOR TYPEs see spc4r17 Table 459. */ -static int -target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) +static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; struct se_lun *lun = cmd->se_lun; @@ -220,7 +221,7 @@ target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) * VENDOR_SPECIFIC_IDENTIFIER and * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION */ - target_parse_naa_6h_vendor_specific(dev, &buf[off]); + spc_parse_naa_6h_vendor_specific(dev, &buf[off]); len = 20; off = (len + 4); @@ -414,8 +415,7 @@ check_scsi_name: } /* Extended INQUIRY Data VPD Page */ -static int -target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) +static int spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) { buf[3] = 0x3c; /* Set HEADSUP, ORDSUP, SIMPSUP */ @@ -428,15 +428,14 @@ target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) } /* Block Limits VPD page */ -static int -target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) +static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; u32 max_sectors; int have_tp = 0; /* - * Following sbc3r22 section 6.5.3 Block Limits VPD page, when + * Following spc3r22 section 6.5.3 Block Limits VPD page, when * emulate_tpu=1 or emulate_tpws=1 we will be expect a * different page length for Thin Provisioning. */ @@ -500,8 +499,7 @@ target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) } /* Block Device Characteristics VPD page */ -static int -target_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) +static int spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; @@ -513,13 +511,12 @@ target_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) } /* Thin Provisioning VPD */ -static int -target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) +static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; /* - * From sbc3r22 section 6.5.4 Thin Provisioning VPD page: + * From spc3r22 section 6.5.4 Thin Provisioning VPD page: * * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to * zero, then the page length shall be set to 0004h. If the DP bit @@ -564,25 +561,23 @@ target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) return 0; } -static int -target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); +static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); static struct { uint8_t page; int (*emulate)(struct se_cmd *, unsigned char *); } evpd_handlers[] = { - { .page = 0x00, .emulate = target_emulate_evpd_00 }, - { .page = 0x80, .emulate = target_emulate_evpd_80 }, - { .page = 0x83, .emulate = target_emulate_evpd_83 }, - { .page = 0x86, .emulate = target_emulate_evpd_86 }, - { .page = 0xb0, .emulate = target_emulate_evpd_b0 }, - { .page = 0xb1, .emulate = target_emulate_evpd_b1 }, - { .page = 0xb2, .emulate = target_emulate_evpd_b2 }, + { .page = 0x00, .emulate = spc_emulate_evpd_00 }, + { .page = 0x80, .emulate = spc_emulate_evpd_80 }, + { .page = 0x83, .emulate = spc_emulate_evpd_83 }, + { .page = 0x86, .emulate = spc_emulate_evpd_86 }, + { .page = 0xb0, .emulate = spc_emulate_evpd_b0 }, + { .page = 0xb1, .emulate = spc_emulate_evpd_b1 }, + { .page = 0xb2, .emulate = spc_emulate_evpd_b2 }, }; /* supported vital product data pages */ -static int -target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) +static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) { int p; @@ -601,7 +596,7 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) return 0; } -int target_emulate_inquiry(struct se_cmd *cmd) +static int spc_emulate_inquiry(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg; @@ -643,7 +638,7 @@ int target_emulate_inquiry(struct se_cmd *cmd) goto out; } - ret = target_emulate_inquiry_std(cmd, buf); + ret = spc_emulate_inquiry_std(cmd, buf); goto out; } @@ -671,70 +666,7 @@ out: return ret; } -int target_emulate_readcapacity(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned char *buf; - unsigned long long blocks_long = dev->transport->get_blocks(dev); - u32 blocks; - - if (blocks_long >= 0x00000000ffffffff) - blocks = 0xffffffff; - else - blocks = (u32)blocks_long; - - buf = transport_kmap_data_sg(cmd); - - buf[0] = (blocks >> 24) & 0xff; - buf[1] = (blocks >> 16) & 0xff; - buf[2] = (blocks >> 8) & 0xff; - buf[3] = blocks & 0xff; - buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; - buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; - buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; - buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; - - transport_kunmap_data_sg(cmd); - - target_complete_cmd(cmd, GOOD); - return 0; -} - -int target_emulate_readcapacity_16(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned char *buf; - unsigned long long blocks = dev->transport->get_blocks(dev); - - buf = transport_kmap_data_sg(cmd); - - buf[0] = (blocks >> 56) & 0xff; - buf[1] = (blocks >> 48) & 0xff; - buf[2] = (blocks >> 40) & 0xff; - buf[3] = (blocks >> 32) & 0xff; - buf[4] = (blocks >> 24) & 0xff; - buf[5] = (blocks >> 16) & 0xff; - buf[6] = (blocks >> 8) & 0xff; - buf[7] = blocks & 0xff; - buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; - buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; - buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; - buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; - /* - * Set Thin Provisioning Enable bit following sbc3r22 in section - * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled. - */ - if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) - buf[14] = 0x80; - - transport_kunmap_data_sg(cmd); - - target_complete_cmd(cmd, GOOD); - return 0; -} - -static int -target_modesense_rwrecovery(unsigned char *p) +static int spc_modesense_rwrecovery(unsigned char *p) { p[0] = 0x01; p[1] = 0x0a; @@ -742,8 +674,7 @@ target_modesense_rwrecovery(unsigned char *p) return 12; } -static int -target_modesense_control(struct se_device *dev, unsigned char *p) +static int spc_modesense_control(struct se_device *dev, unsigned char *p) { p[0] = 0x0a; p[1] = 0x0a; @@ -828,8 +759,7 @@ target_modesense_control(struct se_device *dev, unsigned char *p) return 12; } -static int -target_modesense_caching(struct se_device *dev, unsigned char *p) +static int spc_modesense_caching(struct se_device *dev, unsigned char *p) { p[0] = 0x08; p[1] = 0x12; @@ -840,8 +770,7 @@ target_modesense_caching(struct se_device *dev, unsigned char *p) return 20; } -static void -target_modesense_write_protect(unsigned char *buf, int type) +static void spc_modesense_write_protect(unsigned char *buf, int type) { /* * I believe that the WP bit (bit 7) in the mode header is the same for @@ -856,8 +785,7 @@ target_modesense_write_protect(unsigned char *buf, int type) } } -static void -target_modesense_dpofua(unsigned char *buf, int type) +static void spc_modesense_dpofua(unsigned char *buf, int type) { switch (type) { case TYPE_DISK: @@ -868,7 +796,7 @@ target_modesense_dpofua(unsigned char *buf, int type) } } -int target_emulate_modesense(struct se_cmd *cmd) +static int spc_emulate_modesense(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; @@ -883,18 +811,18 @@ int target_emulate_modesense(struct se_cmd *cmd) switch (cdb[2] & 0x3f) { case 0x01: - length = target_modesense_rwrecovery(&buf[offset]); + length = spc_modesense_rwrecovery(&buf[offset]); break; case 0x08: - length = target_modesense_caching(dev, &buf[offset]); + length = spc_modesense_caching(dev, &buf[offset]); break; case 0x0a: - length = target_modesense_control(dev, &buf[offset]); + length = spc_modesense_control(dev, &buf[offset]); break; case 0x3f: - length = target_modesense_rwrecovery(&buf[offset]); - length += target_modesense_caching(dev, &buf[offset+length]); - length += target_modesense_control(dev, &buf[offset+length]); + length = spc_modesense_rwrecovery(&buf[offset]); + length += spc_modesense_caching(dev, &buf[offset+length]); + length += spc_modesense_control(dev, &buf[offset+length]); break; default: pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", @@ -912,11 +840,11 @@ int target_emulate_modesense(struct se_cmd *cmd) if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || (cmd->se_deve && (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) - target_modesense_write_protect(&buf[3], type); + spc_modesense_write_protect(&buf[3], type); if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) - target_modesense_dpofua(&buf[3], type); + spc_modesense_dpofua(&buf[3], type); if ((offset + 2) > cmd->data_length) offset = cmd->data_length; @@ -928,11 +856,11 @@ int target_emulate_modesense(struct se_cmd *cmd) if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || (cmd->se_deve && (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) - target_modesense_write_protect(&buf[2], type); + spc_modesense_write_protect(&buf[2], type); if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) - target_modesense_dpofua(&buf[2], type); + spc_modesense_dpofua(&buf[2], type); if ((offset + 1) > cmd->data_length) offset = cmd->data_length; @@ -946,7 +874,7 @@ int target_emulate_modesense(struct se_cmd *cmd) return 0; } -int target_emulate_request_sense(struct se_cmd *cmd) +static int spc_emulate_request_sense(struct se_cmd *cmd) { unsigned char *cdb = cmd->t_task_cdb; unsigned char *buf; @@ -1005,126 +933,172 @@ end: return 0; } -/* - * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. - * Note this is not used for TCM/pSCSI passthrough - */ -int target_emulate_unmap(struct se_cmd *cmd) +static int spc_emulate_testunitready(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; - unsigned char *buf, *ptr = NULL; - unsigned char *cdb = &cmd->t_task_cdb[0]; - sector_t lba; - unsigned int size = cmd->data_length, range; - int ret = 0, offset; - unsigned short dl, bd_dl; - - if (!dev->transport->do_discard) { - pr_err("UNMAP emulation not supported for: %s\n", - dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } - - /* First UNMAP block descriptor starts at 8 byte offset */ - offset = 8; - size -= 8; - dl = get_unaligned_be16(&cdb[0]); - bd_dl = get_unaligned_be16(&cdb[2]); - - buf = transport_kmap_data_sg(cmd); - - ptr = &buf[offset]; - pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" - " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); - - while (size) { - lba = get_unaligned_be64(&ptr[0]); - range = get_unaligned_be32(&ptr[8]); - pr_debug("UNMAP: Using lba: %llu and range: %u\n", - (unsigned long long)lba, range); - - ret = dev->transport->do_discard(dev, lba, range); - if (ret < 0) { - pr_err("blkdev_issue_discard() failed: %d\n", - ret); - goto err; - } - - ptr += 16; - size -= 16; - } - -err: - transport_kunmap_data_sg(cmd); - if (!ret) - target_complete_cmd(cmd, GOOD); - return ret; + target_complete_cmd(cmd, GOOD); + return 0; } -/* - * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. - * Note this is not used for TCM/pSCSI passthrough - */ -int target_emulate_write_same(struct se_cmd *cmd) +int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) { struct se_device *dev = cmd->se_dev; - sector_t range; - sector_t lba = cmd->t_task_lba; - u32 num_blocks; - int ret; - - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME emulation not supported" - " for: %s\n", dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } - - if (cmd->t_task_cdb[0] == WRITE_SAME) - num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); - else if (cmd->t_task_cdb[0] == WRITE_SAME_16) - num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); - else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */ - num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); - - /* - * Use the explicit range when non zero is supplied, otherwise calculate - * the remaining range based on ->get_blocks() - starting LBA. - */ - if (num_blocks != 0) - range = num_blocks; - else - range = (dev->transport->get_blocks(dev) - lba); - - pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n", - (unsigned long long)lba, (unsigned long long)range); + struct se_subsystem_dev *su_dev = dev->se_sub_dev; + unsigned char *cdb = cmd->t_task_cdb; - ret = dev->transport->do_discard(dev, lba, range); - if (ret < 0) { - pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); - return ret; - } + switch (cdb[0]) { + case MODE_SELECT: + *size = cdb[4]; + break; + case MODE_SELECT_10: + *size = (cdb[7] << 8) + cdb[8]; + break; + case MODE_SENSE: + *size = cdb[4]; + cmd->execute_cmd = spc_emulate_modesense; + break; + case MODE_SENSE_10: + *size = (cdb[7] << 8) + cdb[8]; + cmd->execute_cmd = spc_emulate_modesense; + break; + case LOG_SELECT: + case LOG_SENSE: + *size = (cdb[7] << 8) + cdb[8]; + break; + case PERSISTENT_RESERVE_IN: + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_cmd = target_scsi3_emulate_pr_in; + *size = (cdb[7] << 8) + cdb[8]; + break; + case PERSISTENT_RESERVE_OUT: + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_cmd = target_scsi3_emulate_pr_out; + *size = (cdb[7] << 8) + cdb[8]; + break; + case RELEASE: + case RELEASE_10: + if (cdb[0] == RELEASE_10) + *size = (cdb[7] << 8) | cdb[8]; + else + *size = cmd->data_length; + + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_cmd = target_scsi2_reservation_release; + break; + case RESERVE: + case RESERVE_10: + /* + * The SPC-2 RESERVE does not contain a size in the SCSI CDB. + * Assume the passthrough or $FABRIC_MOD will tell us about it. + */ + if (cdb[0] == RESERVE_10) + *size = (cdb[7] << 8) | cdb[8]; + else + *size = cmd->data_length; - target_complete_cmd(cmd, GOOD); - return 0; -} + /* + * Setup the legacy emulated handler for SPC-2 and + * >= SPC-3 compatible reservation handling (CRH=1) + * Otherwise, we assume the underlying SCSI logic is + * is running in SPC_PASSTHROUGH, and wants reservations + * emulation disabled. + */ + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_cmd = target_scsi2_reservation_reserve; + break; + case REQUEST_SENSE: + *size = cdb[4]; + cmd->execute_cmd = spc_emulate_request_sense; + break; + case INQUIRY: + *size = (cdb[3] << 8) + cdb[4]; -int target_emulate_synchronize_cache(struct se_cmd *cmd) -{ - if (!cmd->se_dev->transport->do_sync_cache) { - pr_err("SYNCHRONIZE_CACHE emulation not supported" - " for: %s\n", cmd->se_dev->transport->name); + /* + * Do implict HEAD_OF_QUEUE processing for INQUIRY. + * See spc4r17 section 5.3 + */ + if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + cmd->sam_task_attr = MSG_HEAD_TAG; + cmd->execute_cmd = spc_emulate_inquiry; + break; + case SECURITY_PROTOCOL_IN: + case SECURITY_PROTOCOL_OUT: + *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + case EXTENDED_COPY: + case READ_ATTRIBUTE: + case RECEIVE_COPY_RESULTS: + case WRITE_ATTRIBUTE: + *size = (cdb[10] << 24) | (cdb[11] << 16) | + (cdb[12] << 8) | cdb[13]; + break; + case RECEIVE_DIAGNOSTIC: + case SEND_DIAGNOSTIC: + *size = (cdb[3] << 8) | cdb[4]; + break; + case WRITE_BUFFER: + *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; + break; + case REPORT_LUNS: + cmd->execute_cmd = target_report_luns; + *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + /* + * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS + * See spc4r17 section 5.3 + */ + if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + cmd->sam_task_attr = MSG_HEAD_TAG; + break; + case TEST_UNIT_READY: + cmd->execute_cmd = spc_emulate_testunitready; + *size = 0; + break; + case MAINTENANCE_IN: + if (dev->transport->get_device_type(dev) != TYPE_ROM) { + /* + * MAINTENANCE_IN from SCC-2 + * Check for emulated MI_REPORT_TARGET_PGS + */ + if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_cmd = + target_emulate_report_target_port_groups; + } + *size = get_unaligned_be32(&cdb[6]); + } else { + /* + * GPCMD_SEND_KEY from multi media commands + */ + *size = get_unaligned_be16(&cdb[8]); + } + break; + case MAINTENANCE_OUT: + if (dev->transport->get_device_type(dev) != TYPE_ROM) { + /* + * MAINTENANCE_OUT from SCC-2 + * Check for emulated MO_SET_TARGET_PGS. + */ + if (cdb[1] == MO_SET_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_cmd = + target_emulate_set_target_port_groups; + } + *size = get_unaligned_be32(&cdb[6]); + } else { + /* + * GPCMD_SEND_KEY from multi media commands + */ + *size = get_unaligned_be16(&cdb[8]); + } + break; + default: + pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" + " 0x%02x, sending CHECK_CONDITION.\n", + cmd->se_tfo->get_fabric_name(), cdb[0]); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; + return -EINVAL; } - cmd->se_dev->transport->do_sync_cache(cmd); - return 0; -} - -int target_emulate_noop(struct se_cmd *cmd) -{ - target_complete_cmd(cmd, GOOD); return 0; } +EXPORT_SYMBOL(spc_parse_cdb); diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 84caf1bed9a..1c59a3c23b2 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -295,9 +295,6 @@ static void core_tmr_drain_state_list( list_move_tail(&cmd->state_list, &drain_task_list); cmd->state_active = false; - - if (!list_empty(&cmd->execute_list)) - __target_remove_from_execute_list(cmd); } spin_unlock_irqrestore(&dev->execute_task_lock, flags); @@ -354,57 +351,6 @@ static void core_tmr_drain_state_list( } } -static void core_tmr_drain_cmd_list( - struct se_device *dev, - struct se_cmd *prout_cmd, - struct se_node_acl *tmr_nacl, - int tas, - struct list_head *preempt_and_abort_list) -{ - LIST_HEAD(drain_cmd_list); - struct se_queue_obj *qobj = &dev->dev_queue_obj; - struct se_cmd *cmd, *tcmd; - unsigned long flags; - - /* - * Release all commands remaining in the per-device command queue. - * - * This follows the same logic as above for the state list. - */ - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - list_for_each_entry_safe(cmd, tcmd, &qobj->qobj_list, se_queue_node) { - /* - * For PREEMPT_AND_ABORT usage, only process commands - * with a matching reservation key. - */ - if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) - continue; - /* - * Not aborting PROUT PREEMPT_AND_ABORT CDB.. - */ - if (prout_cmd == cmd) - continue; - - cmd->transport_state &= ~CMD_T_QUEUED; - atomic_dec(&qobj->queue_cnt); - list_move_tail(&cmd->se_queue_node, &drain_cmd_list); - } - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - while (!list_empty(&drain_cmd_list)) { - cmd = list_entry(drain_cmd_list.next, struct se_cmd, se_queue_node); - list_del_init(&cmd->se_queue_node); - - pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:" - " %d t_fe_count: %d\n", (preempt_and_abort_list) ? - "Preempt" : "", cmd, cmd->t_state, - atomic_read(&cmd->t_fe_count)); - - core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, - atomic_read(&cmd->t_fe_count)); - } -} - int core_tmr_lun_reset( struct se_device *dev, struct se_tmr_req *tmr, @@ -447,8 +393,7 @@ int core_tmr_lun_reset( core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list); core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas, preempt_and_abort_list); - core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas, - preempt_and_abort_list); + /* * Clear any legacy SPC-2 reservation when called during * LOGICAL UNIT RESET diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 8bd58e28418..b8628a5014b 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -77,8 +77,8 @@ static void core_clear_initiator_node_from_tpg( lun = deve->se_lun; spin_unlock_irq(&nacl->device_list_lock); - core_update_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); spin_lock_irq(&nacl->device_list_lock); } @@ -172,8 +172,8 @@ void core_tpg_add_node_to_devs( (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ? "READ-WRITE" : "READ-ONLY"); - core_update_device_list_for_node(lun, NULL, lun->unpacked_lun, - lun_access, acl, tpg, 1); + core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun, + lun_access, acl, tpg); spin_lock(&tpg->tpg_lun_lock); } spin_unlock(&tpg->tpg_lun_lock); @@ -306,10 +306,8 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( * TPG LUNs if the fabric is not explictly asking for * tpg_check_demo_mode_login_only() == 1. */ - if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only != NULL) && - (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) == 1)) - do { ; } while (0); - else + if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) || + (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1)) core_tpg_add_node_to_devs(acl, tpg); spin_lock_irq(&tpg->acl_node_lock); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 634d0f31a28..0eaae23d12b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -66,15 +66,12 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache; struct kmem_cache *t10_alua_tg_pt_gp_cache; struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -static int transport_generic_write_pending(struct se_cmd *); -static int transport_processing_thread(void *param); -static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *); static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); static int transport_generic_get_mem(struct se_cmd *cmd); +static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); static void transport_put_cmd(struct se_cmd *cmd); -static void transport_remove_cmd_from_queue(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); static void target_complete_ok_work(struct work_struct *work); @@ -195,14 +192,6 @@ u32 scsi_get_new_index(scsi_index_t type) return new_index; } -static void transport_init_queue_obj(struct se_queue_obj *qobj) -{ - atomic_set(&qobj->queue_cnt, 0); - INIT_LIST_HEAD(&qobj->qobj_list); - init_waitqueue_head(&qobj->thread_wq); - spin_lock_init(&qobj->cmd_queue_lock); -} - void transport_subsystem_check_init(void) { int ret; @@ -243,7 +232,6 @@ struct se_session *transport_init_session(void) INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); INIT_LIST_HEAD(&se_sess->sess_cmd_list); - INIT_LIST_HEAD(&se_sess->sess_wait_list); spin_lock_init(&se_sess->sess_cmd_lock); kref_init(&se_sess->sess_kref); @@ -468,18 +456,7 @@ static void target_remove_from_state_list(struct se_cmd *cmd) spin_unlock_irqrestore(&dev->execute_task_lock, flags); } -/* transport_cmd_check_stop(): - * - * 'transport_off = 1' determines if CMD_T_ACTIVE should be cleared. - * 'transport_off = 2' determines if task_dev_state should be removed. - * - * A non-zero u8 t_state sets cmd->t_state. - * Returns 1 when command is stopped, else 0. - */ -static int transport_cmd_check_stop( - struct se_cmd *cmd, - int transport_off, - u8 t_state) +static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists) { unsigned long flags; @@ -493,13 +470,23 @@ static int transport_cmd_check_stop( __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); cmd->transport_state &= ~CMD_T_ACTIVE; - if (transport_off == 2) + if (remove_from_lists) target_remove_from_state_list(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, flags); complete(&cmd->transport_lun_stop_comp); return 1; } + + if (remove_from_lists) { + target_remove_from_state_list(cmd); + + /* + * Clear struct se_cmd->se_lun before the handoff to FE. + */ + cmd->se_lun = NULL; + } + /* * Determine if frontend context caller is requesting the stopping of * this command for frontend exceptions. @@ -509,58 +496,36 @@ static int transport_cmd_check_stop( __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); - if (transport_off == 2) - target_remove_from_state_list(cmd); - - /* - * Clear struct se_cmd->se_lun before the transport_off == 2 handoff - * to FE. - */ - if (transport_off == 2) - cmd->se_lun = NULL; spin_unlock_irqrestore(&cmd->t_state_lock, flags); complete(&cmd->t_transport_stop_comp); return 1; } - if (transport_off) { - cmd->transport_state &= ~CMD_T_ACTIVE; - if (transport_off == 2) { - target_remove_from_state_list(cmd); - /* - * Clear struct se_cmd->se_lun before the transport_off == 2 - * handoff to fabric module. - */ - cmd->se_lun = NULL; - /* - * Some fabric modules like tcm_loop can release - * their internally allocated I/O reference now and - * struct se_cmd now. - * - * Fabric modules are expected to return '1' here if the - * se_cmd being passed is released at this point, - * or zero if not being released. - */ - if (cmd->se_tfo->check_stop_free != NULL) { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - - return cmd->se_tfo->check_stop_free(cmd); - } + + cmd->transport_state &= ~CMD_T_ACTIVE; + if (remove_from_lists) { + /* + * Some fabric modules like tcm_loop can release + * their internally allocated I/O reference now and + * struct se_cmd now. + * + * Fabric modules are expected to return '1' here if the + * se_cmd being passed is released at this point, + * or zero if not being released. + */ + if (cmd->se_tfo->check_stop_free != NULL) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return cmd->se_tfo->check_stop_free(cmd); } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + } - return 0; - } else if (t_state) - cmd->t_state = t_state; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return 0; } static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd) { - return transport_cmd_check_stop(cmd, 2, 0); + return transport_cmd_check_stop(cmd, true); } static void transport_lun_remove_cmd(struct se_cmd *cmd) @@ -591,79 +556,8 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) if (transport_cmd_check_stop_to_fabric(cmd)) return; - if (remove) { - transport_remove_cmd_from_queue(cmd); + if (remove) transport_put_cmd(cmd); - } -} - -static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state, - bool at_head) -{ - struct se_device *dev = cmd->se_dev; - struct se_queue_obj *qobj = &dev->dev_queue_obj; - unsigned long flags; - - if (t_state) { - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->t_state = t_state; - cmd->transport_state |= CMD_T_ACTIVE; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - } - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - - /* If the cmd is already on the list, remove it before we add it */ - if (!list_empty(&cmd->se_queue_node)) - list_del(&cmd->se_queue_node); - else - atomic_inc(&qobj->queue_cnt); - - if (at_head) - list_add(&cmd->se_queue_node, &qobj->qobj_list); - else - list_add_tail(&cmd->se_queue_node, &qobj->qobj_list); - cmd->transport_state |= CMD_T_QUEUED; - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - wake_up_interruptible(&qobj->thread_wq); -} - -static struct se_cmd * -transport_get_cmd_from_queue(struct se_queue_obj *qobj) -{ - struct se_cmd *cmd; - unsigned long flags; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (list_empty(&qobj->qobj_list)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return NULL; - } - cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node); - - cmd->transport_state &= ~CMD_T_QUEUED; - list_del_init(&cmd->se_queue_node); - atomic_dec(&qobj->queue_cnt); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - return cmd; -} - -static void transport_remove_cmd_from_queue(struct se_cmd *cmd) -{ - struct se_queue_obj *qobj = &cmd->se_dev->dev_queue_obj; - unsigned long flags; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (!(cmd->transport_state & CMD_T_QUEUED)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return; - } - cmd->transport_state &= ~CMD_T_QUEUED; - atomic_dec(&qobj->queue_cnt); - list_del_init(&cmd->se_queue_node); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); } static void target_complete_failure_work(struct work_struct *work) @@ -742,68 +636,11 @@ static void target_add_to_state_list(struct se_cmd *cmd) spin_unlock_irqrestore(&dev->execute_task_lock, flags); } -static void __target_add_to_execute_list(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - bool head_of_queue = false; - - if (!list_empty(&cmd->execute_list)) - return; - - if (dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED && - cmd->sam_task_attr == MSG_HEAD_TAG) - head_of_queue = true; - - if (head_of_queue) - list_add(&cmd->execute_list, &dev->execute_list); - else - list_add_tail(&cmd->execute_list, &dev->execute_list); - - atomic_inc(&dev->execute_tasks); - - if (cmd->state_active) - return; - - if (head_of_queue) - list_add(&cmd->state_list, &dev->state_list); - else - list_add_tail(&cmd->state_list, &dev->state_list); - - cmd->state_active = true; -} - -static void target_add_to_execute_list(struct se_cmd *cmd) -{ - unsigned long flags; - struct se_device *dev = cmd->se_dev; - - spin_lock_irqsave(&dev->execute_task_lock, flags); - __target_add_to_execute_list(cmd); - spin_unlock_irqrestore(&dev->execute_task_lock, flags); -} - -void __target_remove_from_execute_list(struct se_cmd *cmd) -{ - list_del_init(&cmd->execute_list); - atomic_dec(&cmd->se_dev->execute_tasks); -} - -static void target_remove_from_execute_list(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned long flags; - - if (WARN_ON(list_empty(&cmd->execute_list))) - return; - - spin_lock_irqsave(&dev->execute_task_lock, flags); - __target_remove_from_execute_list(cmd); - spin_unlock_irqrestore(&dev->execute_task_lock, flags); -} - /* * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status */ +static void transport_write_pending_qf(struct se_cmd *cmd); +static void transport_complete_qf(struct se_cmd *cmd); static void target_qf_do_work(struct work_struct *work) { @@ -827,7 +664,10 @@ static void target_qf_do_work(struct work_struct *work) (cmd->t_state == TRANSPORT_COMPLETE_QF_WP) ? "WRITE_PENDING" : "UNKNOWN"); - transport_add_cmd_to_queue(cmd, cmd->t_state, true); + if (cmd->t_state == TRANSPORT_COMPLETE_QF_WP) + transport_write_pending_qf(cmd); + else if (cmd->t_state == TRANSPORT_COMPLETE_QF_OK) + transport_complete_qf(cmd); } } @@ -874,8 +714,7 @@ void transport_dump_dev_state( break; } - *bl += sprintf(b + *bl, " Execute/Max Queue Depth: %d/%d", - atomic_read(&dev->execute_tasks), dev->queue_depth); + *bl += sprintf(b + *bl, " Max Queue Depth: %d", dev->queue_depth); *bl += sprintf(b + *bl, " SectorSize: %u HwMaxSectors: %u\n", dev->se_sub_dev->se_dev_attrib.block_size, dev->se_sub_dev->se_dev_attrib.hw_max_sectors); @@ -1212,7 +1051,6 @@ struct se_device *transport_add_device_to_core_hba( return NULL; } - transport_init_queue_obj(&dev->dev_queue_obj); dev->dev_flags = device_flags; dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED; dev->dev_ptr = transport_dev; @@ -1222,7 +1060,6 @@ struct se_device *transport_add_device_to_core_hba( INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_tmr_list); - INIT_LIST_HEAD(&dev->execute_list); INIT_LIST_HEAD(&dev->delayed_cmd_list); INIT_LIST_HEAD(&dev->state_list); INIT_LIST_HEAD(&dev->qf_cmd_list); @@ -1261,17 +1098,17 @@ struct se_device *transport_add_device_to_core_hba( * Setup the Asymmetric Logical Unit Assignment for struct se_device */ if (core_setup_alua(dev, force_pt) < 0) - goto out; + goto err_dev_list; /* * Startup the struct se_device processing thread */ - dev->process_thread = kthread_run(transport_processing_thread, dev, - "LIO_%s", dev->transport->name); - if (IS_ERR(dev->process_thread)) { - pr_err("Unable to create kthread: LIO_%s\n", + dev->tmr_wq = alloc_workqueue("tmr-%s", WQ_MEM_RECLAIM | WQ_UNBOUND, 1, + dev->transport->name); + if (!dev->tmr_wq) { + pr_err("Unable to create tmr workqueue for %s\n", dev->transport->name); - goto out; + goto err_dev_list; } /* * Setup work_queue for QUEUE_FULL @@ -1289,7 +1126,7 @@ struct se_device *transport_add_device_to_core_hba( if (!inquiry_prod || !inquiry_rev) { pr_err("All non TCM/pSCSI plugins require" " INQUIRY consts\n"); - goto out; + goto err_wq; } strncpy(&dev->se_sub_dev->t10_wwn.vendor[0], "LIO-ORG", 8); @@ -1299,9 +1136,10 @@ struct se_device *transport_add_device_to_core_hba( scsi_dump_inquiry(dev); return dev; -out: - kthread_stop(dev->process_thread); +err_wq: + destroy_workqueue(dev->tmr_wq); +err_dev_list: spin_lock(&hba->device_lock); list_del(&dev->dev_list); hba->dev_count--; @@ -1315,35 +1153,54 @@ out: } EXPORT_SYMBOL(transport_add_device_to_core_hba); -/* transport_generic_prepare_cdb(): - * - * Since the Initiator sees iSCSI devices as LUNs, the SCSI CDB will - * contain the iSCSI LUN in bits 7-5 of byte 1 as per SAM-2. - * The point of this is since we are mapping iSCSI LUNs to - * SCSI Target IDs having a non-zero LUN in the CDB will throw the - * devices and HBAs for a loop. - */ -static inline void transport_generic_prepare_cdb( - unsigned char *cdb) +int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { - switch (cdb[0]) { - case READ_10: /* SBC - RDProtect */ - case READ_12: /* SBC - RDProtect */ - case READ_16: /* SBC - RDProtect */ - case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ - case VERIFY: /* SBC - VRProtect */ - case VERIFY_16: /* SBC - VRProtect */ - case WRITE_VERIFY: /* SBC - VRProtect */ - case WRITE_VERIFY_12: /* SBC - VRProtect */ - case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ - break; - default: - cdb[1] &= 0x1f; /* clear logical unit number */ - break; + struct se_device *dev = cmd->se_dev; + + if (cmd->unknown_data_length) { + cmd->data_length = size; + } else if (size != cmd->data_length) { + pr_warn("TARGET_CORE[%s]: Expected Transfer Length:" + " %u does not match SCSI CDB Length: %u for SAM Opcode:" + " 0x%02x\n", cmd->se_tfo->get_fabric_name(), + cmd->data_length, size, cmd->t_task_cdb[0]); + + cmd->cmd_spdtl = size; + + if (cmd->data_direction == DMA_TO_DEVICE) { + pr_err("Rejecting underflow/overflow" + " WRITE data\n"); + goto out_invalid_cdb_field; + } + /* + * Reject READ_* or WRITE_* with overflow/underflow for + * type SCF_SCSI_DATA_CDB. + */ + if (dev->se_sub_dev->se_dev_attrib.block_size != 512) { + pr_err("Failing OVERFLOW/UNDERFLOW for LBA op" + " CDB on non 512-byte sector setup subsystem" + " plugin: %s\n", dev->transport->name); + /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ + goto out_invalid_cdb_field; + } + + if (size > cmd->data_length) { + cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; + cmd->residual_count = (size - cmd->data_length); + } else { + cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; + cmd->residual_count = (cmd->data_length - size); + } + cmd->data_length = size; } -} -static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); + return 0; + +out_invalid_cdb_field: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; +} /* * Used by fabric modules containing a local struct se_cmd within their @@ -1361,9 +1218,7 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_lun_node); INIT_LIST_HEAD(&cmd->se_delayed_node); INIT_LIST_HEAD(&cmd->se_qf_node); - INIT_LIST_HEAD(&cmd->se_queue_node); INIT_LIST_HEAD(&cmd->se_cmd_list); - INIT_LIST_HEAD(&cmd->execute_list); INIT_LIST_HEAD(&cmd->state_list); init_completion(&cmd->transport_lun_fe_stop_comp); init_completion(&cmd->transport_lun_stop_comp); @@ -1418,9 +1273,12 @@ int target_setup_cmd_from_cdb( struct se_cmd *cmd, unsigned char *cdb) { + struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + u32 pr_reg_type = 0; + u8 alua_ascq = 0; + unsigned long flags; int ret; - transport_generic_prepare_cdb(cdb); /* * Ensure that the received CDB is less than the max (252 + 8) bytes * for VARIABLE_LENGTH_CMD @@ -1457,15 +1315,66 @@ int target_setup_cmd_from_cdb( * Copy the original CDB into cmd-> */ memcpy(cmd->t_task_cdb, cdb, scsi_command_size(cdb)); + /* - * Setup the received CDB based on SCSI defined opcodes and - * perform unit attention, persistent reservations and ALUA - * checks for virtual device backends. The cmd->t_task_cdb - * pointer is expected to be setup before we reach this point. + * Check for an existing UNIT ATTENTION condition */ - ret = transport_generic_cmd_sequencer(cmd, cdb); + if (core_scsi3_ua_check(cmd, cdb) < 0) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION; + return -EINVAL; + } + + ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq); + if (ret != 0) { + /* + * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; + * The ALUA additional sense code qualifier (ASCQ) is determined + * by the ALUA primary or secondary access state.. + */ + if (ret > 0) { + pr_debug("[%s]: ALUA TG Port not available, " + "SenseKey: NOT_READY, ASC/ASCQ: " + "0x04/0x%02x\n", + cmd->se_tfo->get_fabric_name(), alua_ascq); + + transport_set_sense_codes(cmd, 0x04, alua_ascq); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY; + return -EINVAL; + } + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; + } + + /* + * Check status for SPC-3 Persistent Reservations + */ + if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type)) { + if (su_dev->t10_pr.pr_ops.t10_seq_non_holder( + cmd, cdb, pr_reg_type) != 0) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; + cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EBUSY; + } + /* + * This means the CDB is allowed for the SCSI Initiator port + * when said port is *NOT* holding the legacy SPC-2 or + * SPC-3 Persistent Reservation. + */ + } + + ret = cmd->se_dev->transport->parse_cdb(cmd); if (ret < 0) return ret; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + /* * Check for SAM Task Attribute Emulation */ @@ -1503,10 +1412,9 @@ int transport_handle_cdb_direct( return -EINVAL; } /* - * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE following - * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue() - * in existing usage to ensure that outstanding descriptors are handled - * correctly during shutdown via transport_wait_for_tasks() + * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE to ensure that + * outstanding descriptors are handled correctly during shutdown via + * transport_wait_for_tasks() * * Also, we don't take cmd->t_state_lock here as we only expect * this to be called for initial descriptor submission. @@ -1540,10 +1448,14 @@ EXPORT_SYMBOL(transport_handle_cdb_direct); * @data_dir: DMA data direction * @flags: flags for command submission from target_sc_flags_tables * + * Returns non zero to signal active I/O shutdown failure. All other + * setup exceptions will be returned as a SCSI CHECK_CONDITION response, + * but still return zero here. + * * This may only be called from process context, and also currently * assumes internal allocation of fabric payload buffer by target-core. **/ -void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, +int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags) { @@ -1569,7 +1481,9 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, * for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + if (rc) + return rc; /* * Signal bidirectional data payloads to target-core */ @@ -1582,16 +1496,13 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, transport_send_check_condition_and_sense(se_cmd, se_cmd->scsi_sense_reason, 0); target_put_sess_cmd(se_sess, se_cmd); - return; + return 0; } - /* - * Sanitize CDBs via transport_generic_cmd_sequencer() and - * allocate the necessary tasks to complete the received CDB+data - */ + rc = target_setup_cmd_from_cdb(se_cmd, cdb); if (rc != 0) { transport_generic_request_failure(se_cmd); - return; + return 0; } /* @@ -1600,14 +1511,8 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, */ core_alua_check_nonop_delay(se_cmd); - /* - * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend - * for immediate execution of READs, otherwise wait for - * transport_generic_handle_data() to be called for WRITEs - * when fabric has filled the incoming buffer. - */ transport_handle_cdb_direct(se_cmd); - return; + return 0; } EXPORT_SYMBOL(target_submit_cmd); @@ -1662,7 +1567,11 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, se_cmd->se_tmr_req->ref_task_tag = tag; /* See target_submit_cmd for commentary */ - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + if (ret) { + core_tmr_release_req(se_cmd->se_tmr_req); + return ret; + } ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); if (ret) { @@ -1680,67 +1589,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, EXPORT_SYMBOL(target_submit_tmr); /* - * Used by fabric module frontends defining a TFO->new_cmd_map() caller - * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to - * complete setup in TCM process context w/ TFO->new_cmd_map(). - */ -int transport_generic_handle_cdb_map( - struct se_cmd *cmd) -{ - if (!cmd->se_lun) { - dump_stack(); - pr_err("cmd->se_lun is NULL\n"); - return -EINVAL; - } - - transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP, false); - return 0; -} -EXPORT_SYMBOL(transport_generic_handle_cdb_map); - -/* transport_generic_handle_data(): - * - * - */ -int transport_generic_handle_data( - struct se_cmd *cmd) -{ - /* - * For the software fabric case, then we assume the nexus is being - * failed/shutdown when signals are pending from the kthread context - * caller, so we return a failure. For the HW target mode case running - * in interrupt code, the signal_pending() check is skipped. - */ - if (!in_interrupt() && signal_pending(current)) - return -EPERM; - /* - * If the received CDB has aleady been ABORTED by the generic - * target engine, we now call transport_check_aborted_status() - * to queue any delated TASK_ABORTED status for the received CDB to the - * fabric module as we are expecting no further incoming DATA OUT - * sequences at this point. - */ - if (transport_check_aborted_status(cmd, 1) != 0) - return 0; - - transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE, false); - return 0; -} -EXPORT_SYMBOL(transport_generic_handle_data); - -/* transport_generic_handle_tmr(): - * - * - */ -int transport_generic_handle_tmr( - struct se_cmd *cmd) -{ - transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR, false); - return 0; -} -EXPORT_SYMBOL(transport_generic_handle_tmr); - -/* * If the cmd is active, request it to be stopped and sleep until it * has completed. */ @@ -1797,6 +1645,7 @@ void transport_generic_request_failure(struct se_cmd *cmd) case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: case TCM_UNKNOWN_MODE_PAGE: case TCM_WRITE_PROTECTED: + case TCM_ADDRESS_OUT_OF_RANGE: case TCM_CHECK_CONDITION_ABORT_CMD: case TCM_CHECK_CONDITION_UNIT_ATTENTION: case TCM_CHECK_CONDITION_NOT_READY: @@ -1832,13 +1681,7 @@ void transport_generic_request_failure(struct se_cmd *cmd) cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; break; } - /* - * If a fabric does not define a cmd->se_tfo->new_cmd_map caller, - * make the call to transport_send_check_condition_and_sense() - * directly. Otherwise expect the fabric to make the call to - * transport_send_check_condition_and_sense() after handling - * possible unsoliticied write data payloads. - */ + ret = transport_send_check_condition_and_sense(cmd, cmd->scsi_sense_reason, 0); if (ret == -EAGAIN || ret == -ENOMEM) @@ -1856,406 +1699,123 @@ queue_full: } EXPORT_SYMBOL(transport_generic_request_failure); -static inline u32 transport_lba_21(unsigned char *cdb) +static void __target_execute_cmd(struct se_cmd *cmd) { - return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; -} + int error = 0; -static inline u32 transport_lba_32(unsigned char *cdb) -{ - return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; -} - -static inline unsigned long long transport_lba_64(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - -/* - * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs - */ -static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; - __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - -static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - se_cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); -} - -/* - * Called from Fabric Module context from transport_execute_tasks() - * - * The return of this function determins if the tasks from struct se_cmd - * get added to the execution queue in transport_execute_tasks(), - * or are added to the delayed or ordered lists here. - */ -static inline int transport_execute_task_attr(struct se_cmd *cmd) -{ - if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) - return 1; - /* - * Check for the existence of HEAD_OF_QUEUE, and if true return 1 - * to allow the passed struct se_cmd list of tasks to the front of the list. - */ - if (cmd->sam_task_attr == MSG_HEAD_TAG) { - pr_debug("Added HEAD_OF_QUEUE for CDB:" - " 0x%02x, se_ordered_id: %u\n", - cmd->t_task_cdb[0], - cmd->se_ordered_id); - return 1; - } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) { - atomic_inc(&cmd->se_dev->dev_ordered_sync); - smp_mb__after_atomic_inc(); - - pr_debug("Added ORDERED for CDB: 0x%02x to ordered" - " list, se_ordered_id: %u\n", - cmd->t_task_cdb[0], - cmd->se_ordered_id); - /* - * Add ORDERED command to tail of execution queue if - * no other older commands exist that need to be - * completed first. - */ - if (!atomic_read(&cmd->se_dev->simple_cmds)) - return 1; - } else { - /* - * For SIMPLE and UNTAGGED Task Attribute commands - */ - atomic_inc(&cmd->se_dev->simple_cmds); - smp_mb__after_atomic_inc(); - } - /* - * Otherwise if one or more outstanding ORDERED task attribute exist, - * add the dormant task(s) built for the passed struct se_cmd to the - * execution queue and become in Active state for this struct se_device. - */ - if (atomic_read(&cmd->se_dev->dev_ordered_sync) != 0) { - /* - * Otherwise, add cmd w/ tasks to delayed cmd queue that - * will be drained upon completion of HEAD_OF_QUEUE task. - */ - spin_lock(&cmd->se_dev->delayed_cmd_lock); - cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR; - list_add_tail(&cmd->se_delayed_node, - &cmd->se_dev->delayed_cmd_list); - spin_unlock(&cmd->se_dev->delayed_cmd_lock); - - pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to" - " delayed CMD list, se_ordered_id: %u\n", - cmd->t_task_cdb[0], cmd->sam_task_attr, - cmd->se_ordered_id); - /* - * Return zero to let transport_execute_tasks() know - * not to add the delayed tasks to the execution list. - */ - return 0; - } - /* - * Otherwise, no ORDERED task attributes exist.. - */ - return 1; -} - -/* - * Called from fabric module context in transport_generic_new_cmd() and - * transport_generic_process_write() - */ -static void transport_execute_tasks(struct se_cmd *cmd) -{ - int add_tasks; - struct se_device *se_dev = cmd->se_dev; - /* - * Call transport_cmd_check_stop() to see if a fabric exception - * has occurred that prevents execution. - */ - if (!transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING)) { - /* - * Check for SAM Task Attribute emulation and HEAD_OF_QUEUE - * attribute for the tasks of the received struct se_cmd CDB - */ - add_tasks = transport_execute_task_attr(cmd); - if (add_tasks) { - __transport_execute_tasks(se_dev, cmd); - return; - } - } - __transport_execute_tasks(se_dev, NULL); -} - -static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd) -{ - int error; - struct se_cmd *cmd = NULL; - unsigned long flags; - -check_depth: - spin_lock_irq(&dev->execute_task_lock); - if (new_cmd != NULL) - __target_add_to_execute_list(new_cmd); - - if (list_empty(&dev->execute_list)) { - spin_unlock_irq(&dev->execute_task_lock); - return 0; - } - cmd = list_first_entry(&dev->execute_list, struct se_cmd, execute_list); - __target_remove_from_execute_list(cmd); - spin_unlock_irq(&dev->execute_task_lock); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->transport_state |= CMD_T_BUSY; - cmd->transport_state |= CMD_T_SENT; - - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + spin_lock_irq(&cmd->t_state_lock); + cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT); + spin_unlock_irq(&cmd->t_state_lock); if (cmd->execute_cmd) error = cmd->execute_cmd(cmd); - else { - error = dev->transport->execute_cmd(cmd, cmd->t_data_sg, - cmd->t_data_nents, cmd->data_direction); - } - if (error != 0) { - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->transport_state &= ~CMD_T_BUSY; - cmd->transport_state &= ~CMD_T_SENT; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + if (error) { + spin_lock_irq(&cmd->t_state_lock); + cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT); + spin_unlock_irq(&cmd->t_state_lock); transport_generic_request_failure(cmd); } - - new_cmd = NULL; - goto check_depth; - - return 0; } -static inline u32 transport_get_sectors_6( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) +void target_execute_cmd(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 8-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * Use 24-bit allocation length for TYPE_TAPE. + * If the received CDB has aleady been aborted stop processing it here. */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4]; - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 8-bit sector value. SBC-3 says: - * - * A TRANSFER LENGTH field set to zero specifies that 256 - * logical blocks shall be written. Any other value - * specifies the number of logical blocks that shall be - * written. - */ -type_disk: - return cdb[4] ? : 256; -} - -static inline u32 transport_get_sectors_10( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; + if (transport_check_aborted_status(cmd, 1)) + return; /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 16-bit sector value. + * Determine if IOCTL context caller in requesting the stopping of this + * command for LUN shutdown purposes. */ - if (!dev) - goto type_disk; + spin_lock_irq(&cmd->t_state_lock); + if (cmd->transport_state & CMD_T_LUN_STOP) { + pr_debug("%s:%d CMD_T_LUN_STOP for ITT: 0x%08x\n", + __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); - /* - * XXX_10 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; + cmd->transport_state &= ~CMD_T_ACTIVE; + spin_unlock_irq(&cmd->t_state_lock); + complete(&cmd->transport_lun_stop_comp); + return; } - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 16-bit sector value. - */ -type_disk: - return (u32)(cdb[7] << 8) + cdb[8]; -} - -static inline u32 transport_get_sectors_12( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. + * Determine if frontend context caller is requesting the stopping of + * this command for frontend exceptions. */ - if (!dev) - goto type_disk; + if (cmd->transport_state & CMD_T_STOP) { + pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", + __func__, __LINE__, + cmd->se_tfo->get_task_tag(cmd)); - /* - * XXX_12 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; + spin_unlock_irq(&cmd->t_state_lock); + complete(&cmd->t_transport_stop_comp); + return; } - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 32-bit sector value. - */ -type_disk: - return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; -} - -static inline u32 transport_get_sectors_16( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - if (!dev) - goto type_disk; + cmd->t_state = TRANSPORT_PROCESSING; + spin_unlock_irq(&cmd->t_state_lock); - /* - * Use 24-bit allocation length for TYPE_TAPE. - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14]; - -type_disk: - return (u32)(cdb[10] << 24) + (cdb[11] << 16) + - (cdb[12] << 8) + cdb[13]; -} + if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) + goto execute; -/* - * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants - */ -static inline u32 transport_get_sectors_32( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. + * Check for the existence of HEAD_OF_QUEUE, and if true return 1 + * to allow the passed struct se_cmd list of tasks to the front of the list. */ - return (u32)(cdb[28] << 24) + (cdb[29] << 16) + - (cdb[30] << 8) + cdb[31]; + switch (cmd->sam_task_attr) { + case MSG_HEAD_TAG: + pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x, " + "se_ordered_id: %u\n", + cmd->t_task_cdb[0], cmd->se_ordered_id); + goto execute; + case MSG_ORDERED_TAG: + atomic_inc(&dev->dev_ordered_sync); + smp_mb__after_atomic_inc(); -} + pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, " + " se_ordered_id: %u\n", + cmd->t_task_cdb[0], cmd->se_ordered_id); -static inline u32 transport_get_size( - u32 sectors, - unsigned char *cdb, - struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - if (cdb[1] & 1) { /* sectors */ - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; - } else /* bytes */ - return sectors; + /* + * Execute an ORDERED command if no other older commands + * exist that need to be completed first. + */ + if (!atomic_read(&dev->simple_cmds)) + goto execute; + break; + default: + /* + * For SIMPLE and UNTAGGED Task Attribute commands + */ + atomic_inc(&dev->simple_cmds); + smp_mb__after_atomic_inc(); + break; } - pr_debug("Returning block_size: %u, sectors: %u == %u for" - " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, - sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors, - dev->transport->name); - - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; -} + if (atomic_read(&dev->dev_ordered_sync) != 0) { + spin_lock(&dev->delayed_cmd_lock); + list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); + spin_unlock(&dev->delayed_cmd_lock); -static void transport_xor_callback(struct se_cmd *cmd) -{ - unsigned char *buf, *addr; - struct scatterlist *sg; - unsigned int offset; - int i; - int count; - /* - * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command - * - * 1) read the specified logical block(s); - * 2) transfer logical blocks from the data-out buffer; - * 3) XOR the logical blocks transferred from the data-out buffer with - * the logical blocks read, storing the resulting XOR data in a buffer; - * 4) if the DISABLE WRITE bit is set to zero, then write the logical - * blocks transferred from the data-out buffer; and - * 5) transfer the resulting XOR data to the data-in buffer. - */ - buf = kmalloc(cmd->data_length, GFP_KERNEL); - if (!buf) { - pr_err("Unable to allocate xor_callback buf\n"); + pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to" + " delayed CMD list, se_ordered_id: %u\n", + cmd->t_task_cdb[0], cmd->sam_task_attr, + cmd->se_ordered_id); return; } - /* - * Copy the scatterlist WRITE buffer located at cmd->t_data_sg - * into the locally allocated *buf - */ - sg_copy_to_buffer(cmd->t_data_sg, - cmd->t_data_nents, - buf, - cmd->data_length); +execute: /* - * Now perform the XOR against the BIDI read memory located at - * cmd->t_mem_bidi_list + * Otherwise, no ORDERED task attributes exist.. */ - - offset = 0; - for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { - addr = kmap_atomic(sg_page(sg)); - if (!addr) - goto out; - - for (i = 0; i < sg->length; i++) - *(addr + sg->offset + i) ^= *(buf + offset + i); - - offset += sg->length; - kunmap_atomic(addr); - } - -out: - kfree(buf); + __target_execute_cmd(cmd); } +EXPORT_SYMBOL(target_execute_cmd); /* * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd @@ -2312,737 +1872,31 @@ out: return -1; } -static inline long long transport_dev_end_lba(struct se_device *dev) -{ - return dev->transport->get_blocks(dev) + 1; -} - -static int transport_cmd_get_valid_sectors(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - u32 sectors; - - if (dev->transport->get_device_type(dev) != TYPE_DISK) - return 0; - - sectors = (cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size); - - if ((cmd->t_task_lba + sectors) > transport_dev_end_lba(dev)) { - pr_err("LBA: %llu Sectors: %u exceeds" - " transport_dev_end_lba(): %llu\n", - cmd->t_task_lba, sectors, - transport_dev_end_lba(dev)); - return -EINVAL; - } - - return 0; -} - -static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev) -{ - /* - * Determine if the received WRITE_SAME is used to for direct - * passthrough into Linux/SCSI with struct request via TCM/pSCSI - * or we are signaling the use of internal WRITE_SAME + UNMAP=1 - * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code. - */ - int passthrough = (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV); - - if (!passthrough) { - if ((flags[0] & 0x04) || (flags[0] & 0x02)) { - pr_err("WRITE_SAME PBDATA and LBDATA" - " bits not supported for Block Discard" - " Emulation\n"); - return -ENOSYS; - } - /* - * Currently for the emulated case we only accept - * tpws with the UNMAP=1 bit set. - */ - if (!(flags[0] & 0x08)) { - pr_err("WRITE_SAME w/o UNMAP bit not" - " supported for Block Discard Emulation\n"); - return -ENOSYS; - } - } - - return 0; -} - -/* transport_generic_cmd_sequencer(): - * - * Generic Command Sequencer that should work for most DAS transport - * drivers. - * - * Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD - * RX Thread. - * - * FIXME: Need to support other SCSI OPCODES where as well. +/* + * Process all commands up to the last received ORDERED task attribute which + * requires another blocking boundary */ -static int transport_generic_cmd_sequencer( - struct se_cmd *cmd, - unsigned char *cdb) +static void target_restart_delayed_cmds(struct se_device *dev) { - struct se_device *dev = cmd->se_dev; - struct se_subsystem_dev *su_dev = dev->se_sub_dev; - int ret = 0, sector_ret = 0, passthrough; - u32 sectors = 0, size = 0, pr_reg_type = 0; - u16 service_action; - u8 alua_ascq = 0; - /* - * Check for an existing UNIT ATTENTION condition - */ - if (core_scsi3_ua_check(cmd, cdb) < 0) { - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION; - return -EINVAL; - } - /* - * Check status of Asymmetric Logical Unit Assignment port - */ - ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq); - if (ret != 0) { - /* - * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; - * The ALUA additional sense code qualifier (ASCQ) is determined - * by the ALUA primary or secondary access state.. - */ - if (ret > 0) { - pr_debug("[%s]: ALUA TG Port not available," - " SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n", - cmd->se_tfo->get_fabric_name(), alua_ascq); + for (;;) { + struct se_cmd *cmd; - transport_set_sense_codes(cmd, 0x04, alua_ascq); - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY; - return -EINVAL; - } - goto out_invalid_cdb_field; - } - /* - * Check status for SPC-3 Persistent Reservations - */ - if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type) != 0) { - if (su_dev->t10_pr.pr_ops.t10_seq_non_holder( - cmd, cdb, pr_reg_type) != 0) { - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; - cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EBUSY; - } - /* - * This means the CDB is allowed for the SCSI Initiator port - * when said port is *NOT* holding the legacy SPC-2 or - * SPC-3 Persistent Reservation. - */ - } - - /* - * If we operate in passthrough mode we skip most CDB emulation and - * instead hand the commands down to the physical SCSI device. - */ - passthrough = - (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV); - - switch (cdb[0]) { - case READ_6: - sectors = transport_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case READ_10: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case READ_12: - sectors = transport_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case READ_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_64(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case WRITE_6: - sectors = transport_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case WRITE_10: - case WRITE_VERIFY: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case WRITE_12: - sectors = transport_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case WRITE_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_64(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - break; - case XDWRITEREAD_10: - if ((cmd->data_direction != DMA_TO_DEVICE) || - !(cmd->se_cmd_flags & SCF_BIDI)) - goto out_invalid_cdb_field; - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - - /* - * Do now allow BIDI commands for passthrough mode. - */ - if (passthrough) - goto out_unsupported_cdb; - - /* - * Setup BIDI XOR callback to be run after I/O completion. - */ - cmd->transport_complete_callback = &transport_xor_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - break; - case VARIABLE_LENGTH_CMD: - service_action = get_unaligned_be16(&cdb[8]); - switch (service_action) { - case XDWRITEREAD_32: - sectors = transport_get_sectors_32(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - /* - * Use WRITE_32 and READ_32 opcodes for the emulated - * XDWRITE_READ_32 logic. - */ - cmd->t_task_lba = transport_lba_64_ext(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - - /* - * Do now allow BIDI commands for passthrough mode. - */ - if (passthrough) - goto out_unsupported_cdb; - - /* - * Setup BIDI XOR callback to be run during after I/O - * completion. - */ - cmd->transport_complete_callback = &transport_xor_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - break; - case WRITE_SAME_32: - sectors = transport_get_sectors_32(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" - " supported\n"); - goto out_invalid_cdb_field; - } - - cmd->t_task_lba = get_unaligned_be64(&cdb[12]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - - if (target_check_write_same_discard(&cdb[10], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - default: - pr_err("VARIABLE_LENGTH_CMD service action" - " 0x%04x not supported\n", service_action); - goto out_unsupported_cdb; - } - break; - case MAINTENANCE_IN: - if (dev->transport->get_device_type(dev) != TYPE_ROM) { - /* MAINTENANCE_IN from SCC-2 */ - /* - * Check for emulated MI_REPORT_TARGET_PGS. - */ - if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && - su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_cmd = - target_emulate_report_target_port_groups; - } - size = (cdb[6] << 24) | (cdb[7] << 16) | - (cdb[8] << 8) | cdb[9]; - } else { - /* GPCMD_SEND_KEY from multi media commands */ - size = (cdb[8] << 8) + cdb[9]; - } - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case MODE_SELECT: - size = cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case MODE_SELECT_10: - size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case MODE_SENSE: - size = cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - if (!passthrough) - cmd->execute_cmd = target_emulate_modesense; - break; - case MODE_SENSE_10: - size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - if (!passthrough) - cmd->execute_cmd = target_emulate_modesense; - break; - case GPCMD_READ_BUFFER_CAPACITY: - case GPCMD_SEND_OPC: - case LOG_SELECT: - case LOG_SENSE: - size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case READ_BLOCK_LIMITS: - size = READ_BLOCK_LEN; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case GPCMD_GET_CONFIGURATION: - case GPCMD_READ_FORMAT_CAPACITIES: - case GPCMD_READ_DISC_INFO: - case GPCMD_READ_TRACK_RZONE_INFO: - size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case PERSISTENT_RESERVE_IN: - if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->execute_cmd = target_scsi3_emulate_pr_in; - size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case PERSISTENT_RESERVE_OUT: - if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->execute_cmd = target_scsi3_emulate_pr_out; - size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case GPCMD_MECHANISM_STATUS: - case GPCMD_READ_DVD_STRUCTURE: - size = (cdb[8] << 8) + cdb[9]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case READ_POSITION: - size = READ_POSITION_LEN; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case MAINTENANCE_OUT: - if (dev->transport->get_device_type(dev) != TYPE_ROM) { - /* MAINTENANCE_OUT from SCC-2 - * - * Check for emulated MO_SET_TARGET_PGS. - */ - if (cdb[1] == MO_SET_TARGET_PGS && - su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_cmd = - target_emulate_set_target_port_groups; - } - - size = (cdb[6] << 24) | (cdb[7] << 16) | - (cdb[8] << 8) | cdb[9]; - } else { - /* GPCMD_REPORT_KEY from multi media commands */ - size = (cdb[8] << 8) + cdb[9]; - } - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case INQUIRY: - size = (cdb[3] << 8) + cdb[4]; - /* - * Do implict HEAD_OF_QUEUE processing for INQUIRY. - * See spc4r17 section 5.3 - */ - if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) - cmd->sam_task_attr = MSG_HEAD_TAG; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - if (!passthrough) - cmd->execute_cmd = target_emulate_inquiry; - break; - case READ_BUFFER: - size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case READ_CAPACITY: - size = READ_CAP_LEN; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - if (!passthrough) - cmd->execute_cmd = target_emulate_readcapacity; - break; - case READ_MEDIA_SERIAL_NUMBER: - case SECURITY_PROTOCOL_IN: - case SECURITY_PROTOCOL_OUT: - size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case SERVICE_ACTION_IN: - switch (cmd->t_task_cdb[1] & 0x1f) { - case SAI_READ_CAPACITY_16: - if (!passthrough) - cmd->execute_cmd = - target_emulate_readcapacity_16; - break; - default: - if (passthrough) - break; - - pr_err("Unsupported SA: 0x%02x\n", - cmd->t_task_cdb[1] & 0x1f); - goto out_invalid_cdb_field; - } - /*FALLTHROUGH*/ - case ACCESS_CONTROL_IN: - case ACCESS_CONTROL_OUT: - case EXTENDED_COPY: - case READ_ATTRIBUTE: - case RECEIVE_COPY_RESULTS: - case WRITE_ATTRIBUTE: - size = (cdb[10] << 24) | (cdb[11] << 16) | - (cdb[12] << 8) | cdb[13]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case RECEIVE_DIAGNOSTIC: - case SEND_DIAGNOSTIC: - size = (cdb[3] << 8) | cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; -/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */ -#if 0 - case GPCMD_READ_CD: - sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - size = (2336 * sectors); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; -#endif - case READ_TOC: - size = cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case REQUEST_SENSE: - size = cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - if (!passthrough) - cmd->execute_cmd = target_emulate_request_sense; - break; - case READ_ELEMENT_STATUS: - size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case WRITE_BUFFER: - size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case RESERVE: - case RESERVE_10: - /* - * The SPC-2 RESERVE does not contain a size in the SCSI CDB. - * Assume the passthrough or $FABRIC_MOD will tell us about it. - */ - if (cdb[0] == RESERVE_10) - size = (cdb[7] << 8) | cdb[8]; - else - size = cmd->data_length; - - /* - * Setup the legacy emulated handler for SPC-2 and - * >= SPC-3 compatible reservation handling (CRH=1) - * Otherwise, we assume the underlying SCSI logic is - * is running in SPC_PASSTHROUGH, and wants reservations - * emulation disabled. - */ - if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) - cmd->execute_cmd = target_scsi2_reservation_reserve; - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - break; - case RELEASE: - case RELEASE_10: - /* - * The SPC-2 RELEASE does not contain a size in the SCSI CDB. - * Assume the passthrough or $FABRIC_MOD will tell us about it. - */ - if (cdb[0] == RELEASE_10) - size = (cdb[7] << 8) | cdb[8]; - else - size = cmd->data_length; - - if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) - cmd->execute_cmd = target_scsi2_reservation_release; - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - break; - case SYNCHRONIZE_CACHE: - case SYNCHRONIZE_CACHE_16: - /* - * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE - */ - if (cdb[0] == SYNCHRONIZE_CACHE) { - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - cmd->t_task_lba = transport_lba_32(cdb); - } else { - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - cmd->t_task_lba = transport_lba_64(cdb); - } - if (sector_ret) - goto out_unsupported_cdb; - - size = transport_get_size(sectors, cdb, cmd); - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - - if (passthrough) + spin_lock(&dev->delayed_cmd_lock); + if (list_empty(&dev->delayed_cmd_list)) { + spin_unlock(&dev->delayed_cmd_lock); break; - - /* - * Check to ensure that LBA + Range does not exceed past end of - * device for IBLOCK and FILEIO ->do_sync_cache() backend calls - */ - if ((cmd->t_task_lba != 0) || (sectors != 0)) { - if (transport_cmd_get_valid_sectors(cmd) < 0) - goto out_invalid_cdb_field; - } - cmd->execute_cmd = target_emulate_synchronize_cache; - break; - case UNMAP: - size = get_unaligned_be16(&cdb[7]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - if (!passthrough) - cmd->execute_cmd = target_emulate_unmap; - break; - case WRITE_SAME_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; } - cmd->t_task_lba = get_unaligned_be64(&cdb[2]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - - if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - case WRITE_SAME: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; + cmd = list_entry(dev->delayed_cmd_list.next, + struct se_cmd, se_delayed_node); + list_del(&cmd->se_delayed_node); + spin_unlock(&dev->delayed_cmd_lock); - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; - } + __target_execute_cmd(cmd); - cmd->t_task_lba = get_unaligned_be32(&cdb[2]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - /* - * Follow sbcr26 with WRITE_SAME (10) and check for the existence - * of byte 1 bit 3 UNMAP instead of original reserved field - */ - if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - case ALLOW_MEDIUM_REMOVAL: - case ERASE: - case REZERO_UNIT: - case SEEK_10: - case SPACE: - case START_STOP: - case TEST_UNIT_READY: - case VERIFY: - case WRITE_FILEMARKS: - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - if (!passthrough) - cmd->execute_cmd = target_emulate_noop; - break; - case GPCMD_CLOSE_TRACK: - case INITIALIZE_ELEMENT_STATUS: - case GPCMD_LOAD_UNLOAD: - case GPCMD_SET_SPEED: - case MOVE_MEDIUM: - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - break; - case REPORT_LUNS: - cmd->execute_cmd = target_report_luns; - size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - /* - * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS - * See spc4r17 section 5.3 - */ - if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) - cmd->sam_task_attr = MSG_HEAD_TAG; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case GET_EVENT_STATUS_NOTIFICATION: - size = (cdb[7] << 8) | cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - case ATA_16: - /* Only support ATA passthrough to pSCSI backends.. */ - if (!passthrough) - goto out_unsupported_cdb; - - /* T_LENGTH */ - switch (cdb[2] & 0x3) { - case 0x0: - sectors = 0; - break; - case 0x1: - sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4]; - break; - case 0x2: - sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6]; + if (cmd->sam_task_attr == MSG_ORDERED_TAG) break; - case 0x3: - pr_err("T_LENGTH=0x3 not supported for ATA_16\n"); - goto out_invalid_cdb_field; - } - - /* BYTE_BLOCK */ - if (cdb[2] & 0x4) { - /* BLOCK T_TYPE: 512 or sector */ - size = sectors * ((cdb[2] & 0x10) ? - dev->se_sub_dev->se_dev_attrib.block_size : 512); - } else { - /* BYTE */ - size = sectors; - } - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; - break; - default: - pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" - " 0x%02x, sending CHECK_CONDITION.\n", - cmd->se_tfo->get_fabric_name(), cdb[0]); - goto out_unsupported_cdb; - } - - if (cmd->unknown_data_length) - cmd->data_length = size; - - if (size != cmd->data_length) { - pr_warn("TARGET_CORE[%s]: Expected Transfer Length:" - " %u does not match SCSI CDB Length: %u for SAM Opcode:" - " 0x%02x\n", cmd->se_tfo->get_fabric_name(), - cmd->data_length, size, cdb[0]); - - cmd->cmd_spdtl = size; - - if (cmd->data_direction == DMA_TO_DEVICE) { - pr_err("Rejecting underflow/overflow" - " WRITE data\n"); - goto out_invalid_cdb_field; - } - /* - * Reject READ_* or WRITE_* with overflow/underflow for - * type SCF_SCSI_DATA_SG_IO_CDB. - */ - if (!ret && (dev->se_sub_dev->se_dev_attrib.block_size != 512)) { - pr_err("Failing OVERFLOW/UNDERFLOW for LBA op" - " CDB on non 512-byte sector setup subsystem" - " plugin: %s\n", dev->transport->name); - /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ - goto out_invalid_cdb_field; - } - - if (size > cmd->data_length) { - cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; - cmd->residual_count = (size - cmd->data_length); - } else { - cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; - cmd->residual_count = (cmd->data_length - size); - } - cmd->data_length = size; } - - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds fabric_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.fabric_max_sectors); - goto out_invalid_cdb_field; - } - if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds backend hw_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.hw_max_sectors); - goto out_invalid_cdb_field; - } - } - - /* reject any command that we don't have a handler for */ - if (!(passthrough || cmd->execute_cmd || - (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) - goto out_unsupported_cdb; - - transport_set_supported_SAM_opcode(cmd); - return ret; - -out_unsupported_cdb: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -EINVAL; -out_invalid_cdb_field: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; } /* @@ -3052,8 +1906,6 @@ out_invalid_cdb_field: static void transport_complete_task_attr(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_cmd *cmd_p, *cmd_tmp; - int new_active_tasks = 0; if (cmd->sam_task_attr == MSG_SIMPLE_TAG) { atomic_dec(&dev->simple_cmds); @@ -3075,38 +1927,8 @@ static void transport_complete_task_attr(struct se_cmd *cmd) pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:" " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id); } - /* - * Process all commands up to the last received - * ORDERED task attribute which requires another blocking - * boundary - */ - spin_lock(&dev->delayed_cmd_lock); - list_for_each_entry_safe(cmd_p, cmd_tmp, - &dev->delayed_cmd_list, se_delayed_node) { - - list_del(&cmd_p->se_delayed_node); - spin_unlock(&dev->delayed_cmd_lock); - - pr_debug("Calling add_tasks() for" - " cmd_p: 0x%02x Task Attr: 0x%02x" - " Dormant -> Active, se_ordered_id: %u\n", - cmd_p->t_task_cdb[0], - cmd_p->sam_task_attr, cmd_p->se_ordered_id); - target_add_to_execute_list(cmd_p); - new_active_tasks++; - - spin_lock(&dev->delayed_cmd_lock); - if (cmd_p->sam_task_attr == MSG_ORDERED_TAG) - break; - } - spin_unlock(&dev->delayed_cmd_lock); - /* - * If new tasks have become active, wake up the transport thread - * to do the processing of the Active tasks. - */ - if (new_active_tasks != 0) - wake_up_interruptible(&dev->dev_queue_obj.thread_wq); + target_restart_delayed_cmds(dev); } static void transport_complete_qf(struct se_cmd *cmd) @@ -3365,31 +2187,27 @@ int transport_generic_map_mem_to_cmd( if (!sgl || !sgl_count) return 0; - if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) || - (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) { - /* - * Reject SCSI data overflow with map_mem_to_cmd() as incoming - * scatterlists already have been set to follow what the fabric - * passes for the original expected data transfer length. - */ - if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { - pr_warn("Rejecting SCSI DATA overflow for fabric using" - " SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n"); - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; - } + /* + * Reject SCSI data overflow with map_mem_to_cmd() as incoming + * scatterlists already have been set to follow what the fabric + * passes for the original expected data transfer length. + */ + if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + pr_warn("Rejecting SCSI DATA overflow for fabric using" + " SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n"); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; + } - cmd->t_data_sg = sgl; - cmd->t_data_nents = sgl_count; + cmd->t_data_sg = sgl; + cmd->t_data_nents = sgl_count; - if (sgl_bidi && sgl_bidi_count) { - cmd->t_bidi_data_sg = sgl_bidi; - cmd->t_bidi_data_nents = sgl_bidi_count; - } - cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; + if (sgl_bidi && sgl_bidi_count) { + cmd->t_bidi_data_sg = sgl_bidi; + cmd->t_bidi_data_nents = sgl_bidi_count; } - + cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; return 0; } EXPORT_SYMBOL(transport_generic_map_mem_to_cmd); @@ -3461,7 +2279,7 @@ transport_generic_get_mem(struct se_cmd *cmd) cmd->t_data_nents = nents; sg_init_table(cmd->t_data_sg, nents); - zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB ? 0 : __GFP_ZERO; + zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_CDB ? 0 : __GFP_ZERO; while (length) { u32 page_len = min_t(u32, length, PAGE_SIZE); @@ -3492,7 +2310,6 @@ out: */ int transport_generic_new_cmd(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; int ret = 0; /* @@ -3508,8 +2325,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd) } /* Workaround for handling zero-length control CDBs */ - if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && - !cmd->data_length) { + if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->data_length) { spin_lock_irq(&cmd->t_state_lock); cmd->t_state = TRANSPORT_COMPLETE; cmd->transport_state |= CMD_T_ACTIVE; @@ -3527,52 +2343,45 @@ int transport_generic_new_cmd(struct se_cmd *cmd) return 0; } - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib; - - if (transport_cmd_get_valid_sectors(cmd) < 0) - return -EINVAL; - - BUG_ON(cmd->data_length % attr->block_size); - BUG_ON(DIV_ROUND_UP(cmd->data_length, attr->block_size) > - attr->hw_max_sectors); - } - atomic_inc(&cmd->t_fe_count); /* - * For WRITEs, let the fabric know its buffer is ready. - * - * The command will be added to the execution queue after its write - * data has arrived. + * If this command is not a write we can execute it right here, + * for write buffers we need to notify the fabric driver first + * and let it call back once the write buffers are ready. */ - if (cmd->data_direction == DMA_TO_DEVICE) { - target_add_to_state_list(cmd); - return transport_generic_write_pending(cmd); + target_add_to_state_list(cmd); + if (cmd->data_direction != DMA_TO_DEVICE) { + target_execute_cmd(cmd); + return 0; } - /* - * Everything else but a WRITE, add the command to the execution queue. - */ - transport_execute_tasks(cmd); - return 0; + + spin_lock_irq(&cmd->t_state_lock); + cmd->t_state = TRANSPORT_WRITE_PENDING; + spin_unlock_irq(&cmd->t_state_lock); + + transport_cmd_check_stop(cmd, false); + + ret = cmd->se_tfo->write_pending(cmd); + if (ret == -EAGAIN || ret == -ENOMEM) + goto queue_full; + + if (ret < 0) + return ret; + return 1; out_fail: cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return -EINVAL; +queue_full: + pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); + cmd->t_state = TRANSPORT_COMPLETE_QF_WP; + transport_handle_queue_full(cmd, cmd->se_dev); + return 0; } EXPORT_SYMBOL(transport_generic_new_cmd); -/* transport_generic_process_write(): - * - * - */ -void transport_generic_process_write(struct se_cmd *cmd) -{ - transport_execute_tasks(cmd); -} -EXPORT_SYMBOL(transport_generic_process_write); - static void transport_write_pending_qf(struct se_cmd *cmd) { int ret; @@ -3585,43 +2394,6 @@ static void transport_write_pending_qf(struct se_cmd *cmd) } } -static int transport_generic_write_pending(struct se_cmd *cmd) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->t_state = TRANSPORT_WRITE_PENDING; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - /* - * Clear the se_cmd for WRITE_PENDING status in order to set - * CMD_T_ACTIVE so that transport_generic_handle_data can be called - * from HW target mode interrupt code. This is safe to be called - * with transport_off=1 before the cmd->se_tfo->write_pending - * because the se_cmd->se_lun pointer is not being cleared. - */ - transport_cmd_check_stop(cmd, 1, 0); - - /* - * Call the fabric write_pending function here to let the - * frontend know that WRITE buffers are ready. - */ - ret = cmd->se_tfo->write_pending(cmd); - if (ret == -EAGAIN || ret == -ENOMEM) - goto queue_full; - else if (ret < 0) - return ret; - - return 1; - -queue_full: - pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); - cmd->t_state = TRANSPORT_COMPLETE_QF_WP; - transport_handle_queue_full(cmd, cmd->se_dev); - return 0; -} - void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { @@ -3648,10 +2420,11 @@ EXPORT_SYMBOL(transport_generic_free_cmd); * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, - bool ack_kref) +static int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, + bool ack_kref) { unsigned long flags; + int ret = 0; kref_init(&se_cmd->cmd_kref); /* @@ -3665,11 +2438,17 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, } spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + if (se_sess->sess_tearing_down) { + ret = -ESHUTDOWN; + goto out; + } list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); se_cmd->check_release = 1; + +out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + return ret; } -EXPORT_SYMBOL(target_get_sess_cmd); static void target_release_cmd_kref(struct kref *kref) { @@ -3704,28 +2483,27 @@ int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) } EXPORT_SYMBOL(target_put_sess_cmd); -/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list - * @se_sess: session to split +/* target_sess_cmd_list_set_waiting - Flag all commands in + * sess_cmd_list to complete cmd_wait_comp. Set + * sess_tearing_down so no more commands are queued. + * @se_sess: session to flag */ -void target_splice_sess_cmd_list(struct se_session *se_sess) +void target_sess_cmd_list_set_waiting(struct se_session *se_sess) { struct se_cmd *se_cmd; unsigned long flags; - WARN_ON(!list_empty(&se_sess->sess_wait_list)); - INIT_LIST_HEAD(&se_sess->sess_wait_list); - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - se_sess->sess_tearing_down = 1; - list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); + WARN_ON(se_sess->sess_tearing_down); + se_sess->sess_tearing_down = 1; - list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) + list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) se_cmd->cmd_wait_set = 1; spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } -EXPORT_SYMBOL(target_splice_sess_cmd_list); +EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); /* target_wait_for_sess_cmds - Wait for outstanding descriptors * @se_sess: session to wait for active I/O @@ -3739,7 +2517,7 @@ void target_wait_for_sess_cmds( bool rc = false; list_for_each_entry_safe(se_cmd, tmp_cmd, - &se_sess->sess_wait_list, se_cmd_list) { + &se_sess->sess_cmd_list, se_cmd_list) { list_del(&se_cmd->se_cmd_list); pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" @@ -3791,26 +2569,20 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n", cmd->se_tfo->get_task_tag(cmd)); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_cmd_check_stop(cmd, 1, 0); + transport_cmd_check_stop(cmd, false); return -EPERM; } cmd->transport_state |= CMD_T_LUN_FE_STOP; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq); - // XXX: audit task_flags checks. spin_lock_irqsave(&cmd->t_state_lock, flags); if ((cmd->transport_state & CMD_T_BUSY) && (cmd->transport_state & CMD_T_SENT)) { if (!target_stop_cmd(cmd, &flags)) ret++; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - } else { - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - target_remove_from_execute_list(cmd); } + spin_unlock_irqrestore(&cmd->t_state_lock, flags); pr_debug("ConfigFS: cmd: %p stop tasks ret:" " %d\n", cmd, ret); @@ -3821,7 +2593,6 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) pr_debug("ConfigFS: ITT[0x%08x] - stopped cmd....\n", cmd->se_tfo->get_task_tag(cmd)); } - transport_remove_cmd_from_queue(cmd); return 0; } @@ -3840,11 +2611,6 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun) struct se_cmd, se_lun_node); list_del_init(&cmd->se_lun_node); - /* - * This will notify iscsi_target_transport.c: - * transport_cmd_check_stop() that a LUN shutdown is in - * progress for the iscsi_cmd_t. - */ spin_lock(&cmd->t_state_lock); pr_debug("SE_LUN[%d] - Setting cmd->transport" "_lun_stop for ITT: 0x%08x\n", @@ -3911,7 +2677,7 @@ check_cond: spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags); - transport_cmd_check_stop(cmd, 1, 0); + transport_cmd_check_stop(cmd, false); complete(&cmd->transport_lun_fe_stop_comp); spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags); continue; @@ -3967,10 +2733,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) spin_unlock_irqrestore(&cmd->t_state_lock, flags); return false; } - /* - * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE - * has been set in transport_set_supported_SAM_opcode(). - */ + if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -4028,8 +2791,6 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) spin_unlock_irqrestore(&cmd->t_state_lock, flags); - wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq); - wait_for_completion(&cmd->t_transport_stop_comp); spin_lock_irqsave(&cmd->t_state_lock, flags); @@ -4212,6 +2973,15 @@ int transport_send_check_condition_and_sense( /* WRITE PROTECTED */ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27; break; + case TCM_ADDRESS_OUT_OF_RANGE: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x21; + break; case TCM_CHECK_CONDITION_UNIT_ATTENTION: /* CURRENT ERROR */ buffer[offset] = 0x70; @@ -4312,8 +3082,9 @@ void transport_send_task_abort(struct se_cmd *cmd) cmd->se_tfo->queue_status(cmd); } -static int transport_generic_do_tmr(struct se_cmd *cmd) +static void target_tmr_work(struct work_struct *work) { + struct se_cmd *cmd = container_of(work, struct se_cmd, work); struct se_device *dev = cmd->se_dev; struct se_tmr_req *tmr = cmd->se_tmr_req; int ret; @@ -4349,80 +3120,13 @@ static int transport_generic_do_tmr(struct se_cmd *cmd) cmd->se_tfo->queue_tm_rsp(cmd); transport_cmd_check_stop_to_fabric(cmd); - return 0; } -/* transport_processing_thread(): - * - * - */ -static int transport_processing_thread(void *param) +int transport_generic_handle_tmr( + struct se_cmd *cmd) { - int ret; - struct se_cmd *cmd; - struct se_device *dev = param; - - while (!kthread_should_stop()) { - ret = wait_event_interruptible(dev->dev_queue_obj.thread_wq, - atomic_read(&dev->dev_queue_obj.queue_cnt) || - kthread_should_stop()); - if (ret < 0) - goto out; - -get_cmd: - cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj); - if (!cmd) - continue; - - switch (cmd->t_state) { - case TRANSPORT_NEW_CMD: - BUG(); - break; - case TRANSPORT_NEW_CMD_MAP: - if (!cmd->se_tfo->new_cmd_map) { - pr_err("cmd->se_tfo->new_cmd_map is" - " NULL for TRANSPORT_NEW_CMD_MAP\n"); - BUG(); - } - ret = cmd->se_tfo->new_cmd_map(cmd); - if (ret < 0) { - transport_generic_request_failure(cmd); - break; - } - ret = transport_generic_new_cmd(cmd); - if (ret < 0) { - transport_generic_request_failure(cmd); - break; - } - break; - case TRANSPORT_PROCESS_WRITE: - transport_generic_process_write(cmd); - break; - case TRANSPORT_PROCESS_TMR: - transport_generic_do_tmr(cmd); - break; - case TRANSPORT_COMPLETE_QF_WP: - transport_write_pending_qf(cmd); - break; - case TRANSPORT_COMPLETE_QF_OK: - transport_complete_qf(cmd); - break; - default: - pr_err("Unknown t_state: %d for ITT: 0x%08x " - "i_state: %d on SE LUN: %u\n", - cmd->t_state, - cmd->se_tfo->get_task_tag(cmd), - cmd->se_tfo->get_cmd_state(cmd), - cmd->se_lun->unpacked_lun); - BUG(); - } - - goto get_cmd; - } - -out: - WARN_ON(!list_empty(&dev->state_list)); - WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list)); - dev->process_thread = NULL; + INIT_WORK(&cmd->work, target_tmr_work); + queue_work(cmd->se_dev->tmr_wq, &cmd->work); return 0; } +EXPORT_SYMBOL(transport_generic_handle_tmr); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index f03fb9730f5..b9cb5006177 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -215,7 +215,7 @@ int ft_write_pending(struct se_cmd *se_cmd) */ if ((ep->xid <= lport->lro_xid) && (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { - if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) && + if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && lport->tt.ddp_target(lport, ep->xid, se_cmd->t_data_sg, se_cmd->t_data_nents)) @@ -230,6 +230,8 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + if (cmd->aborted) + return ~0; return fc_seq_exch(cmd->seq)->rxid; } @@ -541,9 +543,11 @@ static void ft_send_work(struct work_struct *work) * Use a single se_cmd->cmd_kref as we expect to release se_cmd * directly from ft_check_stop_free callback in response path. */ - target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, - &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), - ntohl(fcp->fc_dl), task_attr, data_dir, 0); + if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), + ntohl(fcp->fc_dl), task_attr, data_dir, 0)) + goto err; + pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); return; diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 071a505f98f..ad36ede1a1e 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -183,6 +183,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd) return ft_queue_status(se_cmd); } +static void ft_execute_work(struct work_struct *work) +{ + struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); + + target_execute_cmd(&cmd->se_cmd); +} + /* * Receive write data frame. */ @@ -307,8 +314,10 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) cmd->write_data_len += tlen; } last_frame: - if (cmd->write_data_len == se_cmd->data_length) - transport_generic_handle_data(se_cmd); + if (cmd->write_data_len == se_cmd->data_length) { + INIT_WORK(&cmd->work, ft_execute_work); + queue_work(cmd->sess->tport->tpg->workqueue, &cmd->work); + } drop: fc_frame_free(fp); } diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index c46439c8dd7..5444866e13e 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -294,7 +294,7 @@ static int bot_send_write_request(struct usbg_cmd *cmd) pr_err("%s(%d)\n", __func__, __LINE__); wait_for_completion(&cmd->write_complete); - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); cleanup: return ret; } @@ -725,7 +725,7 @@ static int uasp_send_write_request(struct usbg_cmd *cmd) } wait_for_completion(&cmd->write_complete); - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); cleanup: return ret; } @@ -1065,16 +1065,20 @@ static void usbg_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense); - - transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); - return; + goto out; } - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); + 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0) + goto out; + + return; + +out: + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); } static int usbg_submit_command(struct f_uas *fu, @@ -1177,16 +1181,20 @@ static void bot_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense); - - transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); - return; + goto out; } - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - cmd->data_len, cmd->prio_attr, dir, 0); + cmd->data_len, cmd->prio_attr, dir, 0) < 0) + goto out; + + return; + +out: + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); } static int bot_submit_command(struct f_uas *fu, @@ -1400,19 +1408,6 @@ static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) return 1; } -static int usbg_new_cmd(struct se_cmd *se_cmd) -{ - struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, - se_cmd); - int ret; - - ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf); - if (ret) - return ret; - - return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0); -} - static void usbg_cmd_release(struct kref *ref) { struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd, @@ -1902,7 +1897,6 @@ static struct target_core_fabric_ops usbg_ops = { .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl, .tpg_release_fabric_acl = usbg_release_fabric_acl, .tpg_get_inst_index = usbg_tpg_get_inst_index, - .new_cmd_map = usbg_new_cmd, .release_cmd = usbg_release_cmd, .shutdown_session = usbg_shutdown_session, .close_session = usbg_close_session, |