int i;
void *tmp_buf;
-- for (i = 0; i < config->num_reg_defaults; i++)
-- if (config->reg_defaults[i].reg % map->reg_stride)
-- return -EINVAL;
--
if (map->cache_type == REGCACHE_NONE) {
++ if (config->reg_defaults || config->num_reg_defaults_raw)
++ dev_warn(map->dev,
++ "No cache used with register defaults set!\n");
++
map->cache_bypass = true;
return 0;
}
++ if (config->reg_defaults && !config->num_reg_defaults) {
++ dev_err(map->dev,
++ "Register defaults are set without the number!\n");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < config->num_reg_defaults; i++)
++ if (config->reg_defaults[i].reg % map->reg_stride)
++ return -EINVAL;
++
for (i = 0; i < ARRAY_SIZE(cache_types); i++)
if (cache_types[i]->type == map->cache_type)
break;
* a copy of it.
*/
if (config->reg_defaults) {
-- if (!map->num_reg_defaults)
-- return -EINVAL;
tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults *
sizeof(struct reg_default), GFP_KERNEL);
if (!tmp_buf)
switch (map->cache_word_size) {
case 1: {
u8 *cache = base;
+ +
cache[idx] = val;
break;
}
case 2: {
u16 *cache = base;
+ +
cache[idx] = val;
break;
}
case 4: {
u32 *cache = base;
+ +
+ + cache[idx] = val;
+ + break;
+ + }
+ +#ifdef CONFIG_64BIT
+ + case 8: {
+ + u64 *cache = base;
+ +
cache[idx] = val;
break;
}
+ +#endif
default:
BUG();
}
switch (map->cache_word_size) {
case 1: {
const u8 *cache = base;
+ +
return cache[idx];
}
case 2: {
const u16 *cache = base;
+ +
return cache[idx];
}
case 4: {
const u32 *cache = base;
+ +
+ + return cache[idx];
+ + }
+ +#ifdef CONFIG_64BIT
+ + case 8: {
+ + const u64 *cache = base;
+ +
return cache[idx];
}
+ +#endif
default:
BUG();
}
unsigned int *mask_buf;
unsigned int *mask_buf_def;
unsigned int *wake_buf;
++ unsigned int *type_buf;
++ unsigned int *type_buf_def;
unsigned int irq_reg_stride;
++ unsigned int type_reg_stride;
};
static inline const
}
}
++ for (i = 0; i < d->chip->num_type_reg; i++) {
++ if (!d->type_buf_def[i])
++ continue;
++ reg = d->chip->type_base +
++ (i * map->reg_stride * d->type_reg_stride);
++ if (d->chip->type_invert)
++ ret = regmap_update_bits(d->map, reg,
++ d->type_buf_def[i], ~d->type_buf[i]);
++ else
++ ret = regmap_update_bits(d->map, reg,
++ d->type_buf_def[i], d->type_buf[i]);
++ if (ret != 0)
++ dev_err(d->map->dev, "Failed to sync type in %x\n",
++ reg);
++ }
++
if (d->chip->runtime_pm)
pm_runtime_put(map->dev);
d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
}
++ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
++ {
++ 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);
++ int reg = irq_data->type_reg_offset / map->reg_stride;
++
++ if (!(irq_data->type_rising_mask | irq_data->type_falling_mask))
++ return 0;
++
++ d->type_buf[reg] &= ~(irq_data->type_falling_mask |
++ irq_data->type_rising_mask);
++ switch (type) {
++ case IRQ_TYPE_EDGE_FALLING:
++ d->type_buf[reg] |= irq_data->type_falling_mask;
++ break;
++
++ case IRQ_TYPE_EDGE_RISING:
++ d->type_buf[reg] |= irq_data->type_rising_mask;
++ break;
++
++ case IRQ_TYPE_EDGE_BOTH:
++ d->type_buf[reg] |= (irq_data->type_falling_mask |
++ irq_data->type_rising_mask);
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ return 0;
++ }
++
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);
.irq_bus_sync_unlock = regmap_irq_sync_unlock,
.irq_disable = regmap_irq_disable,
.irq_enable = regmap_irq_enable,
++ .irq_set_type = regmap_irq_set_type,
.irq_set_wake = regmap_irq_set_wake,
};
if (!d)
return -ENOMEM;
-- d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
++ d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->status_buf)
goto err_alloc;
-- d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
++ d->mask_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->mask_buf)
goto err_alloc;
-- d->mask_buf_def = kzalloc(sizeof(unsigned int) * chip->num_regs,
++ d->mask_buf_def = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->mask_buf_def)
goto err_alloc;
if (chip->wake_base) {
-- d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
++ d->wake_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->wake_buf)
goto err_alloc;
}
++ if (chip->num_type_reg) {
++ d->type_buf_def = kcalloc(chip->num_type_reg,
++ sizeof(unsigned int), GFP_KERNEL);
++ if (!d->type_buf_def)
++ goto err_alloc;
++
++ d->type_buf = kcalloc(chip->num_type_reg, sizeof(unsigned int),
++ GFP_KERNEL);
++ if (!d->type_buf)
++ goto err_alloc;
++ }
++
d->irq_chip = regmap_irq_chip;
d->irq_chip.name = chip->name;
d->irq = irq;
else
d->irq_reg_stride = 1;
++ if (chip->type_reg_stride)
++ d->type_reg_stride = chip->type_reg_stride;
++ else
++ d->type_reg_stride = 1;
++
if (!map->use_single_read && map->reg_stride == 1 &&
d->irq_reg_stride == 1) {
-- d->status_reg_buf = kmalloc(map->format.val_bytes *
-- chip->num_regs, GFP_KERNEL);
++ d->status_reg_buf = kmalloc_array(chip->num_regs,
++ map->format.val_bytes,
++ GFP_KERNEL);
if (!d->status_reg_buf)
goto err_alloc;
}
}
}
++ if (chip->num_type_reg) {
++ for (i = 0; i < chip->num_irqs; i++) {
++ reg = chip->irqs[i].type_reg_offset / map->reg_stride;
++ d->type_buf_def[reg] |= chip->irqs[i].type_rising_mask |
++ chip->irqs[i].type_falling_mask;
++ }
++ for (i = 0; i < chip->num_type_reg; ++i) {
++ if (!d->type_buf_def[i])
++ continue;
++
++ reg = chip->type_base +
++ (i * map->reg_stride * d->type_reg_stride);
++ if (chip->type_invert)
++ ret = regmap_update_bits(map, reg,
++ d->type_buf_def[i], 0xFF);
++ else
++ ret = regmap_update_bits(map, reg,
++ d->type_buf_def[i], 0x0);
++ if (ret != 0) {
++ dev_err(map->dev,
++ "Failed to set type in 0x%x: %x\n",
++ reg, ret);
++ goto err_alloc;
++ }
++ }
++ }
++
if (irq_base)
d->domain = irq_domain_add_legacy(map->dev->of_node,
chip->num_irqs, irq_base, 0,
err_domain:
/* Should really dispose of the domain but... */
err_alloc:
++ kfree(d->type_buf);
++ kfree(d->type_buf_def);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
free_irq(irq, d);
irq_domain_remove(d->domain);
++ kfree(d->type_buf);
++ kfree(d->type_buf_def);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
*(u32 *)buf = val << shift;
}
+ +#ifdef CONFIG_64BIT
+ +static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift)
+ +{
+ + __be64 *b = buf;
+ +
+ + b[0] = cpu_to_be64((u64)val << shift);
+ +}
+ +
+ +static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift)
+ +{
+ + __le64 *b = buf;
+ +
+ + b[0] = cpu_to_le64((u64)val << shift);
+ +}
+ +
+ +static void regmap_format_64_native(void *buf, unsigned int val,
+ + unsigned int shift)
+ +{
+ + *(u64 *)buf = (u64)val << shift;
+ +}
+ +#endif
+ +
static void regmap_parse_inplace_noop(void *buf)
{
}
return *(u32 *)buf;
}
+ +#ifdef CONFIG_64BIT
+ +static unsigned int regmap_parse_64_be(const void *buf)
+ +{
+ + const __be64 *b = buf;
+ +
+ + return be64_to_cpu(b[0]);
+ +}
+ +
+ +static unsigned int regmap_parse_64_le(const void *buf)
+ +{
+ + const __le64 *b = buf;
+ +
+ + return le64_to_cpu(b[0]);
+ +}
+ +
+ +static void regmap_parse_64_be_inplace(void *buf)
+ +{
+ + __be64 *b = buf;
+ +
+ + b[0] = be64_to_cpu(b[0]);
+ +}
+ +
+ +static void regmap_parse_64_le_inplace(void *buf)
+ +{
+ + __le64 *b = buf;
+ +
+ + b[0] = le64_to_cpu(b[0]);
+ +}
+ +
+ +static unsigned int regmap_parse_64_native(const void *buf)
+ +{
+ + return *(u64 *)buf;
+ +}
+ +#endif
+ +
static void regmap_lock_mutex(void *__map)
{
struct regmap *map = __map;
}
break;
+ +#ifdef CONFIG_64BIT
+ + case 64:
+ + switch (reg_endian) {
+ + case REGMAP_ENDIAN_BIG:
+ + map->format.format_reg = regmap_format_64_be;
+ + break;
+ + case REGMAP_ENDIAN_NATIVE:
+ + map->format.format_reg = regmap_format_64_native;
+ + break;
+ + default:
+ + goto err_map;
+ + }
+ + break;
+ +#endif
+ +
default:
goto err_map;
}
goto err_map;
}
break;
+ +#ifdef CONFIG_64BIT
+ + case 64:
+ + switch (val_endian) {
+ + case REGMAP_ENDIAN_BIG:
+ + map->format.format_val = regmap_format_64_be;
+ + map->format.parse_val = regmap_parse_64_be;
+ + map->format.parse_inplace = regmap_parse_64_be_inplace;
+ + break;
+ + case REGMAP_ENDIAN_LITTLE:
+ + map->format.format_val = regmap_format_64_le;
+ + map->format.parse_val = regmap_parse_64_le;
+ + map->format.parse_inplace = regmap_parse_64_le_inplace;
+ + break;
+ + case REGMAP_ENDIAN_NATIVE:
+ + map->format.format_val = regmap_format_64_native;
+ + map->format.parse_val = regmap_parse_64_native;
+ + break;
+ + default:
+ + goto err_map;
+ + }
+ + break;
+ +#endif
}
if (map->format.format_write) {
{
int ret;
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
{
int ret;
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
if (map->bus && !map->format.parse_inplace)
return -EINVAL;
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
/*
int reg = regs[i].reg;
if (!map->writeable_reg(map->dev, reg))
return -EINVAL;
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
}
if (val_len % map->format.val_bytes)
return -EINVAL;
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
{
int ret;
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
if (val_count == 0)
return -EINVAL;
size_t val_bytes = map->format.val_bytes;
bool vol = regmap_volatile_range(map, reg, val_count);
-- if (reg % map->reg_stride)
++ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
* we assume that the values are native
* endian.
*/
+ +#ifdef CONFIG_64BIT
+ + u64 *u64 = val;
+ +#endif
u32 *u32 = val;
u16 *u16 = val;
u8 *u8 = val;
switch (map->format.val_bytes) {
+ +#ifdef CONFIG_64BIT
+ + case 8:
+ + u64[i] = ival;
+ + break;
+ +#endif
case 4:
u32[i] = ival;
break;
*
* @reg_offset: Offset of the status/mask register within the bank
* @mask: Mask used to flag/control the register.
++ * @type_reg_offset: Offset register for the irq type setting.
++ * @type_rising_mask: Mask bit to configure RISING type irq.
++ * @type_falling_mask: Mask bit to configure FALLING type irq.
*/
struct regmap_irq {
unsigned int reg_offset;
unsigned int mask;
++ unsigned int type_reg_offset;
++ unsigned int type_rising_mask;
++ unsigned int type_falling_mask;
};
#define REGMAP_IRQ_REG(_irq, _off, _mask) \
* @ack_base: Base ack address. If zero then the chip is clear on read.
* Using zero value is possible with @use_ack bit.
* @wake_base: Base address for wake enables. If zero unsupported.
++ * @type_base: Base address for irq type. If zero unsupported.
* @irq_reg_stride: Stride to use for chips where registers are not contiguous.
* @init_ack_masked: Ack all masked interrupts once during initalization.
* @mask_invert: Inverted mask register: cleared bits are masked out.
* @use_ack: Use @ack register even if it is zero.
* @ack_invert: Inverted ack register: cleared bits for ack.
* @wake_invert: Inverted wake register: cleared bits are wake enabled.
++ * @type_invert: Invert the type flags.
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
*
* @num_regs: Number of registers in each control bank.
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
* assigned based on the index in the array of the interrupt.
* @num_irqs: Number of descriptors.
++ * @num_type_reg: Number of type registers.
++ * @type_reg_stride: Stride to use for chips where type registers are not
++ * contiguous.
*/
struct regmap_irq_chip {
const char *name;
unsigned int unmask_base;
unsigned int ack_base;
unsigned int wake_base;
++ unsigned int type_base;
unsigned int irq_reg_stride;
bool init_ack_masked:1;
bool mask_invert:1;
bool ack_invert:1;
bool wake_invert:1;
bool runtime_pm:1;
++ bool type_invert:1;
int num_regs;
const struct regmap_irq *irqs;
int num_irqs;
++
++ int num_type_reg;
++ unsigned int type_reg_stride;
};
struct regmap_irq_chip_data;
}
static inline int regmap_register_patch(struct regmap *map,
-- const struct reg_default *regs,
++ const struct reg_sequence *regs,
int num_regs)
{
WARN_ONCE(1, "regmap API is disabled");