Commit a6e6d863 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull regmap updates from Mark Brown:
 "A small but useful set of regmap updates this time around:

   - An abstraction for bitfields within a register map contributed by
     Srinivas Kandagatla, allowing drivers to cope more easily when
     hardware designers randomly move things about (mainly when talking
     to things like system controllers).

   - Changes from Lars-Peter Clausen to allow the MMIO regmap to be used
     from hard IRQ context.

   - Small improvements to the cache infrastructure and performance,
     including a default cache sync operation so now all regmaps can
     sync easily.

  There's also a pinctrl driver making use of the new bitfield API,
  merged here for dependency reasons.  There will be a simple add/add
  conflict with the pinctrl tree as a result."

* tag 'regmap-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  pinctrl: st: Remove unnecessary use of of_match_ptr macro
  pinctrl: st: fix return value check
  pinctrl: st: Add pinctrl and pinconf support.
  regmap: debugfs: Suppress cache for partial register files
  regmap: Add regmap_field APIs
  regmap: core: Cache all registers by default when cache is enabled
  regmap: Implemented default cache sync operation
  regmap: Make regmap-mmio usable from atomic contexts
  regmap: regcache: Fixup locking for custom lock callbacks
  regmap: debugfs: Fix return from regmap_debugfs_get_dump_start
  regmap: debugfs: Don't mark lockdep as broken due to debugfs write
  regmap: rbtree: Use range information to allocate nodes
  regmap: rbtree: Factor out node allocation
  regmap: Make regmap_check_range_table() a public API
  regmap: Add support for discarding parts of the register cache
parents 60b5adff 7bc8c4c3
*ST pin controller.
Each multi-function pin is controlled, driven and routed through the
PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
and multiple alternate functions(ALT1 - ALTx) that directly connect
the pin to different hardware blocks.
When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
Pull Up (PU) are driven by the related PIO block.
ST pinctrl driver controls PIO multiplexing block and also interacts with
gpio driver to configure a pin.
Required properties: (PIO multiplexing block)
- compatible : should be "st,<SOC>-<pio-block>-pinctrl"
like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
- gpio-controller : Indicates this device is a GPIO controller
- #gpio-cells : Should be one. The first cell is the pin number.
- st,retime-pin-mask : Should be mask to specify which pins can be retimed.
If the property is not present, it is assumed that all the pins in the
bank are capable of retiming. Retiming is mainly used to improve the
IO timing margins of external synchronous interfaces.
- st,bank-name : Should be a name string for this bank as
specified in datasheet.
- st,syscfg : Should be a phandle of the syscfg node.
Example:
pin-controller-sbc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "st,stih415-sbc-pinctrl";
st,syscfg = <&syscfg_sbc>;
ranges = <0 0xfe610000 0x5000>;
PIO0: gpio@fe610000 {
gpio-controller;
#gpio-cells = <1>;
reg = <0 0x100>;
st,bank-name = "PIO0";
};
...
pin-functions nodes follow...
};
Contents of function subnode node:
----------------------
Required properties for pin configuration node:
- st,pins : Child node with list of pins with configuration.
Below is the format of how each pin conf should look like.
<bank offset mux mode rt_type rt_delay rt_clk>
Every PIO is represented with 4-7 parameters depending on retime configuration.
Each parameter is explained as below.
-bank : Should be bank phandle to which this PIO belongs.
-offset : Offset in the PIO bank.
-mux : Should be alternate function number associated this pin.
Use same numbers from datasheet.
-mode :pin configuration is selected from one of the below values.
IN
IN_PU
OUT
BIDIR
BIDIR_PU
-rt_type Retiming Configuration for the pin.
Possible retime configuration are:
------- -------------
value args
------- -------------
NICLK <delay> <clk>
ICLK_IO <delay> <clk>
BYPASS <delay>
DE_IO <delay> <clk>
SE_ICLK_IO <delay> <clk>
SE_NICLK_IO <delay> <clk>
- delay is retime delay in pico seconds as mentioned in data sheet.
- rt_clk :clk to be use for retime.
Possible values are:
CLK_A
CLK_B
CLK_C
CLK_D
Example of mmcclk pin which is a bi-direction pull pu with retime config
as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
pin-controller {
...
mmc0 {
pinctrl_mmc: mmc {
st,pins {
mmcclk = <&PIO13 4 ALT4 BIDIR_PU NICLK 0 CLK_B>;
...
};
};
...
};
};
sdhci0:sdhci@fe810000{
...
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mmc>;
};
...@@ -52,6 +52,7 @@ struct regmap_async { ...@@ -52,6 +52,7 @@ struct regmap_async {
struct regmap { struct regmap {
struct mutex mutex; struct mutex mutex;
spinlock_t spinlock; spinlock_t spinlock;
unsigned long spinlock_flags;
regmap_lock lock; regmap_lock lock;
regmap_unlock unlock; regmap_unlock unlock;
void *lock_arg; /* This is passed to lock/unlock functions */ void *lock_arg; /* This is passed to lock/unlock functions */
...@@ -148,6 +149,7 @@ struct regcache_ops { ...@@ -148,6 +149,7 @@ struct regcache_ops {
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value); int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
int (*write)(struct regmap *map, unsigned int reg, unsigned int value); int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
int (*sync)(struct regmap *map, unsigned int min, unsigned int max); int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
int (*drop)(struct regmap *map, unsigned int min, unsigned int max);
}; };
bool regmap_writeable(struct regmap *map, unsigned int reg); bool regmap_writeable(struct regmap *map, unsigned int reg);
...@@ -174,6 +176,14 @@ struct regmap_range_node { ...@@ -174,6 +176,14 @@ struct regmap_range_node {
unsigned int window_len; unsigned int window_len;
}; };
struct regmap_field {
struct regmap *regmap;
unsigned int mask;
/* lsb */
unsigned int shift;
unsigned int reg;
};
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
extern void regmap_debugfs_initcall(void); extern void regmap_debugfs_initcall(void);
extern void regmap_debugfs_init(struct regmap *map, const char *name); extern void regmap_debugfs_init(struct regmap *map, const char *name);
......
...@@ -304,6 +304,48 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, ...@@ -304,6 +304,48 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
return 0; return 0;
} }
static struct regcache_rbtree_node *
regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
{
struct regcache_rbtree_node *rbnode;
const struct regmap_range *range;
int i;
rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
if (!rbnode)
return NULL;
/* If there is a read table then use it to guess at an allocation */
if (map->rd_table) {
for (i = 0; i < map->rd_table->n_yes_ranges; i++) {
if (regmap_reg_in_range(reg,
&map->rd_table->yes_ranges[i]))
break;
}
if (i != map->rd_table->n_yes_ranges) {
range = &map->rd_table->yes_ranges[i];
rbnode->blklen = range->range_max - range->range_min
+ 1;
rbnode->base_reg = range->range_min;
}
}
if (!rbnode->blklen) {
rbnode->blklen = sizeof(*rbnode);
rbnode->base_reg = reg;
}
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
GFP_KERNEL);
if (!rbnode->block) {
kfree(rbnode);
return NULL;
}
return rbnode;
}
static int regcache_rbtree_write(struct regmap *map, unsigned int reg, static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
unsigned int value) unsigned int value)
{ {
...@@ -354,23 +396,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, ...@@ -354,23 +396,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
return 0; return 0;
} }
} }
/* we did not manage to find a place to insert it in an existing
* block so create a new rbnode with a single register in its block. /* We did not manage to find a place to insert it in
* This block will get populated further if any other adjacent * an existing block so create a new rbnode.
* registers get modified in the future.
*/ */
rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); rbnode = regcache_rbtree_node_alloc(map, reg);
if (!rbnode) if (!rbnode)
return -ENOMEM; return -ENOMEM;
rbnode->blklen = sizeof(*rbnode); regcache_rbtree_set_register(map, rbnode,
rbnode->base_reg = reg; reg - rbnode->base_reg, value);
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
GFP_KERNEL);
if (!rbnode->block) {
kfree(rbnode);
return -ENOMEM;
}
regcache_rbtree_set_register(map, rbnode, 0, value);
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode); regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode; rbtree_ctx->cached_rbnode = rbnode;
} }
......
...@@ -250,6 +250,38 @@ int regcache_write(struct regmap *map, ...@@ -250,6 +250,38 @@ int regcache_write(struct regmap *map,
return 0; return 0;
} }
static int regcache_default_sync(struct regmap *map, unsigned int min,
unsigned int max)
{
unsigned int reg;
for (reg = min; reg <= max; reg++) {
unsigned int val;
int ret;
if (regmap_volatile(map, reg))
continue;
ret = regcache_read(map, reg, &val);
if (ret)
return ret;
/* Is this the hardware default? If so skip. */
ret = regcache_lookup_reg(map, reg);
if (ret >= 0 && val == map->reg_defaults[ret].def)
continue;
map->cache_bypass = 1;
ret = _regmap_write(map, reg, val);
map->cache_bypass = 0;
if (ret)
return ret;
dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
}
return 0;
}
/** /**
* regcache_sync: Sync the register cache with the hardware. * regcache_sync: Sync the register cache with the hardware.
* *
...@@ -268,7 +300,7 @@ int regcache_sync(struct regmap *map) ...@@ -268,7 +300,7 @@ int regcache_sync(struct regmap *map)
const char *name; const char *name;
unsigned int bypass; unsigned int bypass;
BUG_ON(!map->cache_ops || !map->cache_ops->sync); BUG_ON(!map->cache_ops);
map->lock(map->lock_arg); map->lock(map->lock_arg);
/* Remember the initial bypass state */ /* Remember the initial bypass state */
...@@ -297,7 +329,10 @@ int regcache_sync(struct regmap *map) ...@@ -297,7 +329,10 @@ int regcache_sync(struct regmap *map)
} }
map->cache_bypass = 0; map->cache_bypass = 0;
ret = map->cache_ops->sync(map, 0, map->max_register); if (map->cache_ops->sync)
ret = map->cache_ops->sync(map, 0, map->max_register);
else
ret = regcache_default_sync(map, 0, map->max_register);
if (ret == 0) if (ret == 0)
map->cache_dirty = false; map->cache_dirty = false;
...@@ -331,7 +366,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min, ...@@ -331,7 +366,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
const char *name; const char *name;
unsigned int bypass; unsigned int bypass;
BUG_ON(!map->cache_ops || !map->cache_ops->sync); BUG_ON(!map->cache_ops);
map->lock(map->lock_arg); map->lock(map->lock_arg);
...@@ -346,7 +381,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min, ...@@ -346,7 +381,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
if (!map->cache_dirty) if (!map->cache_dirty)
goto out; goto out;
ret = map->cache_ops->sync(map, min, max); if (map->cache_ops->sync)
ret = map->cache_ops->sync(map, min, max);
else
ret = regcache_default_sync(map, min, max);
out: out:
trace_regcache_sync(map->dev, name, "stop region"); trace_regcache_sync(map->dev, name, "stop region");
...@@ -358,6 +396,43 @@ int regcache_sync_region(struct regmap *map, unsigned int min, ...@@ -358,6 +396,43 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
} }
EXPORT_SYMBOL_GPL(regcache_sync_region); EXPORT_SYMBOL_GPL(regcache_sync_region);
/**
* regcache_drop_region: Discard part of the register cache
*
* @map: map to operate on
* @min: first register to discard
* @max: last register to discard
*
* Discard part of the register cache.
*
* Return a negative value on failure, 0 on success.
*/
int regcache_drop_region(struct regmap *map, unsigned int min,
unsigned int max)
{
unsigned int reg;
int ret = 0;
if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop))
return -EINVAL;
map->lock(map->lock_arg);
trace_regcache_drop_region(map->dev, min, max);
if (map->cache_present)
for (reg = min; reg < max + 1; reg++)
clear_bit(reg, map->cache_present);
if (map->cache_ops && map->cache_ops->drop)
ret = map->cache_ops->drop(map, min, max);
map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regcache_drop_region);
/** /**
* regcache_cache_only: Put a register map into cache only mode * regcache_cache_only: Put a register map into cache only mode
* *
......
...@@ -84,6 +84,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, ...@@ -84,6 +84,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
unsigned int fpos_offset; unsigned int fpos_offset;
unsigned int reg_offset; unsigned int reg_offset;
/* Suppress the cache if we're using a subrange */
if (from)
return from;
/* /*
* If we don't have a cache build one so we don't have to do a * If we don't have a cache build one so we don't have to do a
* linear scan each time. * linear scan each time.
...@@ -145,7 +149,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, ...@@ -145,7 +149,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
reg_offset = fpos_offset / map->debugfs_tot_len; reg_offset = fpos_offset / map->debugfs_tot_len;
*pos = c->min + (reg_offset * map->debugfs_tot_len); *pos = c->min + (reg_offset * map->debugfs_tot_len);
mutex_unlock(&map->cache_lock); mutex_unlock(&map->cache_lock);
return c->base_reg + reg_offset; return c->base_reg + (reg_offset * map->reg_stride);
} }
*pos = c->max; *pos = c->max;
...@@ -281,7 +285,7 @@ static ssize_t regmap_map_write_file(struct file *file, ...@@ -281,7 +285,7 @@ static ssize_t regmap_map_write_file(struct file *file,
return -EINVAL; return -EINVAL;
/* Userspace has been fiddling around behind the kernel's back */ /* Userspace has been fiddling around behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE); add_taint(TAINT_USER, LOCKDEP_STILL_OK);
ret = regmap_write(map, reg, value); ret = regmap_write(map, reg, value);
if (ret < 0) if (ret < 0)
......
...@@ -65,9 +65,8 @@ bool regmap_reg_in_ranges(unsigned int reg, ...@@ -65,9 +65,8 @@ bool regmap_reg_in_ranges(unsigned int reg,
} }
EXPORT_SYMBOL_GPL(regmap_reg_in_ranges); EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
static bool _regmap_check_range_table(struct regmap *map, bool regmap_check_range_table(struct regmap *map, unsigned int reg,
unsigned int reg, const struct regmap_access_table *table)
const struct regmap_access_table *table)
{ {
/* Check "no ranges" first */ /* Check "no ranges" first */
if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
...@@ -80,6 +79,7 @@ static bool _regmap_check_range_table(struct regmap *map, ...@@ -80,6 +79,7 @@ static bool _regmap_check_range_table(struct regmap *map,
return regmap_reg_in_ranges(reg, table->yes_ranges, return regmap_reg_in_ranges(reg, table->yes_ranges,
table->n_yes_ranges); table->n_yes_ranges);
} }
EXPORT_SYMBOL_GPL(regmap_check_range_table);
bool regmap_writeable(struct regmap *map, unsigned int reg) bool regmap_writeable(struct regmap *map, unsigned int reg)
{ {
...@@ -90,7 +90,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg) ...@@ -90,7 +90,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
return map->writeable_reg(map->dev, reg); return map->writeable_reg(map->dev, reg);
if (map->wr_table) if (map->wr_table)
return _regmap_check_range_table(map, reg, map->wr_table); return regmap_check_range_table(map, reg, map->wr_table);
return true; return true;
} }
...@@ -107,7 +107,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg) ...@@ -107,7 +107,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
return map->readable_reg(map->dev, reg); return map->readable_reg(map->dev, reg);
if (map->rd_table) if (map->rd_table)
return _regmap_check_range_table(map, reg, map->rd_table); return regmap_check_range_table(map, reg, map->rd_table);
return true; return true;
} }
...@@ -121,9 +121,12 @@ bool regmap_volatile(struct regmap *map, unsigned int reg) ...@@ -121,9 +121,12 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
return map->volatile_reg(map->dev, reg); return map->volatile_reg(map->dev, reg);
if (map->volatile_table) if (map->volatile_table)
return _regmap_check_range_table(map, reg, map->volatile_table); return regmap_check_range_table(map, reg, map->volatile_table);
return true; if (map->cache_ops)
return false;
else
return true;
} }
bool regmap_precious(struct regmap *map, unsigned int reg) bool regmap_precious(struct regmap *map, unsigned int reg)
...@@ -135,7 +138,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg) ...@@ -135,7 +138,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
return map->precious_reg(map->dev, reg); return map->precious_reg(map->dev, reg);
if (map->precious_table) if (map->precious_table)
return _regmap_check_range_table(map, reg, map->precious_table); return regmap_check_range_table(map, reg, map->precious_table);
return false; return false;
} }
...@@ -302,13 +305,16 @@ static void regmap_unlock_mutex(void *__map) ...@@ -302,13 +305,16 @@ static void regmap_unlock_mutex(void *__map)
static void regmap_lock_spinlock(void *__map) static void regmap_lock_spinlock(void *__map)
{ {
struct regmap *map = __map; struct regmap *map = __map;
spin_lock(&map->spinlock); unsigned long flags;
spin_lock_irqsave(&map->spinlock, flags);
map->spinlock_flags = flags;
} }
static void regmap_unlock_spinlock(void *__map) static void regmap_unlock_spinlock(void *__map)
{ {
struct regmap *map = __map; struct regmap *map = __map;
spin_unlock(&map->spinlock); spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
} }
static void dev_get_regmap_release(struct device *dev, void *res) static void dev_get_regmap_release(struct device *dev, void *res)
...@@ -801,6 +807,95 @@ struct regmap *devm_regmap_init(struct device *dev, ...@@ -801,6 +807,95 @@ struct regmap *devm_regmap_init(struct device *dev,
} }
EXPORT_SYMBOL_GPL(devm_regmap_init); EXPORT_SYMBOL_GPL(devm_regmap_init);
static void regmap_field_init(struct regmap_field *rm_field,
struct regmap *regmap, struct reg_field reg_field)
{
int field_bits = reg_field.msb - reg_field.lsb + 1;
rm_field->regmap = regmap;
rm_field->reg = reg_field.reg;
rm_field->shift = reg_field.lsb;
rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb);
}
/**
* devm_regmap_field_alloc(): Allocate and initialise a register field
* in a register map.
*
* @dev: Device that will be interacted with
* @regmap: regmap bank in which this register field is located.
* @reg_field: Register field with in the bank.
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap_field. The regmap_field will be automatically freed
* by the device management code.
*/
struct regmap_field *devm_regmap_field_alloc(struct device *dev,
struct regmap *regmap, struct reg_field reg_field)
{
struct regmap_field *rm_field = devm_kzalloc(dev,
sizeof(*rm_field), GFP_KERNEL);
if (!rm_field)
return ERR_PTR(-ENOMEM);
regmap_field_init(rm_field, regmap, reg_field);
return rm_field;
}
EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
/**
* devm_regmap_field_free(): Free register field allocated using
* devm_regmap_field_alloc. Usally drivers need not call this function,
* as the memory allocated via devm will be freed as per device-driver
* life-cyle.
*
* @dev: Device that will be interacted with
* @field: regmap field which should be freed.
*/
void devm_regmap_field_free(struct device *dev,
struct regmap_field *field)
{
devm_kfree(dev, field);
}
EXPORT_SYMBOL_GPL(devm_regmap_field_free);
/**
* regmap_field_alloc(): Allocate and initialise a register field
* in a register map.
*
* @regmap: regmap bank in which this register field is located.
* @reg_field: Register field with in the bank.
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap_field. The regmap_field should be freed by the
* user once its finished working with it using regmap_field_free().
*/
struct regmap_field *regmap_field_alloc(struct regmap *regmap,
struct reg_field reg_field)
{
struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
if (!rm_field)
return ERR_PTR(-ENOMEM);
regmap_field_init(rm_field, regmap, reg_field);
return rm_field;
}
EXPORT_SYMBOL_GPL(regmap_field_alloc);
/**
* regmap_field_free(): Free register field allocated using regmap_field_alloc
*
* @field: regmap field which should be freed.
*/
void regmap_field_free(struct regmap_field *field)
{
kfree(field);
}
EXPORT_SYMBOL_GPL(regmap_field_free);
/** /**
* regmap_reinit_cache(): Reinitialise the current register cache * regmap_reinit_cache(): Reinitialise the current register cache
* *
...@@ -1249,6 +1344,22 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -1249,6 +1344,22 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
} }
EXPORT_SYMBOL_GPL(regmap_raw_write); EXPORT_SYMBOL_GPL(regmap_raw_write);
/**
* regmap_field_write(): Write a value to a single register field
*
* @field: Register field to write to
* @val: Value to be written
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int regmap_field_write(struct regmap_field *field, unsigned int val)
{
return regmap_update_bits(field->regmap, field->reg,
field->mask, val << field->shift);
}
EXPORT_SYMBOL_GPL(regmap_field_write);
/* /*
* regmap_bulk_write(): Write multiple registers to the device * regmap_bulk_write(): Write multiple registers to the device
* *
...@@ -1531,6 +1642,31 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -1531,6 +1642,31 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
} }
EXPORT_SYMBOL_GPL(regmap_raw_read); EXPORT_SYMBOL_GPL(regmap_raw_read);
/**
* regmap_field_read(): Read a value to a single register field
*
* @field: Register field to read from
* @val: Pointer to store read value
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int regmap_field_read(struct regmap_field *field, unsigned int *val)
{
int ret;
unsigned int reg_val;
ret = regmap_read(field->regmap, field->reg, &reg_val);
if (ret != 0)
return ret;
reg_val &= field->mask;
reg_val >>= field->shift;
*val = reg_val;
return ret;
}
EXPORT_SYMBOL_GPL(regmap_field_read);
/** /**
* regmap_bulk_read(): Read multiple registers from the device * regmap_bulk_read(): Read multiple registers from the device
* *
......
...@@ -169,6 +169,12 @@ config PINCTRL_SUNXI ...@@ -169,6 +169,12 @@ config PINCTRL_SUNXI
select PINMUX select PINMUX
select GENERIC_PINCONF select GENERIC_PINCONF
config PINCTRL_ST
bool
depends on OF
select PINMUX
select PINCONF
config PINCTRL_TEGRA config PINCTRL_TEGRA
bool bool
select PINMUX select PINMUX
......
...@@ -46,6 +46,7 @@ obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o ...@@ -46,6 +46,7 @@ obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o
obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/ obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/
......
/*
* Copyright (C) 2013 STMicroelectronics (R&D) Limited.
* Authors:
* Srinivas Kandagatla <srinivas.kandagatla@st.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/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/platform_device.h>
#include "core.h"
/* PIO Block registers */
/* PIO output */
#define REG_PIO_POUT 0x00
/* Set bits of POUT */
#define REG_PIO_SET_POUT 0x04
/* Clear bits of POUT */
#define REG_PIO_CLR_POUT 0x08
/* PIO input */
#define REG_PIO_PIN 0x10
/* PIO configuration */
#define REG_PIO_PC(n) (0x20 + (n) * 0x10)
/* Set bits of PC[2:0] */
#define REG_PIO_SET_PC(n) (0x24 + (n) * 0x10)
/* Clear bits of PC[2:0] */
#define REG_PIO_CLR_PC(n) (0x28 + (n) * 0x10)
/* PIO input comparison */
#define REG_PIO_PCOMP 0x50
/* Set bits of PCOMP */
#define REG_PIO_SET_PCOMP 0x54
/* Clear bits of PCOMP */
#define REG_PIO_CLR_PCOMP 0x58
/* PIO input comparison mask */
#define REG_PIO_PMASK 0x60
/* Set bits of PMASK */
#define REG_PIO_SET_PMASK 0x64
/* Clear bits of PMASK */
#define REG_PIO_CLR_PMASK 0x68
#define ST_GPIO_DIRECTION_BIDIR 0x1
#define ST_GPIO_DIRECTION_OUT 0x2
#define ST_GPIO_DIRECTION_IN 0x4
/**
* Packed style retime configuration.
* There are two registers cfg0 and cfg1 in this style for each bank.
* Each field in this register is 8 bit corresponding to 8 pins in the bank.
*/
#define RT_P_CFGS_PER_BANK 2
#define RT_P_CFG0_CLK1NOTCLK0_FIELD(reg) REG_FIELD(reg, 0, 7)
#define RT_P_CFG0_DELAY_0_FIELD(reg) REG_FIELD(reg, 16, 23)
#define RT_P_CFG0_DELAY_1_FIELD(reg) REG_FIELD(reg, 24, 31)
#define RT_P_CFG1_INVERTCLK_FIELD(reg) REG_FIELD(reg, 0, 7)
#define RT_P_CFG1_RETIME_FIELD(reg) REG_FIELD(reg, 8, 15)
#define RT_P_CFG1_CLKNOTDATA_FIELD(reg) REG_FIELD(reg, 16, 23)
#define RT_P_CFG1_DOUBLE_EDGE_FIELD(reg) REG_FIELD(reg, 24, 31)
/**
* Dedicated style retime Configuration register
* each register is dedicated per pin.
*/
#define RT_D_CFGS_PER_BANK 8
#define RT_D_CFG_CLK_SHIFT 0
#define RT_D_CFG_CLK_MASK (0x3 << 0)
#define RT_D_CFG_CLKNOTDATA_SHIFT 2
#define RT_D_CFG_CLKNOTDATA_MASK BIT(2)
#define RT_D_CFG_DELAY_SHIFT 3
#define RT_D_CFG_DELAY_MASK (0xf << 3)
#define RT_D_CFG_DELAY_INNOTOUT_SHIFT 7
#define RT_D_CFG_DELAY_INNOTOUT_MASK BIT(7)
#define RT_D_CFG_DOUBLE_EDGE_SHIFT 8
#define RT_D_CFG_DOUBLE_EDGE_MASK BIT(8)
#define RT_D_CFG_INVERTCLK_SHIFT 9
#define RT_D_CFG_INVERTCLK_MASK BIT(9)
#define RT_D_CFG_RETIME_SHIFT 10
#define RT_D_CFG_RETIME_MASK BIT(10)
/*
* Pinconf is represented in an opaque unsigned long variable.
* Below is the bit allocation details for each possible configuration.
* All the bit fields can be encapsulated into four variables
* (direction, retime-type, retime-clk, retime-delay)
*
* +----------------+
*[31:28]| reserved-3 |
* +----------------+-------------
*[27] | oe | |
* +----------------+ v
*[26] | pu | [Direction ]
* +----------------+ ^
*[25] | od | |
* +----------------+-------------
*[24] | reserved-2 |
* +----------------+-------------
*[23] | retime | |
* +----------------+ |
*[22] | retime-invclk | |
* +----------------+ v
*[21] |retime-clknotdat| [Retime-type ]
* +----------------+ ^
*[20] | retime-de | |
* +----------------+-------------
*[19:18]| retime-clk |------>[Retime-Clk ]
* +----------------+
*[17:16]| reserved-1 |
* +----------------+
*[15..0]| retime-delay |------>[Retime Delay]
* +----------------+
*/
#define ST_PINCONF_UNPACK(conf, param)\
((conf >> ST_PINCONF_ ##param ##_SHIFT) \
& ST_PINCONF_ ##param ##_MASK)
#define ST_PINCONF_PACK(conf, val, param) (conf |=\
((val & ST_PINCONF_ ##param ##_MASK) << \
ST_PINCONF_ ##param ##_SHIFT))
/* Output enable */
#define ST_PINCONF_OE_MASK 0x1
#define ST_PINCONF_OE_SHIFT 27
#define ST_PINCONF_OE BIT(27)
#define ST_PINCONF_UNPACK_OE(conf) ST_PINCONF_UNPACK(conf, OE)
#define ST_PINCONF_PACK_OE(conf) ST_PINCONF_PACK(conf, 1, OE)
/* Pull Up */
#define ST_PINCONF_PU_MASK 0x1
#define ST_PINCONF_PU_SHIFT 26
#define ST_PINCONF_PU BIT(26)
#define ST_PINCONF_UNPACK_PU(conf) ST_PINCONF_UNPACK(conf, PU)
#define ST_PINCONF_PACK_PU(conf) ST_PINCONF_PACK(conf, 1, PU)
/* Open Drain */
#define ST_PINCONF_OD_MASK 0x1
#define ST_PINCONF_OD_SHIFT 25
#define ST_PINCONF_OD BIT(25)
#define ST_PINCONF_UNPACK_OD(conf) ST_PINCONF_UNPACK(conf, OD)
#define ST_PINCONF_PACK_OD(conf) ST_PINCONF_PACK(conf, 1, OD)
#define ST_PINCONF_RT_MASK 0x1
#define ST_PINCONF_RT_SHIFT 23
#define ST_PINCONF_RT BIT(23)
#define ST_PINCONF_UNPACK_RT(conf) ST_PINCONF_UNPACK(conf, RT)
#define ST_PINCONF_PACK_RT(conf) ST_PINCONF_PACK(conf, 1, RT)
#define ST_PINCONF_RT_INVERTCLK_MASK 0x1
#define ST_PINCONF_RT_INVERTCLK_SHIFT 22
#define ST_PINCONF_RT_INVERTCLK BIT(22)
#define ST_PINCONF_UNPACK_RT_INVERTCLK(conf) \
ST_PINCONF_UNPACK(conf, RT_INVERTCLK)
#define ST_PINCONF_PACK_RT_INVERTCLK(conf) \
ST_PINCONF_PACK(conf, 1, RT_INVERTCLK)
#define ST_PINCONF_RT_CLKNOTDATA_MASK 0x1
#define ST_PINCONF_RT_CLKNOTDATA_SHIFT 21
#define ST_PINCONF_RT_CLKNOTDATA BIT(21)
#define ST_PINCONF_UNPACK_RT_CLKNOTDATA(conf) \
ST_PINCONF_UNPACK(conf, RT_CLKNOTDATA)
#define ST_PINCONF_PACK_RT_CLKNOTDATA(conf) \
ST_PINCONF_PACK(conf, 1, RT_CLKNOTDATA)
#define ST_PINCONF_RT_DOUBLE_EDGE_MASK 0x1
#define ST_PINCONF_RT_DOUBLE_EDGE_SHIFT 20
#define ST_PINCONF_RT_DOUBLE_EDGE BIT(20)
#define ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \
ST_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE)
#define ST_PINCONF_PACK_RT_DOUBLE_EDGE(conf) \
ST_PINCONF_PACK(conf, 1, RT_DOUBLE_EDGE)
#define ST_PINCONF_RT_CLK_MASK 0x3
#define ST_PINCONF_RT_CLK_SHIFT 18
#define ST_PINCONF_RT_CLK BIT(18)
#define ST_PINCONF_UNPACK_RT_CLK(conf) ST_PINCONF_UNPACK(conf, RT_CLK)
#define ST_PINCONF_PACK_RT_CLK(conf, val) ST_PINCONF_PACK(conf, val, RT_CLK)
/* RETIME_DELAY in Pico Secs */
#define ST_PINCONF_RT_DELAY_MASK 0xffff
#define ST_PINCONF_RT_DELAY_SHIFT 0
#define ST_PINCONF_UNPACK_RT_DELAY(conf) ST_PINCONF_UNPACK(conf, RT_DELAY)
#define ST_PINCONF_PACK_RT_DELAY(conf, val) \
ST_PINCONF_PACK(conf, val, RT_DELAY)
#define ST_GPIO_PINS_PER_BANK (8)
#define OF_GPIO_ARGS_MIN (4)
#define OF_RT_ARGS_MIN (2)
#define gpio_range_to_bank(chip) \
container_of(chip, struct st_gpio_bank, range)
#define gpio_chip_to_bank(chip) \
container_of(chip, struct st_gpio_bank, gpio_chip)
enum st_retime_style {
st_retime_style_none,
st_retime_style_packed,
st_retime_style_dedicated,
};
struct st_retime_dedicated {
struct regmap_field *rt[ST_GPIO_PINS_PER_BANK];
};
struct st_retime_packed {
struct regmap_field *clk1notclk0;
struct regmap_field *delay_0;
struct regmap_field *delay_1;
struct regmap_field *invertclk;
struct regmap_field *retime;
struct regmap_field *clknotdata;
struct regmap_field *double_edge;
};
struct st_pio_control {
u32 rt_pin_mask;
struct regmap_field *alt, *oe, *pu, *od;
/* retiming */
union {
struct st_retime_packed rt_p;
struct st_retime_dedicated rt_d;
} rt;
};
struct st_pctl_data {
enum st_retime_style rt_style;
unsigned int *input_delays;
int ninput_delays;
unsigned int *output_delays;
int noutput_delays;
/* register offset information */
int alt, oe, pu, od, rt;
};
struct st_pinconf {
int pin;
const char *name;
unsigned long config;
int altfunc;
};
struct st_pmx_func {
const char *name;
const char **groups;
unsigned ngroups;
};
struct st_pctl_group {
const char *name;
unsigned int *pins;
unsigned npins;
struct st_pinconf *pin_conf;
};
struct st_gpio_bank {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range range;
void __iomem *base;
struct st_pio_control pc;
};
struct st_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl;
struct st_gpio_bank *banks;
int nbanks;
struct st_pmx_func *functions;
int nfunctions;
struct st_pctl_group *groups;
int ngroups;
struct regmap *regmap;
const struct st_pctl_data *data;
};
/* SOC specific data */
/* STiH415 data */
unsigned int stih415_input_delays[] = {0, 500, 1000, 1500};
unsigned int stih415_output_delays[] = {0, 1000, 2000, 3000};
#define STIH415_PCTRL_COMMON_DATA \
.rt_style = st_retime_style_packed, \
.input_delays = stih415_input_delays, \
.ninput_delays = 4, \
.output_delays = stih415_output_delays, \
.noutput_delays = 4
static const struct st_pctl_data stih415_sbc_data = {
STIH415_PCTRL_COMMON_DATA,
.alt = 0, .oe = 5, .pu = 7, .od = 9, .rt = 16,
};
static const struct st_pctl_data stih415_front_data = {
STIH415_PCTRL_COMMON_DATA,
.alt = 0, .oe = 8, .pu = 10, .od = 12, .rt = 16,
};
static const struct st_pctl_data stih415_rear_data = {
STIH415_PCTRL_COMMON_DATA,
.alt = 0, .oe = 6, .pu = 8, .od = 10, .rt = 38,
};
static const struct st_pctl_data stih415_left_data = {
STIH415_PCTRL_COMMON_DATA,
.alt = 0, .oe = 3, .pu = 4, .od = 5, .rt = 6,
};
static const struct st_pctl_data stih415_right_data = {
STIH415_PCTRL_COMMON_DATA,
.alt = 0, .oe = 5, .pu = 7, .od = 9, .rt = 11,
};
/* STiH416 data */
unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500,
1750, 2000, 2250, 2500, 2750, 3000, 3250 };
static const struct st_pctl_data stih416_data = {
.rt_style = st_retime_style_dedicated,
.input_delays = stih416_delays,
.ninput_delays = 14,
.output_delays = stih416_delays,
.noutput_delays = 14,
.alt = 0, .oe = 40, .pu = 50, .od = 60, .rt = 100,
};
/* Low level functions.. */
static inline int st_gpio_bank(int gpio)
{
return gpio/ST_GPIO_PINS_PER_BANK;
}
static inline int st_gpio_pin(int gpio)
{
return gpio%ST_GPIO_PINS_PER_BANK;
}
static void st_pinconf_set_config(struct st_pio_control *pc,
int pin, unsigned long config)
{
struct regmap_field *output_enable = pc->oe;
struct regmap_field *pull_up = pc->pu;
struct regmap_field *open_drain = pc->od;
unsigned int oe_value, pu_value, od_value;
unsigned long mask = BIT(pin);
regmap_field_read(output_enable, &oe_value);
regmap_field_read(pull_up, &pu_value);
regmap_field_read(open_drain, &od_value);
/* Clear old values */
oe_value &= ~mask;
pu_value &= ~mask;
od_value &= ~mask;
if (config & ST_PINCONF_OE)
oe_value |= mask;
if (config & ST_PINCONF_PU)
pu_value |= mask;
if (config & ST_PINCONF_OD)
od_value |= mask;
regmap_field_write(output_enable, oe_value);
regmap_field_write(pull_up, pu_value);
regmap_field_write(open_drain, od_value);
}
static void st_pctl_set_function(struct st_pio_control *pc,
int pin_id, int function)
{
struct regmap_field *alt = pc->alt;
unsigned int val;
int pin = st_gpio_pin(pin_id);
int offset = pin * 4;
regmap_field_read(alt, &val);
val &= ~(0xf << offset);
val |= function << offset;
regmap_field_write(alt, val);
}
static unsigned long st_pinconf_delay_to_bit(unsigned int delay,
const struct st_pctl_data *data, unsigned long config)
{
unsigned int *delay_times;
int num_delay_times, i, closest_index = -1;
unsigned int closest_divergence = UINT_MAX;
if (ST_PINCONF_UNPACK_OE(config)) {
delay_times = data->output_delays;
num_delay_times = data->noutput_delays;
} else {
delay_times = data->input_delays;
num_delay_times = data->ninput_delays;
}
for (i = 0; i < num_delay_times; i++) {
unsigned int divergence = abs(delay - delay_times[i]);
if (divergence == 0)
return i;
if (divergence < closest_divergence) {
closest_divergence = divergence;
closest_index = i;
}
}
pr_warn("Attempt to set delay %d, closest available %d\n",
delay, delay_times[closest_index]);
return closest_index;
}
static unsigned long st_pinconf_bit_to_delay(unsigned int index,
const struct st_pctl_data *data, unsigned long output)
{
unsigned int *delay_times;
int num_delay_times;
if (output) {
delay_times = data->output_delays;
num_delay_times = data->noutput_delays;
} else {
delay_times = data->input_delays;
num_delay_times = data->ninput_delays;
}
if (index < num_delay_times) {
return delay_times[index];
} else {
pr_warn("Delay not found in/out delay list\n");
return 0;
}
}
static void st_regmap_field_bit_set_clear_pin(struct regmap_field *field,
int enable, int pin)
{
unsigned int val = 0;
regmap_field_read(field, &val);
if (enable)
val |= BIT(pin);
else
val &= ~BIT(pin);
regmap_field_write(field, val);
}
static void st_pinconf_set_retime_packed(struct st_pinctrl *info,
struct st_pio_control *pc, unsigned long config, int pin)
{
const struct st_pctl_data *data = info->data;
struct st_retime_packed *rt_p = &pc->rt.rt_p;
unsigned int delay;
st_regmap_field_bit_set_clear_pin(rt_p->clk1notclk0,
ST_PINCONF_UNPACK_RT_CLK(config), pin);
st_regmap_field_bit_set_clear_pin(rt_p->clknotdata,
ST_PINCONF_UNPACK_RT_CLKNOTDATA(config), pin);
st_regmap_field_bit_set_clear_pin(rt_p->double_edge,
ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config), pin);
st_regmap_field_bit_set_clear_pin(rt_p->invertclk,
ST_PINCONF_UNPACK_RT_INVERTCLK(config), pin);
st_regmap_field_bit_set_clear_pin(rt_p->retime,
ST_PINCONF_UNPACK_RT(config), pin);
delay = st_pinconf_delay_to_bit(ST_PINCONF_UNPACK_RT_DELAY(config),
data, config);
/* 2 bit delay, lsb */
st_regmap_field_bit_set_clear_pin(rt_p->delay_0, delay & 0x1, pin);
/* 2 bit delay, msb */
st_regmap_field_bit_set_clear_pin(rt_p->delay_1, delay & 0x2, pin);
}
static void st_pinconf_set_retime_dedicated(struct st_pinctrl *info,
struct st_pio_control *pc, unsigned long config, int pin)
{
int input = ST_PINCONF_UNPACK_OE(config) ? 0 : 1;
int clk = ST_PINCONF_UNPACK_RT_CLK(config);
int clknotdata = ST_PINCONF_UNPACK_RT_CLKNOTDATA(config);
int double_edge = ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
int invertclk = ST_PINCONF_UNPACK_RT_INVERTCLK(config);
int retime = ST_PINCONF_UNPACK_RT(config);
unsigned long delay = st_pinconf_delay_to_bit(
ST_PINCONF_UNPACK_RT_DELAY(config),
info->data, config);
struct st_retime_dedicated *rt_d = &pc->rt.rt_d;
unsigned long retime_config =
((clk) << RT_D_CFG_CLK_SHIFT) |
((delay) << RT_D_CFG_DELAY_SHIFT) |
((input) << RT_D_CFG_DELAY_INNOTOUT_SHIFT) |
((retime) << RT_D_CFG_RETIME_SHIFT) |
((clknotdata) << RT_D_CFG_CLKNOTDATA_SHIFT) |
((invertclk) << RT_D_CFG_INVERTCLK_SHIFT) |
((double_edge) << RT_D_CFG_DOUBLE_EDGE_SHIFT);
regmap_field_write(rt_d->rt[pin], retime_config);
}
static void st_pinconf_get_direction(struct st_pio_control *pc,
int pin, unsigned long *config)
{
unsigned int oe_value, pu_value, od_value;
regmap_field_read(pc->oe, &oe_value);
regmap_field_read(pc->pu, &pu_value);
regmap_field_read(pc->od, &od_value);
if (oe_value & BIT(pin))
ST_PINCONF_PACK_OE(*config);
if (pu_value & BIT(pin))
ST_PINCONF_PACK_PU(*config);
if (od_value & BIT(pin))
ST_PINCONF_PACK_OD(*config);
}
static int st_pinconf_get_retime_packed(struct st_pinctrl *info,
struct st_pio_control *pc, int pin, unsigned long *config)
{
const struct st_pctl_data *data = info->data;
struct st_retime_packed *rt_p = &pc->rt.rt_p;
unsigned int delay_bits, delay, delay0, delay1, val;
int output = ST_PINCONF_UNPACK_OE(*config);
if (!regmap_field_read(rt_p->retime, &val) && (val & BIT(pin)))
ST_PINCONF_PACK_RT(*config);
if (!regmap_field_read(rt_p->clk1notclk0, &val) && (val & BIT(pin)))
ST_PINCONF_PACK_RT_CLK(*config, 1);
if (!regmap_field_read(rt_p->clknotdata, &val) && (val & BIT(pin)))
ST_PINCONF_PACK_RT_CLKNOTDATA(*config);
if (!regmap_field_read(rt_p->double_edge, &val) && (val & BIT(pin)))
ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config);
if (!regmap_field_read(rt_p->invertclk, &val) && (val & BIT(pin)))
ST_PINCONF_PACK_RT_INVERTCLK(*config);
regmap_field_read(rt_p->delay_0, &delay0);
regmap_field_read(rt_p->delay_1, &delay1);
delay_bits = (((delay1 & BIT(pin)) ? 1 : 0) << 1) |
(((delay0 & BIT(pin)) ? 1 : 0));
delay = st_pinconf_bit_to_delay(delay_bits, data, output);
ST_PINCONF_PACK_RT_DELAY(*config, delay);
return 0;
}
static int st_pinconf_get_retime_dedicated(struct st_pinctrl *info,
struct st_pio_control *pc, int pin, unsigned long *config)
{
unsigned int value;
unsigned long delay_bits, delay, rt_clk;
int output = ST_PINCONF_UNPACK_OE(*config);
struct st_retime_dedicated *rt_d = &pc->rt.rt_d;
regmap_field_read(rt_d->rt[pin], &value);
rt_clk = (value & RT_D_CFG_CLK_MASK) >> RT_D_CFG_CLK_SHIFT;
ST_PINCONF_PACK_RT_CLK(*config, rt_clk);
delay_bits = (value & RT_D_CFG_DELAY_MASK) >> RT_D_CFG_DELAY_SHIFT;
delay = st_pinconf_bit_to_delay(delay_bits, info->data, output);
ST_PINCONF_PACK_RT_DELAY(*config, delay);
if (value & RT_D_CFG_CLKNOTDATA_MASK)
ST_PINCONF_PACK_RT_CLKNOTDATA(*config);
if (value & RT_D_CFG_DOUBLE_EDGE_MASK)
ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config);
if (value & RT_D_CFG_INVERTCLK_MASK)
ST_PINCONF_PACK_RT_INVERTCLK(*config);
if (value & RT_D_CFG_RETIME_MASK)
ST_PINCONF_PACK_RT(*config);
return 0;
}
/* GPIO related functions */
static inline void __st_gpio_set(struct st_gpio_bank *bank,
unsigned offset, int value)
{
if (value)
writel(BIT(offset), bank->base + REG_PIO_SET_POUT);
else
writel(BIT(offset), bank->base + REG_PIO_CLR_POUT);
}
static void st_gpio_direction(struct st_gpio_bank *bank,
unsigned int gpio, unsigned int direction)
{
int offset = st_gpio_pin(gpio);
int i = 0;
/**
* There are three configuration registers (PIOn_PC0, PIOn_PC1
* and PIOn_PC2) for each port. These are used to configure the
* PIO port pins. Each pin can be configured as an input, output,
* bidirectional, or alternative function pin. Three bits, one bit
* from each of the three registers, configure the corresponding bit of
* the port. Valid bit settings is:
*
* PC2 PC1 PC0 Direction.
* 0 0 0 [Input Weak pull-up]
* 0 0 or 1 1 [Bidirection]
* 0 1 0 [Output]
* 1 0 0 [Input]
*
* PIOn_SET_PC and PIOn_CLR_PC registers are used to set and clear bits
* individually.
*/
for (i = 0; i <= 2; i++) {
if (direction & BIT(i))
writel(BIT(offset), bank->base + REG_PIO_SET_PC(i));
else
writel(BIT(offset), bank->base + REG_PIO_CLR_PC(i));
}
}
static int st_gpio_request(struct gpio_chip *chip, unsigned offset)
{
return pinctrl_request_gpio(chip->base + offset);
}
static void st_gpio_free(struct gpio_chip *chip, unsigned offset)
{
pinctrl_free_gpio(chip->base + offset);
}
static int st_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
return !!(readl(bank->base + REG_PIO_PIN) & BIT(offset));
}
static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
__st_gpio_set(bank, offset, value);
}
static int st_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
pinctrl_gpio_direction_input(chip->base + offset);
return 0;
}
static int st_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
__st_gpio_set(bank, offset, value);
pinctrl_gpio_direction_output(chip->base + offset);
return 0;
}
static int st_gpio_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags)
{
if (WARN_ON(gc->of_gpio_n_cells < 1))
return -EINVAL;
if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
return -EINVAL;
if (gpiospec->args[0] > gc->ngpio)
return -EINVAL;
return gpiospec->args[0];
}
/* Pinctrl Groups */
static int st_pctl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
return info->ngroups;
}
static const char *st_pctl_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
return info->groups[selector].name;
}
static int st_pctl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned selector, const unsigned **pins, unsigned *npins)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
if (selector >= info->ngroups)
return -EINVAL;
*pins = info->groups[selector].pins;
*npins = info->groups[selector].npins;
return 0;
}
static const inline struct st_pctl_group *st_pctl_find_group_by_name(
const struct st_pinctrl *info, const char *name)
{
int i;
for (i = 0; i < info->ngroups; i++) {
if (!strcmp(info->groups[i].name, name))
return &info->groups[i];
}
return NULL;
}
static int st_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
const struct st_pctl_group *grp;
struct pinctrl_map *new_map;
struct device_node *parent;
int map_num, i;
grp = st_pctl_find_group_by_name(info, np->name);
if (!grp) {
dev_err(info->dev, "unable to find group for node %s\n",
np->name);
return -EINVAL;
}
map_num = grp->npins + 1;
new_map = devm_kzalloc(pctldev->dev,
sizeof(*new_map) * map_num, GFP_KERNEL);
if (!new_map)
return -ENOMEM;
parent = of_get_parent(np);
if (!parent) {
devm_kfree(pctldev->dev, new_map);
return -EINVAL;
}
*map = new_map;
*num_maps = map_num;
new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
new_map[0].data.mux.function = parent->name;
new_map[0].data.mux.group = np->name;
of_node_put(parent);
/* create config map per pin */
new_map++;
for (i = 0; i < grp->npins; i++) {
new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
new_map[i].data.configs.group_or_pin =
pin_get_name(pctldev, grp->pins[i]);
new_map[i].data.configs.configs = &grp->pin_conf[i].config;
new_map[i].data.configs.num_configs = 1;
}
dev_info(pctldev->dev, "maps: function %s group %s num %d\n",
(*map)->data.mux.function, grp->name, map_num);
return 0;
}
static void st_pctl_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
}
static struct pinctrl_ops st_pctlops = {
.get_groups_count = st_pctl_get_groups_count,
.get_group_pins = st_pctl_get_group_pins,
.get_group_name = st_pctl_get_group_name,
.dt_node_to_map = st_pctl_dt_node_to_map,
.dt_free_map = st_pctl_dt_free_map,
};
/* Pinmux */
static int st_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
return info->nfunctions;
}
const char *st_pmx_get_fname(struct pinctrl_dev *pctldev,
unsigned selector)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
return info->functions[selector].name;
}
static int st_pmx_get_groups(struct pinctrl_dev *pctldev,
unsigned selector, const char * const **grps, unsigned * const ngrps)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
*grps = info->functions[selector].groups;
*ngrps = info->functions[selector].ngroups;
return 0;
}
static struct st_pio_control *st_get_pio_control(
struct pinctrl_dev *pctldev, int pin)
{
struct pinctrl_gpio_range *range =
pinctrl_find_gpio_range_from_pin(pctldev, pin);
struct st_gpio_bank *bank = gpio_range_to_bank(range);
return &bank->pc;
}
static int st_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector,
unsigned group)
{
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
struct st_pinconf *conf = info->groups[group].pin_conf;
struct st_pio_control *pc;
int i;
for (i = 0; i < info->groups[group].npins; i++) {
pc = st_get_pio_control(pctldev, conf[i].pin);
st_pctl_set_function(pc, conf[i].pin, conf[i].altfunc);
}
return 0;
}
static void st_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
unsigned group)
{
}
static int st_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range, unsigned gpio,
bool input)
{
struct st_gpio_bank *bank = gpio_range_to_bank(range);
/*
* When a PIO bank is used in its primary function mode (altfunc = 0)
* Output Enable (OE), Open Drain(OD), and Pull Up (PU)
* for the primary PIO functions are driven by the related PIO block
*/
st_pctl_set_function(&bank->pc, gpio, 0);
st_gpio_direction(bank, gpio, input ?
ST_GPIO_DIRECTION_IN : ST_GPIO_DIRECTION_OUT);
return 0;
}
static struct pinmux_ops st_pmxops = {
.get_functions_count = st_pmx_get_funcs_count,
.get_function_name = st_pmx_get_fname,
.get_function_groups = st_pmx_get_groups,
.enable = st_pmx_enable,
.disable = st_pmx_disable,
.gpio_set_direction = st_pmx_set_gpio_direction,
};
/* Pinconf */
static void st_pinconf_get_retime(struct st_pinctrl *info,
struct st_pio_control *pc, int pin, unsigned long *config)
{
if (info->data->rt_style == st_retime_style_packed)
st_pinconf_get_retime_packed(info, pc, pin, config);
else if (info->data->rt_style == st_retime_style_dedicated)
if ((BIT(pin) & pc->rt_pin_mask))
st_pinconf_get_retime_dedicated(info, pc,
pin, config);
}
static void st_pinconf_set_retime(struct st_pinctrl *info,
struct st_pio_control *pc, int pin, unsigned long config)
{
if (info->data->rt_style == st_retime_style_packed)
st_pinconf_set_retime_packed(info, pc, config, pin);
else if (info->data->rt_style == st_retime_style_dedicated)
if ((BIT(pin) & pc->rt_pin_mask))
st_pinconf_set_retime_dedicated(info, pc,
config, pin);
}
static int st_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin_id, unsigned long config)
{
int pin = st_gpio_pin(pin_id);
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id);
st_pinconf_set_config(pc, pin, config);
st_pinconf_set_retime(info, pc, pin, config);
return 0;
}
static int st_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin_id, unsigned long *config)
{
int pin = st_gpio_pin(pin_id);
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id);
*config = 0;
st_pinconf_get_direction(pc, pin, config);
st_pinconf_get_retime(info, pc, pin, config);
return 0;
}
static void st_pinconf_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned pin_id)
{
unsigned long config;
st_pinconf_get(pctldev, pin_id, &config);
seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n"
"\t\t[retime:%ld,invclk:%ld,clknotdat:%ld,"
"de:%ld,rt-clk:%ld,rt-delay:%ld]",
ST_PINCONF_UNPACK_OE(config),
ST_PINCONF_UNPACK_PU(config),
ST_PINCONF_UNPACK_OD(config),
ST_PINCONF_UNPACK_RT(config),
ST_PINCONF_UNPACK_RT_INVERTCLK(config),
ST_PINCONF_UNPACK_RT_CLKNOTDATA(config),
ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config),
ST_PINCONF_UNPACK_RT_CLK(config),
ST_PINCONF_UNPACK_RT_DELAY(config));
}
static struct pinconf_ops st_confops = {
.pin_config_get = st_pinconf_get,
.pin_config_set = st_pinconf_set,
.pin_config_dbg_show = st_pinconf_dbg_show,
};
static void st_pctl_dt_child_count(struct st_pinctrl *info,
struct device_node *np)
{
struct device_node *child;
for_each_child_of_node(np, child) {
if (of_property_read_bool(child, "gpio-controller")) {
info->nbanks++;
} else {
info->nfunctions++;
info->ngroups += of_get_child_count(child);
}
}
}
static int st_pctl_dt_setup_retime_packed(struct st_pinctrl *info,
int bank, struct st_pio_control *pc)
{
struct device *dev = info->dev;
struct regmap *rm = info->regmap;
const struct st_pctl_data *data = info->data;
/* 2 registers per bank */
int reg = (data->rt + bank * RT_P_CFGS_PER_BANK) * 4;
struct st_retime_packed *rt_p = &pc->rt.rt_p;
/* cfg0 */
struct reg_field clk1notclk0 = RT_P_CFG0_CLK1NOTCLK0_FIELD(reg);
struct reg_field delay_0 = RT_P_CFG0_DELAY_0_FIELD(reg);
struct reg_field delay_1 = RT_P_CFG0_DELAY_1_FIELD(reg);
/* cfg1 */
struct reg_field invertclk = RT_P_CFG1_INVERTCLK_FIELD(reg + 4);
struct reg_field retime = RT_P_CFG1_RETIME_FIELD(reg + 4);
struct reg_field clknotdata = RT_P_CFG1_CLKNOTDATA_FIELD(reg + 4);
struct reg_field double_edge = RT_P_CFG1_DOUBLE_EDGE_FIELD(reg + 4);
rt_p->clk1notclk0 = devm_regmap_field_alloc(dev, rm, clk1notclk0);
rt_p->delay_0 = devm_regmap_field_alloc(dev, rm, delay_0);
rt_p->delay_1 = devm_regmap_field_alloc(dev, rm, delay_1);
rt_p->invertclk = devm_regmap_field_alloc(dev, rm, invertclk);
rt_p->retime = devm_regmap_field_alloc(dev, rm, retime);
rt_p->clknotdata = devm_regmap_field_alloc(dev, rm, clknotdata);
rt_p->double_edge = devm_regmap_field_alloc(dev, rm, double_edge);
if (IS_ERR(rt_p->clk1notclk0) || IS_ERR(rt_p->delay_0) ||
IS_ERR(rt_p->delay_1) || IS_ERR(rt_p->invertclk) ||
IS_ERR(rt_p->retime) || IS_ERR(rt_p->clknotdata) ||
IS_ERR(rt_p->double_edge))
return -EINVAL;
return 0;
}
static int st_pctl_dt_setup_retime_dedicated(struct st_pinctrl *info,
int bank, struct st_pio_control *pc)
{
struct device *dev = info->dev;
struct regmap *rm = info->regmap;
const struct st_pctl_data *data = info->data;
/* 8 registers per bank */
int reg_offset = (data->rt + bank * RT_D_CFGS_PER_BANK) * 4;
struct st_retime_dedicated *rt_d = &pc->rt.rt_d;
unsigned int j;
u32 pin_mask = pc->rt_pin_mask;
for (j = 0; j < RT_D_CFGS_PER_BANK; j++) {
if (BIT(j) & pin_mask) {
struct reg_field reg = REG_FIELD(reg_offset, 0, 31);
rt_d->rt[j] = devm_regmap_field_alloc(dev, rm, reg);
if (IS_ERR(rt_d->rt[j]))
return -EINVAL;
reg_offset += 4;
}
}
return 0;
}
static int st_pctl_dt_setup_retime(struct st_pinctrl *info,
int bank, struct st_pio_control *pc)
{
const struct st_pctl_data *data = info->data;
if (data->rt_style == st_retime_style_packed)
return st_pctl_dt_setup_retime_packed(info, bank, pc);
else if (data->rt_style == st_retime_style_dedicated)
return st_pctl_dt_setup_retime_dedicated(info, bank, pc);
return -EINVAL;
}
static int st_parse_syscfgs(struct st_pinctrl *info,
int bank, struct device_node *np)
{
const struct st_pctl_data *data = info->data;
/**
* For a given shared register like OE/PU/OD, there are 8 bits per bank
* 0:7 belongs to bank0, 8:15 belongs to bank1 ...
* So each register is shared across 4 banks.
*/
int lsb = (bank%4) * ST_GPIO_PINS_PER_BANK;
int msb = lsb + ST_GPIO_PINS_PER_BANK - 1;
struct reg_field alt_reg = REG_FIELD((data->alt + bank) * 4, 0, 31);
struct reg_field oe_reg = REG_FIELD((data->oe + bank/4) * 4, lsb, msb);
struct reg_field pu_reg = REG_FIELD((data->pu + bank/4) * 4, lsb, msb);
struct reg_field od_reg = REG_FIELD((data->od + bank/4) * 4, lsb, msb);
struct st_pio_control *pc = &info->banks[bank].pc;
struct device *dev = info->dev;
struct regmap *regmap = info->regmap;
pc->alt = devm_regmap_field_alloc(dev, regmap, alt_reg);
pc->oe = devm_regmap_field_alloc(dev, regmap, oe_reg);
pc->pu = devm_regmap_field_alloc(dev, regmap, pu_reg);
pc->od = devm_regmap_field_alloc(dev, regmap, od_reg);
if (IS_ERR(pc->alt) || IS_ERR(pc->oe) ||
IS_ERR(pc->pu) || IS_ERR(pc->od))
return -EINVAL;
/* retime avaiable for all pins by default */
pc->rt_pin_mask = 0xff;
of_property_read_u32(np, "st,retime-pin-mask", &pc->rt_pin_mask);
st_pctl_dt_setup_retime(info, bank, pc);
return 0;
}
/*
* Each pin is represented in of the below forms.
* <bank offset mux direction rt_type rt_delay rt_clk>
*/
static int st_pctl_dt_parse_groups(struct device_node *np,
struct st_pctl_group *grp, struct st_pinctrl *info, int idx)
{
/* bank pad direction val altfunction */
const __be32 *list;
struct property *pp;
struct st_pinconf *conf;
phandle phandle;
struct device_node *pins;
u32 pin;
int i = 0, npins = 0, nr_props;
pins = of_get_child_by_name(np, "st,pins");
if (!pins)
return -ENODATA;
for_each_property_of_node(pins, pp) {
/* Skip those we do not want to proceed */
if (!strcmp(pp->name, "name"))
continue;
if (pp && (pp->length/sizeof(__be32)) >= OF_GPIO_ARGS_MIN) {
npins++;
} else {
pr_warn("Invalid st,pins in %s node\n", np->name);
return -EINVAL;
}
}
grp->npins = npins;
grp->name = np->name;
grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL);
grp->pin_conf = devm_kzalloc(info->dev,
npins * sizeof(*conf), GFP_KERNEL);
if (!grp->pins || !grp->pin_conf)
return -ENOMEM;
/* <bank offset mux direction rt_type rt_delay rt_clk> */
for_each_property_of_node(pins, pp) {
if (!strcmp(pp->name, "name"))
continue;
nr_props = pp->length/sizeof(u32);
list = pp->value;
conf = &grp->pin_conf[i];
/* bank & offset */
phandle = be32_to_cpup(list++);
pin = be32_to_cpup(list++);
conf->pin = of_get_named_gpio(pins, pp->name, 0);
conf->name = pp->name;
grp->pins[i] = conf->pin;
/* mux */
conf->altfunc = be32_to_cpup(list++);
conf->config = 0;
/* direction */
conf->config |= be32_to_cpup(list++);
/* rt_type rt_delay rt_clk */
if (nr_props >= OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN) {
/* rt_type */
conf->config |= be32_to_cpup(list++);
/* rt_delay */
conf->config |= be32_to_cpup(list++);
/* rt_clk */
if (nr_props > OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN)
conf->config |= be32_to_cpup(list++);
}
i++;
}
of_node_put(pins);
return 0;
}
static int st_pctl_parse_functions(struct device_node *np,
struct st_pinctrl *info, u32 index, int *grp_index)
{
struct device_node *child;
struct st_pmx_func *func;
struct st_pctl_group *grp;
int ret, i;
func = &info->functions[index];
func->name = np->name;
func->ngroups = of_get_child_count(np);
if (func->ngroups <= 0) {
dev_err(info->dev, "No groups defined\n");
return -EINVAL;
}
func->groups = devm_kzalloc(info->dev,
func->ngroups * sizeof(char *), GFP_KERNEL);
if (!func->groups)
return -ENOMEM;
i = 0;
for_each_child_of_node(np, child) {
func->groups[i] = child->name;
grp = &info->groups[*grp_index];
*grp_index += 1;
ret = st_pctl_dt_parse_groups(child, grp, info, i++);
if (ret)
return ret;
}
dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n",
index, func->name, func->ngroups);
return 0;
}
static struct gpio_chip st_gpio_template = {
.request = st_gpio_request,
.free = st_gpio_free,
.get = st_gpio_get,
.set = st_gpio_set,
.direction_input = st_gpio_direction_input,
.direction_output = st_gpio_direction_output,
.ngpio = ST_GPIO_PINS_PER_BANK,
.of_gpio_n_cells = 1,
.of_xlate = st_gpio_xlate,
};
static int st_gpiolib_register_bank(struct st_pinctrl *info,
int bank_nr, struct device_node *np)
{
struct st_gpio_bank *bank = &info->banks[bank_nr];
struct pinctrl_gpio_range *range = &bank->range;
struct device *dev = info->dev;
int bank_num = of_alias_get_id(np, "gpio");
struct resource res;
int err;
if (of_address_to_resource(np, 0, &res))
return -ENODEV;
bank->base = devm_request_and_ioremap(dev, &res);
if (!bank->base) {
dev_err(dev, "Can't get IO memory mapping!\n");
return -ENODEV;
}
bank->gpio_chip = st_gpio_template;
bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.of_node = np;
of_property_read_string(np, "st,bank-name", &range->name);
bank->gpio_chip.label = range->name;
range->id = bank_num;
range->pin_base = range->base = range->id * ST_GPIO_PINS_PER_BANK;
range->npins = bank->gpio_chip.ngpio;
range->gc = &bank->gpio_chip;
err = gpiochip_add(&bank->gpio_chip);
if (err) {
dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_num);
return err;
}
dev_info(dev, "%s bank added.\n", range->name);
return 0;
}
static struct of_device_id st_pctl_of_match[] = {
{ .compatible = "st,stih415-sbc-pinctrl", .data = &stih415_sbc_data },
{ .compatible = "st,stih415-rear-pinctrl", .data = &stih415_rear_data },
{ .compatible = "st,stih415-left-pinctrl", .data = &stih415_left_data },
{ .compatible = "st,stih415-right-pinctrl",
.data = &stih415_right_data },
{ .compatible = "st,stih415-front-pinctrl",
.data = &stih415_front_data },
{ .compatible = "st,stih416-sbc-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-front-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-rear-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-fvdp-fe-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-fvdp-lite-pinctrl", .data = &stih416_data},
{ /* sentinel */ }
};
static int st_pctl_probe_dt(struct platform_device *pdev,
struct pinctrl_desc *pctl_desc, struct st_pinctrl *info)
{
int ret = 0;
int i = 0, j = 0, k = 0, bank;
struct pinctrl_pin_desc *pdesc;
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
int grp_index = 0;
st_pctl_dt_child_count(info, np);
if (!info->nbanks) {
dev_err(&pdev->dev, "you need atleast one gpio bank\n");
return -EINVAL;
}
dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks);
dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups);
info->functions = devm_kzalloc(&pdev->dev,
info->nfunctions * sizeof(*info->functions), GFP_KERNEL);
info->groups = devm_kzalloc(&pdev->dev,
info->ngroups * sizeof(*info->groups) , GFP_KERNEL);
info->banks = devm_kzalloc(&pdev->dev,
info->nbanks * sizeof(*info->banks), GFP_KERNEL);
if (!info->functions || !info->groups || !info->banks)
return -ENOMEM;
info->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(info->regmap)) {
dev_err(info->dev, "No syscfg phandle specified\n");
return PTR_ERR(info->regmap);
}
info->data = of_match_node(st_pctl_of_match, np)->data;
pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK;
pdesc = devm_kzalloc(&pdev->dev,
sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL);
if (!pdesc)
return -ENOMEM;
pctl_desc->pins = pdesc;
bank = 0;
for_each_child_of_node(np, child) {
if (of_property_read_bool(child, "gpio-controller")) {
const char *bank_name = NULL;
ret = st_gpiolib_register_bank(info, bank, child);
if (ret)
return ret;
k = info->banks[bank].range.pin_base;
bank_name = info->banks[bank].range.name;
for (j = 0; j < ST_GPIO_PINS_PER_BANK; j++, k++) {
pdesc->number = k;
pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]",
bank_name, j);
pdesc++;
}
st_parse_syscfgs(info, bank, child);
bank++;
} else {
ret = st_pctl_parse_functions(child, info,
i++, &grp_index);
if (ret) {
dev_err(&pdev->dev, "No functions found.\n");
return ret;
}
}
}
return 0;
}
static int st_pctl_probe(struct platform_device *pdev)
{
struct st_pinctrl *info;
struct pinctrl_desc *pctl_desc;
int ret, i;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "device node not found.\n");
return -EINVAL;
}
pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
if (!pctl_desc)
return -ENOMEM;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->dev = &pdev->dev;
platform_set_drvdata(pdev, info);
ret = st_pctl_probe_dt(pdev, pctl_desc, info);
if (ret)
return ret;
pctl_desc->owner = THIS_MODULE,
pctl_desc->pctlops = &st_pctlops,
pctl_desc->pmxops = &st_pmxops,
pctl_desc->confops = &st_confops,
pctl_desc->name = dev_name(&pdev->dev);
info->pctl = pinctrl_register(pctl_desc, &pdev->dev, info);
if (!info->pctl) {
dev_err(&pdev->dev, "Failed pinctrl registration\n");
return -EINVAL;
}
for (i = 0; i < info->nbanks; i++)
pinctrl_add_gpio_range(info->pctl, &info->banks[i].range);
return 0;
}
static struct platform_driver st_pctl_driver = {
.driver = {
.name = "st-pinctrl",
.owner = THIS_MODULE,
.of_match_table = st_pctl_of_match,
},
.probe = st_pctl_probe,
};
static int __init st_pctl_init(void)
{
return platform_driver_register(&st_pctl_driver);
}
arch_initcall(st_pctl_init);
...@@ -23,6 +23,7 @@ struct irq_domain; ...@@ -23,6 +23,7 @@ struct irq_domain;
struct spi_device; struct spi_device;
struct regmap; struct regmap;
struct regmap_range_cfg; struct regmap_range_cfg;
struct regmap_field;
/* An enum of all the supported cache types */ /* An enum of all the supported cache types */
enum regcache_type { enum regcache_type {
...@@ -394,10 +395,15 @@ bool regmap_can_raw_write(struct regmap *map); ...@@ -394,10 +395,15 @@ bool regmap_can_raw_write(struct regmap *map);
int regcache_sync(struct regmap *map); int regcache_sync(struct regmap *map);
int regcache_sync_region(struct regmap *map, unsigned int min, int regcache_sync_region(struct regmap *map, unsigned int min,
unsigned int max); unsigned int max);
int regcache_drop_region(struct regmap *map, unsigned int min,
unsigned int max);
void regcache_cache_only(struct regmap *map, bool enable); void regcache_cache_only(struct regmap *map, bool enable);
void regcache_cache_bypass(struct regmap *map, bool enable); void regcache_cache_bypass(struct regmap *map, bool enable);
void regcache_mark_dirty(struct regmap *map); void regcache_mark_dirty(struct regmap *map);
bool regmap_check_range_table(struct regmap *map, unsigned int reg,
const struct regmap_access_table *table);
int regmap_register_patch(struct regmap *map, const struct reg_default *regs, int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs); int num_regs);
...@@ -411,6 +417,36 @@ bool regmap_reg_in_ranges(unsigned int reg, ...@@ -411,6 +417,36 @@ bool regmap_reg_in_ranges(unsigned int reg,
const struct regmap_range *ranges, const struct regmap_range *ranges,
unsigned int nranges); unsigned int nranges);
/**
* Description of an register field
*
* @reg: Offset of the register within the regmap bank
* @lsb: lsb of the register field.
* @reg: msb of the register field.
*/
struct reg_field {
unsigned int reg;
unsigned int lsb;
unsigned int msb;
};
#define REG_FIELD(_reg, _lsb, _msb) { \
.reg = _reg, \
.lsb = _lsb, \
.msb = _msb, \
}
struct regmap_field *regmap_field_alloc(struct regmap *regmap,
struct reg_field reg_field);
void regmap_field_free(struct regmap_field *field);
struct regmap_field *devm_regmap_field_alloc(struct device *dev,
struct regmap *regmap, struct reg_field reg_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_write(struct regmap_field *field, unsigned int val);
/** /**
* Description of an IRQ for the generic regmap irq_chip. * Description of an IRQ for the generic regmap irq_chip.
* *
...@@ -562,6 +598,13 @@ static inline int regcache_sync_region(struct regmap *map, unsigned int min, ...@@ -562,6 +598,13 @@ static inline int regcache_sync_region(struct regmap *map, unsigned int min,
return -EINVAL; return -EINVAL;
} }
static inline int regcache_drop_region(struct regmap *map, unsigned int min,
unsigned int max)
{
WARN_ONCE(1, "regmap API is disabled");
return -EINVAL;
}
static inline void regcache_cache_only(struct regmap *map, bool enable) static inline void regcache_cache_only(struct regmap *map, bool enable)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
......
...@@ -223,6 +223,29 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_done, ...@@ -223,6 +223,29 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_done,
); );
TRACE_EVENT(regcache_drop_region,
TP_PROTO(struct device *dev, unsigned int from,
unsigned int to),
TP_ARGS(dev, from, to),
TP_STRUCT__entry(
__string( name, dev_name(dev) )
__field( unsigned int, from )
__field( unsigned int, to )
),
TP_fast_assign(
__assign_str(name, dev_name(dev));
__entry->from = from;
__entry->to = to;
),
TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from,
(unsigned int)__entry->to)
);
#endif /* _TRACE_REGMAP_H */ #endif /* _TRACE_REGMAP_H */
/* This part must be outside protection */ /* This part must be outside protection */
......
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