Commit b7aae4a9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regmap-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap updates from Mark Brown:
 "This has been a very busy release for regmap, not just in cleaning up
  the mess we got ourselves into with the endianness handling but also
  in other areas too:

   - Fixes for the endianness handling so that we now explicitly default
     to little endian (the code used to do this by accident).  This
     fixes handling of explictly specified endianness on big endian
     systems.

   - Optimisation of the implementation of register striding.

   - A refectoring of the _update_bits() code to reduce duplication.

   - Fixes and enhancements for the interrupt implementation which make
     it easier to use in a wider range of systems"

* tag 'regmap-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (28 commits)
  regmap: irq: add devm apis for regmap_{add,del}_irq_chip
  regmap: replace regmap_write_bits()
  regmap: irq: Enable irq retriggering for nested irqs
  regmap: add regmap_fields_force_xxx() macros
  regmap: add regmap_field_force_xxx() macros
  regmap: merge regmap_fields_update_bits() into macro
  regmap: merge regmap_fields_write() into macro
  regmap: add regmap_fields_update_bits_base()
  regmap: merge regmap_field_update_bits() into macro
  regmap: merge regmap_field_write() into macro
  regmap: add regmap_field_update_bits_base()
  regmap: merge regmap_update_bits_check_async() into macro
  regmap: merge regmap_update_bits_check() into macro
  regmap: merge regmap_update_bits_async() into macro
  regmap: merge regmap_update_bits() into macro
  regmap: add regmap_update_bits_base()
  regcache: flat: Introduce register strider order
  regcache: Introduce the index parsing API by stride order
  regmap: core: Introduce register stride order
  regmap: irq: add devm apis for regmap_{add,del}_irq_chip
  ...
parents ff280e36 d25263d9
...@@ -5,15 +5,18 @@ Index Device Endianness properties ...@@ -5,15 +5,18 @@ Index Device Endianness properties
--------------------------------------------------- ---------------------------------------------------
1 BE 'big-endian' 1 BE 'big-endian'
2 LE 'little-endian' 2 LE 'little-endian'
3 Native 'native-endian'
For one device driver, which will run in different scenarios above For one device driver, which will run in different scenarios above
on different SoCs using the devicetree, we need one way to simplify on different SoCs using the devicetree, we need one way to simplify
this. this.
Required properties: Optional properties:
- {big,little}-endian: these are boolean properties, if absent - {big,little,native}-endian: these are boolean properties, if absent
meaning that the CPU and the Device are in the same endianness mode, then the implementation will choose a default based on the device
these properties are for register values and all the buffers only. being controlled. These properties are for register values and all
the buffers only. Native endian means that the CPU and device have
the same endianness.
Examples: Examples:
Scenario 1 : CPU in LE mode & device in LE mode. Scenario 1 : CPU in LE mode & device in LE mode.
......
...@@ -74,7 +74,7 @@ uart0: serial@10000100 { ...@@ -74,7 +74,7 @@ uart0: serial@10000100 {
timer: timer@10000040 { timer: timer@10000040 {
compatible = "syscon"; compatible = "syscon";
reg = <0x10000040 0x2c>; reg = <0x10000040 0x2c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -54,7 +54,7 @@ ubus { ...@@ -54,7 +54,7 @@ ubus {
periph_cntl: syscon@10000000 { periph_cntl: syscon@10000000 {
compatible = "syscon"; compatible = "syscon";
reg = <0x10000000 0x14>; reg = <0x10000000 0x14>;
little-endian; native-endian;
}; };
reboot: syscon-reboot@10000008 { reboot: syscon-reboot@10000008 {
......
...@@ -98,7 +98,7 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -98,7 +98,7 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7125-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>; reg = <0x404000 0x60c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -118,7 +118,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -118,7 +118,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7346-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -112,7 +112,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -112,7 +112,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7358-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -112,7 +112,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -112,7 +112,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7360-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -118,7 +118,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 { ...@@ -118,7 +118,7 @@ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7362-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -99,7 +99,7 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -99,7 +99,7 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7420-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>; reg = <0x404000 0x60c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -100,7 +100,7 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -100,7 +100,7 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -114,7 +114,7 @@ upg_irq0_intc: upg_irq0_intc@406780 { ...@@ -114,7 +114,7 @@ upg_irq0_intc: upg_irq0_intc@406780 {
sun_top_ctrl: syscon@404000 { sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon"; compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>; reg = <0x404000 0x51c>;
little-endian; native-endian;
}; };
reboot { reboot {
......
...@@ -110,6 +110,7 @@ struct regmap { ...@@ -110,6 +110,7 @@ struct regmap {
/* number of bits to (left) shift the reg value when formatting*/ /* number of bits to (left) shift the reg value when formatting*/
int reg_shift; int reg_shift;
int reg_stride; int reg_stride;
int reg_stride_order;
/* regcache specific members */ /* regcache specific members */
const struct regcache_ops *cache_ops; const struct regcache_ops *cache_ops;
...@@ -263,4 +264,19 @@ static inline const char *regmap_name(const struct regmap *map) ...@@ -263,4 +264,19 @@ static inline const char *regmap_name(const struct regmap *map)
return map->name; return map->name;
} }
static inline unsigned int regmap_get_offset(const struct regmap *map,
unsigned int index)
{
if (map->reg_stride_order >= 0)
return index << map->reg_stride_order;
else
return index * map->reg_stride;
}
static inline unsigned int regcache_get_index_by_order(const struct regmap *map,
unsigned int reg)
{
return reg >> map->reg_stride_order;
}
#endif #endif
...@@ -16,20 +16,30 @@ ...@@ -16,20 +16,30 @@
#include "internal.h" #include "internal.h"
static inline unsigned int regcache_flat_get_index(const struct regmap *map,
unsigned int reg)
{
return regcache_get_index_by_order(map, reg);
}
static int regcache_flat_init(struct regmap *map) static int regcache_flat_init(struct regmap *map)
{ {
int i; int i;
unsigned int *cache; unsigned int *cache;
map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int), if (!map || map->reg_stride_order < 0)
GFP_KERNEL); return -EINVAL;
map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
+ 1, sizeof(unsigned int), GFP_KERNEL);
if (!map->cache) if (!map->cache)
return -ENOMEM; return -ENOMEM;
cache = map->cache; cache = map->cache;
for (i = 0; i < map->num_reg_defaults; i++) for (i = 0; i < map->num_reg_defaults; i++)
cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def; cache[regcache_flat_get_index(map, map->reg_defaults[i].reg)] =
map->reg_defaults[i].def;
return 0; return 0;
} }
...@@ -47,7 +57,7 @@ static int regcache_flat_read(struct regmap *map, ...@@ -47,7 +57,7 @@ static int regcache_flat_read(struct regmap *map,
{ {
unsigned int *cache = map->cache; unsigned int *cache = map->cache;
*value = cache[reg]; *value = cache[regcache_flat_get_index(map, reg)];
return 0; return 0;
} }
...@@ -57,7 +67,7 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg, ...@@ -57,7 +67,7 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg,
{ {
unsigned int *cache = map->cache; unsigned int *cache = map->cache;
cache[reg] = value; cache[regcache_flat_get_index(map, reg)] = value;
return 0; return 0;
} }
......
...@@ -30,7 +30,7 @@ static int regcache_hw_init(struct regmap *map) ...@@ -30,7 +30,7 @@ static int regcache_hw_init(struct regmap *map)
int i, j; int i, j;
int ret; int ret;
int count; int count;
unsigned int val; unsigned int reg, val;
void *tmp_buf; void *tmp_buf;
if (!map->num_reg_defaults_raw) if (!map->num_reg_defaults_raw)
...@@ -57,7 +57,7 @@ static int regcache_hw_init(struct regmap *map) ...@@ -57,7 +57,7 @@ static int regcache_hw_init(struct regmap *map)
bool cache_bypass = map->cache_bypass; bool cache_bypass = map->cache_bypass;
dev_warn(map->dev, "No cache defaults, reading back from HW\n"); dev_warn(map->dev, "No cache defaults, reading back from HW\n");
/* Bypass the cache access till data read from HW*/ /* Bypass the cache access till data read from HW */
map->cache_bypass = true; map->cache_bypass = true;
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
if (!tmp_buf) { if (!tmp_buf) {
...@@ -65,29 +65,48 @@ static int regcache_hw_init(struct regmap *map) ...@@ -65,29 +65,48 @@ static int regcache_hw_init(struct regmap *map)
goto err_free; goto err_free;
} }
ret = regmap_raw_read(map, 0, tmp_buf, ret = regmap_raw_read(map, 0, tmp_buf,
map->num_reg_defaults_raw); map->cache_size_raw);
map->cache_bypass = cache_bypass; map->cache_bypass = cache_bypass;
if (ret < 0) if (ret == 0) {
goto err_cache_free; map->reg_defaults_raw = tmp_buf;
map->cache_free = 1;
map->reg_defaults_raw = tmp_buf; } else {
map->cache_free = 1; kfree(tmp_buf);
}
} }
/* fill the reg_defaults */ /* fill the reg_defaults */
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
if (regmap_volatile(map, i * map->reg_stride)) reg = i * map->reg_stride;
if (!regmap_readable(map, reg))
continue; continue;
val = regcache_get_val(map, map->reg_defaults_raw, i);
map->reg_defaults[j].reg = i * map->reg_stride; if (regmap_volatile(map, reg))
continue;
if (map->reg_defaults_raw) {
val = regcache_get_val(map, map->reg_defaults_raw, i);
} else {
bool cache_bypass = map->cache_bypass;
map->cache_bypass = true;
ret = regmap_read(map, reg, &val);
map->cache_bypass = cache_bypass;
if (ret != 0) {
dev_err(map->dev, "Failed to read %d: %d\n",
reg, ret);
goto err_free;
}
}
map->reg_defaults[j].reg = reg;
map->reg_defaults[j].def = val; map->reg_defaults[j].def = val;
j++; j++;
} }
return 0; return 0;
err_cache_free:
kfree(tmp_buf);
err_free: err_free:
kfree(map->reg_defaults); kfree(map->reg_defaults);
......
...@@ -379,6 +379,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, ...@@ -379,6 +379,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
irq_set_chip_data(virq, data); irq_set_chip_data(virq, data);
irq_set_chip(virq, &data->irq_chip); irq_set_chip(virq, &data->irq_chip);
irq_set_nested_thread(virq, 1); irq_set_nested_thread(virq, 1);
irq_set_parent(virq, data->irq);
irq_set_noprobe(virq); irq_set_noprobe(virq);
return 0; return 0;
...@@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip); ...@@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
* *
* @irq: Primary IRQ for the device * @irq: Primary IRQ for the device
* @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
*
* This function also dispose all mapped irq on chip.
*/ */
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
{ {
unsigned int virq;
int hwirq;
if (!d) if (!d)
return; return;
free_irq(irq, d); free_irq(irq, d);
/* Dispose all virtual irq from irq domain before removing it */
for (hwirq = 0; hwirq < d->chip->num_irqs; hwirq++) {
/* Ignore hwirq if holes in the IRQ list */
if (!d->chip->irqs[hwirq].mask)
continue;
/*
* Find the virtual irq of hwirq on chip and if it is
* there then dispose it
*/
virq = irq_find_mapping(d->domain, hwirq);
if (virq)
irq_dispose_mapping(virq);
}
irq_domain_remove(d->domain); irq_domain_remove(d->domain);
kfree(d->type_buf); kfree(d->type_buf);
kfree(d->type_buf_def); kfree(d->type_buf_def);
...@@ -674,6 +696,88 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) ...@@ -674,6 +696,88 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
} }
EXPORT_SYMBOL_GPL(regmap_del_irq_chip); EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
static void devm_regmap_irq_chip_release(struct device *dev, void *res)
{
struct regmap_irq_chip_data *d = *(struct regmap_irq_chip_data **)res;
regmap_del_irq_chip(d->irq, d);
}
static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)
{
struct regmap_irq_chip_data **r = res;
if (!r || !*r) {
WARN_ON(!r || !*r);
return 0;
}
return *r == data;
}
/**
* devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip()
*
* @dev: The device pointer on which irq_chip belongs to.
* @map: The regmap for the device.
* @irq: The IRQ the device uses to signal interrupts
* @irq_flags: The IRQF_ flags to use for the primary interrupt.
* @chip: Configuration for the interrupt controller.
* @data: Runtime data structure for the controller, allocated on success
*
* Returns 0 on success or an errno on failure.
*
* The regmap_irq_chip data automatically be released when the device is
* unbound.
*/
int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
int irq_flags, int irq_base,
const struct regmap_irq_chip *chip,
struct regmap_irq_chip_data **data)
{
struct regmap_irq_chip_data **ptr, *d;
int ret;
ptr = devres_alloc(devm_regmap_irq_chip_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = regmap_add_irq_chip(map, irq, irq_flags, irq_base,
chip, &d);
if (ret < 0) {
devres_free(ptr);
return ret;
}
*ptr = d;
devres_add(dev, ptr);
*data = d;
return 0;
}
EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip);
/**
* devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip()
*
* @dev: Device for which which resource was allocated.
* @irq: Primary IRQ for the device
* @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
*/
void devm_regmap_del_irq_chip(struct device *dev, int irq,
struct regmap_irq_chip_data *data)
{
int rc;
WARN_ON(irq != data->irq);
rc = devres_release(dev, devm_regmap_irq_chip_release,
devm_regmap_irq_chip_match, data);
if (rc != 0)
WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip);
/** /**
* regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
* *
......
...@@ -25,26 +25,14 @@ ...@@ -25,26 +25,14 @@
struct regmap_mmio_context { struct regmap_mmio_context {
void __iomem *regs; void __iomem *regs;
unsigned reg_bytes;
unsigned val_bytes; unsigned val_bytes;
unsigned pad_bytes;
struct clk *clk; struct clk *clk;
};
static inline void regmap_mmio_regsize_check(size_t reg_size) void (*reg_write)(struct regmap_mmio_context *ctx,
{ unsigned int reg, unsigned int val);
switch (reg_size) { unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
case 1: unsigned int reg);
case 2: };
case 4:
#ifdef CONFIG_64BIT
case 8:
#endif
break;
default:
BUG();
}
}
static int regmap_mmio_regbits_check(size_t reg_bits) static int regmap_mmio_regbits_check(size_t reg_bits)
{ {
...@@ -88,72 +76,62 @@ static int regmap_mmio_get_min_stride(size_t val_bits) ...@@ -88,72 +76,62 @@ static int regmap_mmio_get_min_stride(size_t val_bits)
return min_stride; return min_stride;
} }
static inline void regmap_mmio_count_check(size_t count, u32 offset) static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
unsigned int reg,
unsigned int val)
{
writeb(val, ctx->regs + reg);
}
static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
unsigned int reg,
unsigned int val)
{ {
BUG_ON(count <= offset); writew(val, ctx->regs + reg);
} }
static inline unsigned int static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
regmap_mmio_get_offset(const void *reg, size_t reg_size) unsigned int reg,
unsigned int val)
{ {
switch (reg_size) { iowrite16be(val, ctx->regs + reg);
case 1: }
return *(u8 *)reg;
case 2: static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
return *(u16 *)reg; unsigned int reg,
case 4: unsigned int val)
return *(u32 *)reg; {
writel(val, ctx->regs + reg);
}
static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
unsigned int reg,
unsigned int val)
{
iowrite32be(val, ctx->regs + reg);
}
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
case 8: static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
return *(u64 *)reg; unsigned int reg,
#endif unsigned int val)
default: {
BUG(); writeq(val, ctx->regs + reg);
}
} }
#endif
static int regmap_mmio_gather_write(void *context, static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{ {
struct regmap_mmio_context *ctx = context; struct regmap_mmio_context *ctx = context;
unsigned int offset;
int ret; int ret;
regmap_mmio_regsize_check(reg_size);
if (!IS_ERR(ctx->clk)) { if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk); ret = clk_enable(ctx->clk);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
offset = regmap_mmio_get_offset(reg, reg_size); ctx->reg_write(ctx, reg, val);
while (val_size) {
switch (ctx->val_bytes) {
case 1:
writeb(*(u8 *)val, ctx->regs + offset);
break;
case 2:
writew(*(u16 *)val, ctx->regs + offset);
break;
case 4:
writel(*(u32 *)val, ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
writeq(*(u64 *)val, ctx->regs + offset);
break;
#endif
default:
/* Should be caught by regmap_mmio_check_config */
BUG();
}
val_size -= ctx->val_bytes;
val += ctx->val_bytes;
offset += ctx->val_bytes;
}
if (!IS_ERR(ctx->clk)) if (!IS_ERR(ctx->clk))
clk_disable(ctx->clk); clk_disable(ctx->clk);
...@@ -161,59 +139,56 @@ static int regmap_mmio_gather_write(void *context, ...@@ -161,59 +139,56 @@ static int regmap_mmio_gather_write(void *context,
return 0; return 0;
} }
static int regmap_mmio_write(void *context, const void *data, size_t count) static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
unsigned int reg)
{ {
struct regmap_mmio_context *ctx = context; return readb(ctx->regs + reg);
unsigned int offset = ctx->reg_bytes + ctx->pad_bytes; }
static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
unsigned int reg)
{
return readw(ctx->regs + reg);
}
static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
unsigned int reg)
{
return ioread16be(ctx->regs + reg);
}
static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
unsigned int reg)
{
return readl(ctx->regs + reg);
}
regmap_mmio_count_check(count, offset); static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
unsigned int reg)
{
return ioread32be(ctx->regs + reg);
}
return regmap_mmio_gather_write(context, data, ctx->reg_bytes, #ifdef CONFIG_64BIT
data + offset, count - offset); static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
unsigned int reg)
{
return readq(ctx->regs + reg);
} }
#endif
static int regmap_mmio_read(void *context, static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
const void *reg, size_t reg_size,
void *val, size_t val_size)
{ {
struct regmap_mmio_context *ctx = context; struct regmap_mmio_context *ctx = context;
unsigned int offset;
int ret; int ret;
regmap_mmio_regsize_check(reg_size);
if (!IS_ERR(ctx->clk)) { if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk); ret = clk_enable(ctx->clk);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
offset = regmap_mmio_get_offset(reg, reg_size); *val = ctx->reg_read(ctx, reg);
while (val_size) {
switch (ctx->val_bytes) {
case 1:
*(u8 *)val = readb(ctx->regs + offset);
break;
case 2:
*(u16 *)val = readw(ctx->regs + offset);
break;
case 4:
*(u32 *)val = readl(ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
*(u64 *)val = readq(ctx->regs + offset);
break;
#endif
default:
/* Should be caught by regmap_mmio_check_config */
BUG();
}
val_size -= ctx->val_bytes;
val += ctx->val_bytes;
offset += ctx->val_bytes;
}
if (!IS_ERR(ctx->clk)) if (!IS_ERR(ctx->clk))
clk_disable(ctx->clk); clk_disable(ctx->clk);
...@@ -232,14 +207,11 @@ static void regmap_mmio_free_context(void *context) ...@@ -232,14 +207,11 @@ static void regmap_mmio_free_context(void *context)
kfree(context); kfree(context);
} }
static struct regmap_bus regmap_mmio = { static const struct regmap_bus regmap_mmio = {
.fast_io = true, .fast_io = true,
.write = regmap_mmio_write, .reg_write = regmap_mmio_write,
.gather_write = regmap_mmio_gather_write, .reg_read = regmap_mmio_read,
.read = regmap_mmio_read,
.free_context = regmap_mmio_free_context, .free_context = regmap_mmio_free_context,
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
}; };
static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
...@@ -265,24 +237,71 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -265,24 +237,71 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
if (config->reg_stride < min_stride) if (config->reg_stride < min_stride)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
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); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) if (!ctx)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ctx->regs = regs; ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8; ctx->val_bytes = config->val_bits / 8;
ctx->reg_bytes = config->reg_bits / 8;
ctx->pad_bytes = config->pad_bits / 8;
ctx->clk = ERR_PTR(-ENODEV); ctx->clk = ERR_PTR(-ENODEV);
switch (config->reg_format_endian) {
case REGMAP_ENDIAN_DEFAULT:
case REGMAP_ENDIAN_LITTLE:
#ifdef __LITTLE_ENDIAN
case REGMAP_ENDIAN_NATIVE:
#endif
switch (config->val_bits) {
case 8:
ctx->reg_read = regmap_mmio_read8;
ctx->reg_write = regmap_mmio_write8;
break;
case 16:
ctx->reg_read = regmap_mmio_read16le;
ctx->reg_write = regmap_mmio_write16le;
break;
case 32:
ctx->reg_read = regmap_mmio_read32le;
ctx->reg_write = regmap_mmio_write32le;
break;
#ifdef CONFIG_64BIT
case 64:
ctx->reg_read = regmap_mmio_read64le;
ctx->reg_write = regmap_mmio_write64le;
break;
#endif
default:
ret = -EINVAL;
goto err_free;
}
break;
case REGMAP_ENDIAN_BIG:
#ifdef __BIG_ENDIAN
case REGMAP_ENDIAN_NATIVE:
#endif
switch (config->val_bits) {
case 8:
ctx->reg_read = regmap_mmio_read8;
ctx->reg_write = regmap_mmio_write8;
break;
case 16:
ctx->reg_read = regmap_mmio_read16be;
ctx->reg_write = regmap_mmio_write16be;
break;
case 32:
ctx->reg_read = regmap_mmio_read32be;
ctx->reg_write = regmap_mmio_write32be;
break;
default:
ret = -EINVAL;
goto err_free;
}
break;
default:
ret = -EINVAL;
goto err_free;
}
if (clk_id == NULL) if (clk_id == NULL)
return ctx; return ctx;
......
This diff is collapsed.
...@@ -65,6 +65,36 @@ struct reg_sequence { ...@@ -65,6 +65,36 @@ struct reg_sequence {
unsigned int delay_us; unsigned int delay_us;
}; };
#define regmap_update_bits(map, reg, mask, val) \
regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
#define regmap_update_bits_async(map, reg, mask, val)\
regmap_update_bits_base(map, reg, mask, val, NULL, true, false)
#define regmap_update_bits_check(map, reg, mask, val, change)\
regmap_update_bits_base(map, reg, mask, val, change, false, false)
#define regmap_update_bits_check_async(map, reg, mask, val, change)\
regmap_update_bits_base(map, reg, mask, val, change, true, false)
#define regmap_write_bits(map, reg, mask, val) \
regmap_update_bits_base(map, reg, mask, val, NULL, false, true)
#define regmap_field_write(field, val) \
regmap_field_update_bits_base(field, ~0, val, NULL, false, false)
#define regmap_field_force_write(field, val) \
regmap_field_update_bits_base(field, ~0, val, NULL, false, true)
#define regmap_field_update_bits(field, mask, val)\
regmap_field_update_bits_base(field, mask, val, NULL, false, false)
#define regmap_field_force_update_bits(field, mask, val) \
regmap_field_update_bits_base(field, mask, val, NULL, false, true)
#define regmap_fields_write(field, id, val) \
regmap_fields_update_bits_base(field, id, ~0, val, NULL, false, false)
#define regmap_fields_force_write(field, id, val) \
regmap_fields_update_bits_base(field, id, ~0, val, NULL, false, true)
#define regmap_fields_update_bits(field, id, mask, val)\
regmap_fields_update_bits_base(field, id, mask, val, NULL, false, false)
#define regmap_fields_force_update_bits(field, id, mask, val) \
regmap_fields_update_bits_base(field, id, mask, val, NULL, false, true)
#ifdef CONFIG_REGMAP #ifdef CONFIG_REGMAP
enum regmap_endian { enum regmap_endian {
...@@ -162,7 +192,7 @@ typedef void (*regmap_unlock)(void *); ...@@ -162,7 +192,7 @@ typedef void (*regmap_unlock)(void *);
* This field is a duplicate of a similar file in * This field is a duplicate of a similar file in
* 'struct regmap_bus' and serves exact same purpose. * 'struct regmap_bus' and serves exact same purpose.
* Use it only for "no-bus" cases. * Use it only for "no-bus" cases.
* @max_register: Optional, specifies the maximum valid register index. * @max_register: Optional, specifies the maximum valid register address.
* @wr_table: Optional, points to a struct regmap_access_table specifying * @wr_table: Optional, points to a struct regmap_access_table specifying
* valid ranges for write access. * valid ranges for write access.
* @rd_table: As above, for read access. * @rd_table: As above, for read access.
...@@ -691,18 +721,9 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, ...@@ -691,18 +721,9 @@ int regmap_raw_read(struct regmap *map, unsigned int reg,
void *val, size_t val_len); void *val, size_t val_len);
int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t val_count); size_t val_count);
int regmap_update_bits(struct regmap *map, unsigned int reg, int regmap_update_bits_base(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val); unsigned int mask, unsigned int val,
int regmap_write_bits(struct regmap *map, unsigned int reg, bool *change, bool async, bool force);
unsigned int mask, unsigned int val);
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val);
int regmap_update_bits_check(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change);
int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change);
int regmap_get_val_bytes(struct regmap *map); int regmap_get_val_bytes(struct regmap *map);
int regmap_get_max_register(struct regmap *map); int regmap_get_max_register(struct regmap *map);
int regmap_get_reg_stride(struct regmap *map); int regmap_get_reg_stride(struct regmap *map);
...@@ -770,18 +791,14 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev, ...@@ -770,18 +791,14 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev,
void devm_regmap_field_free(struct device *dev, struct regmap_field *field); void devm_regmap_field_free(struct device *dev, struct regmap_field *field);
int regmap_field_read(struct regmap_field *field, unsigned int *val); int regmap_field_read(struct regmap_field *field, unsigned int *val);
int regmap_field_write(struct regmap_field *field, unsigned int val); int regmap_field_update_bits_base(struct regmap_field *field,
int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val,
unsigned int mask, unsigned int val); bool *change, bool async, bool force);
int regmap_fields_write(struct regmap_field *field, unsigned int id,
unsigned int val);
int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
unsigned int val);
int regmap_fields_read(struct regmap_field *field, unsigned int id, int regmap_fields_read(struct regmap_field *field, unsigned int id,
unsigned int *val); unsigned int *val);
int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id,
unsigned int mask, unsigned int val); unsigned int mask, unsigned int val,
bool *change, bool async, bool force);
/** /**
* Description of an IRQ for the generic regmap irq_chip. * Description of an IRQ for the generic regmap irq_chip.
...@@ -868,6 +885,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -868,6 +885,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
int irq_base, const 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 **data);
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data); void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
int irq_flags, int irq_base,
const struct regmap_irq_chip *chip,
struct regmap_irq_chip_data **data);
void devm_regmap_del_irq_chip(struct device *dev, int irq,
struct regmap_irq_chip_data *data);
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data); int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq); int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data); struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data);
...@@ -937,42 +962,26 @@ static inline int regmap_bulk_read(struct regmap *map, unsigned int reg, ...@@ -937,42 +962,26 @@ static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
return -EINVAL; return -EINVAL;
} }
static inline int regmap_update_bits(struct regmap *map, unsigned int reg, static inline int regmap_update_bits_base(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val) unsigned int mask, unsigned int val,
{ bool *change, bool async, bool force)
WARN_ONCE(1, "regmap API is disabled");
return -EINVAL;
}
static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
WARN_ONCE(1, "regmap API is disabled");
return -EINVAL;
}
static inline int regmap_update_bits_async(struct regmap *map,
unsigned int reg,
unsigned int mask, unsigned int val)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
return -EINVAL; return -EINVAL;
} }
static inline int regmap_update_bits_check(struct regmap *map, static inline int regmap_field_update_bits_base(struct regmap_field *field,
unsigned int reg, unsigned int mask, unsigned int val,
unsigned int mask, unsigned int val, bool *change, bool async, bool force)
bool *change)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
return -EINVAL; return -EINVAL;
} }
static inline int regmap_update_bits_check_async(struct regmap *map, static inline int regmap_fields_update_bits_base(struct regmap_field *field,
unsigned int reg, unsigned int id,
unsigned int mask, unsigned int mask, unsigned int val,
unsigned int val, bool *change, bool async, bool force)
bool *change)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment