aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/sh-pfc/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/sh-pfc/core.c')
-rw-r--r--drivers/pinctrl/sh-pfc/core.c302
1 files changed, 84 insertions, 218 deletions
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 970ddff2b0b6..b551336924a5 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -10,7 +10,6 @@
*/
#define DRV_NAME "sh-pfc"
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <linux/err.h>
@@ -30,10 +29,8 @@ static int sh_pfc_ioremap(struct sh_pfc *pfc, struct platform_device *pdev)
struct resource *res;
int k;
- if (pdev->num_resources == 0) {
- pfc->num_windows = 0;
- return 0;
- }
+ if (pdev->num_resources == 0)
+ return -EINVAL;
pfc->window = devm_kzalloc(pfc->dev, pdev->num_resources *
sizeof(*pfc->window), GFP_NOWAIT);
@@ -59,11 +56,11 @@ static void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc,
unsigned long address)
{
struct sh_pfc_window *window;
- int k;
+ unsigned int i;
/* scan through physical windows and convert address */
- for (k = 0; k < pfc->num_windows; k++) {
- window = pfc->window + k;
+ for (i = 0; i < pfc->num_windows; i++) {
+ window = pfc->window + i;
if (address < window->phys)
continue;
@@ -74,11 +71,33 @@ static void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc,
return window->virt + (address - window->phys);
}
- /* no windows defined, register must be 1:1 mapped virt:phys */
- return (void __iomem *)address;
+ BUG();
+ return NULL;
+}
+
+int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin)
+{
+ unsigned int offset;
+ unsigned int i;
+
+ if (pfc->info->ranges == NULL)
+ return pin;
+
+ for (i = 0, offset = 0; i < pfc->info->nr_ranges; ++i) {
+ const struct pinmux_range *range = &pfc->info->ranges[i];
+
+ if (pin <= range->end)
+ return pin >= range->begin
+ ? offset + pin - range->begin : -1;
+
+ offset += range->end - range->begin + 1;
+ }
+
+ return -EINVAL;
}
-static int sh_pfc_enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
+static int sh_pfc_enum_in_range(pinmux_enum_t enum_id,
+ const struct pinmux_range *r)
{
if (enum_id < r->begin)
return 0;
@@ -89,8 +108,8 @@ static int sh_pfc_enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
return 1;
}
-static unsigned long sh_pfc_read_raw_reg(void __iomem *mapped_reg,
- unsigned long reg_width)
+unsigned long sh_pfc_read_raw_reg(void __iomem *mapped_reg,
+ unsigned long reg_width)
{
switch (reg_width) {
case 8:
@@ -105,8 +124,8 @@ static unsigned long sh_pfc_read_raw_reg(void __iomem *mapped_reg,
return 0;
}
-static void sh_pfc_write_raw_reg(void __iomem *mapped_reg,
- unsigned long reg_width, unsigned long data)
+void sh_pfc_write_raw_reg(void __iomem *mapped_reg, unsigned long reg_width,
+ unsigned long data)
{
switch (reg_width) {
case 8:
@@ -123,39 +142,8 @@ static void sh_pfc_write_raw_reg(void __iomem *mapped_reg,
BUG();
}
-int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos)
-{
- unsigned long pos;
-
- pos = dr->reg_width - (in_pos + 1);
-
- pr_debug("read_bit: addr = %lx, pos = %ld, "
- "r_width = %ld\n", dr->reg, pos, dr->reg_width);
-
- return (sh_pfc_read_raw_reg(dr->mapped_reg, dr->reg_width) >> pos) & 1;
-}
-
-void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
- unsigned long value)
-{
- unsigned long pos;
-
- pos = dr->reg_width - (in_pos + 1);
-
- pr_debug("write_bit addr = %lx, value = %d, pos = %ld, "
- "r_width = %ld\n",
- dr->reg, !!value, pos, dr->reg_width);
-
- if (value)
- set_bit(pos, &dr->reg_shadow);
- else
- clear_bit(pos, &dr->reg_shadow);
-
- sh_pfc_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
-}
-
static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
- struct pinmux_cfg_reg *crp,
+ const struct pinmux_cfg_reg *crp,
unsigned long in_pos,
void __iomem **mapped_regp,
unsigned long *maskp,
@@ -176,24 +164,8 @@ static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
}
}
-static int sh_pfc_read_config_reg(struct sh_pfc *pfc,
- struct pinmux_cfg_reg *crp,
- unsigned long field)
-{
- void __iomem *mapped_reg;
- unsigned long mask, pos;
-
- sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
-
- pr_debug("read_reg: addr = %lx, field = %ld, "
- "r_width = %ld, f_width = %ld\n",
- crp->reg, field, crp->reg_width, crp->field_width);
-
- return (sh_pfc_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask;
-}
-
static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
- struct pinmux_cfg_reg *crp,
+ const struct pinmux_cfg_reg *crp,
unsigned long field, unsigned long value)
{
void __iomem *mapped_reg;
@@ -201,9 +173,9 @@ static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
- pr_debug("write_reg addr = %lx, value = %ld, field = %ld, "
- "r_width = %ld, f_width = %ld\n",
- crp->reg, value, field, crp->reg_width, crp->field_width);
+ dev_dbg(pfc->dev, "write_reg addr = %lx, value = %ld, field = %ld, "
+ "r_width = %ld, f_width = %ld\n",
+ crp->reg, value, field, crp->reg_width, crp->field_width);
mask = ~(mask << pos);
value = value << pos;
@@ -220,83 +192,11 @@ static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data);
}
-static int sh_pfc_setup_data_reg(struct sh_pfc *pfc, unsigned gpio)
-{
- struct pinmux_gpio *gpiop = &pfc->info->gpios[gpio];
- struct pinmux_data_reg *data_reg;
- int k, n;
-
- if (!sh_pfc_enum_in_range(gpiop->enum_id, &pfc->info->data))
- return -1;
-
- k = 0;
- while (1) {
- data_reg = pfc->info->data_regs + k;
-
- if (!data_reg->reg_width)
- break;
-
- data_reg->mapped_reg = sh_pfc_phys_to_virt(pfc, data_reg->reg);
-
- for (n = 0; n < data_reg->reg_width; n++) {
- if (data_reg->enum_ids[n] == gpiop->enum_id) {
- gpiop->flags &= ~PINMUX_FLAG_DREG;
- gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT);
- gpiop->flags &= ~PINMUX_FLAG_DBIT;
- gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT);
- return 0;
- }
- }
- k++;
- }
-
- BUG();
-
- return -1;
-}
-
-static void sh_pfc_setup_data_regs(struct sh_pfc *pfc)
-{
- struct pinmux_data_reg *drp;
- int k;
-
- for (k = pfc->info->first_gpio; k <= pfc->info->last_gpio; k++)
- sh_pfc_setup_data_reg(pfc, k);
-
- k = 0;
- while (1) {
- drp = pfc->info->data_regs + k;
-
- if (!drp->reg_width)
- break;
-
- drp->reg_shadow = sh_pfc_read_raw_reg(drp->mapped_reg,
- drp->reg_width);
- k++;
- }
-}
-
-int sh_pfc_get_data_reg(struct sh_pfc *pfc, unsigned gpio,
- struct pinmux_data_reg **drp, int *bitp)
-{
- struct pinmux_gpio *gpiop = &pfc->info->gpios[gpio];
- int k, n;
-
- if (!sh_pfc_enum_in_range(gpiop->enum_id, &pfc->info->data))
- return -1;
-
- k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
- n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
- *drp = pfc->info->data_regs + k;
- *bitp = n;
- return 0;
-}
-
static int sh_pfc_get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
- struct pinmux_cfg_reg **crp, int *fieldp,
- int *valuep, unsigned long **cntp)
+ const struct pinmux_cfg_reg **crp, int *fieldp,
+ int *valuep)
{
- struct pinmux_cfg_reg *config_reg;
+ const struct pinmux_cfg_reg *config_reg;
unsigned long r_width, f_width, curr_width, ncomb;
int k, m, n, pos, bit_pos;
@@ -324,7 +224,6 @@ static int sh_pfc_get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
*crp = config_reg;
*fieldp = m;
*valuep = n;
- *cntp = &config_reg->cnt[m];
return 0;
}
}
@@ -334,50 +233,42 @@ static int sh_pfc_get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
k++;
}
- return -1;
+ return -EINVAL;
}
-int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
- pinmux_enum_t *enum_idp)
+static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, pinmux_enum_t mark, int pos,
+ pinmux_enum_t *enum_idp)
{
- pinmux_enum_t enum_id = pfc->info->gpios[gpio].enum_id;
- pinmux_enum_t *data = pfc->info->gpio_data;
+ const pinmux_enum_t *data = pfc->info->gpio_data;
int k;
- if (!sh_pfc_enum_in_range(enum_id, &pfc->info->data)) {
- if (!sh_pfc_enum_in_range(enum_id, &pfc->info->mark)) {
- pr_err("non data/mark enum_id for gpio %d\n", gpio);
- return -1;
- }
- }
-
if (pos) {
*enum_idp = data[pos + 1];
return pos + 1;
}
for (k = 0; k < pfc->info->gpio_data_size; k++) {
- if (data[k] == enum_id) {
+ if (data[k] == mark) {
*enum_idp = data[k + 1];
return k + 1;
}
}
- pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio);
- return -1;
+ dev_err(pfc->dev, "cannot locate data/mark enum_id for mark %d\n",
+ mark);
+ return -EINVAL;
}
-int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
- int cfg_mode)
+int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
{
- struct pinmux_cfg_reg *cr = NULL;
+ const struct pinmux_cfg_reg *cr = NULL;
pinmux_enum_t enum_id;
- struct pinmux_range *range;
+ const struct pinmux_range *range;
int in_range, pos, field, value;
- unsigned long *cntp;
+ int ret;
switch (pinmux_type) {
-
+ case PINMUX_TYPE_GPIO:
case PINMUX_TYPE_FUNCTION:
range = NULL;
break;
@@ -399,33 +290,37 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
break;
default:
- goto out_err;
+ return -EINVAL;
}
pos = 0;
enum_id = 0;
field = 0;
value = 0;
+
+ /* Iterate over all the configuration fields we need to update. */
while (1) {
- pos = sh_pfc_gpio_to_enum(pfc, gpio, pos, &enum_id);
- if (pos <= 0)
- goto out_err;
+ pos = sh_pfc_mark_to_enum(pfc, mark, pos, &enum_id);
+ if (pos < 0)
+ return pos;
if (!enum_id)
break;
- /* first check if this is a function enum */
+ /* Check if the configuration field selects a function. If it
+ * doesn't, skip the field if it's not applicable to the
+ * requested pinmux type.
+ */
in_range = sh_pfc_enum_in_range(enum_id, &pfc->info->function);
if (!in_range) {
- /* not a function enum */
- if (range) {
- /*
- * other range exists, so this pin is
- * a regular GPIO pin that now is being
- * bound to a specific direction.
- *
- * for this case we only allow function enums
- * and the enums that match the other range.
+ if (pinmux_type == PINMUX_TYPE_FUNCTION) {
+ /* Functions are allowed to modify all
+ * fields.
+ */
+ in_range = 1;
+ } else if (pinmux_type != PINMUX_TYPE_GPIO) {
+ /* Input/output types can only modify fields
+ * that correspond to their respective ranges.
*/
in_range = sh_pfc_enum_in_range(enum_id, range);
@@ -436,60 +331,29 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
*/
if (in_range && enum_id == range->force)
continue;
- } else {
- /*
- * no other range exists, so this pin
- * must then be of the function type.
- *
- * allow function type pins to select
- * any combination of function/in/out
- * in their MARK lists.
- */
- in_range = 1;
}
+ /* GPIOs are only allowed to modify function fields. */
}
if (!in_range)
continue;
- if (sh_pfc_get_config_reg(pfc, enum_id, &cr,
- &field, &value, &cntp) != 0)
- goto out_err;
-
- switch (cfg_mode) {
- case GPIO_CFG_DRYRUN:
- if (!*cntp ||
- (sh_pfc_read_config_reg(pfc, cr, field) != value))
- continue;
- break;
-
- case GPIO_CFG_REQ:
- sh_pfc_write_config_reg(pfc, cr, field, value);
- *cntp = *cntp + 1;
- break;
+ ret = sh_pfc_get_config_reg(pfc, enum_id, &cr, &field, &value);
+ if (ret < 0)
+ return ret;
- case GPIO_CFG_FREE:
- *cntp = *cntp - 1;
- break;
- }
+ sh_pfc_write_config_reg(pfc, cr, field, value);
}
return 0;
- out_err:
- return -1;
}
static int sh_pfc_probe(struct platform_device *pdev)
{
- struct sh_pfc_soc_info *info;
+ const struct sh_pfc_soc_info *info;
struct sh_pfc *pfc;
int ret;
- /*
- * Ensure that the type encoding fits
- */
- BUILD_BUG_ON(PINMUX_FLAG_TYPE > ((1 << PINMUX_FLAG_DBIT_SHIFT) - 1));
-
info = pdev->id_entry->driver_data
? (void *)pdev->id_entry->driver_data : pdev->dev.platform_data;
if (info == NULL)
@@ -509,7 +373,6 @@ static int sh_pfc_probe(struct platform_device *pdev)
spin_lock_init(&pfc->lock);
pinctrl_provide_dummies();
- sh_pfc_setup_data_regs(pfc);
/*
* Initialize pinctrl bindings first
@@ -529,13 +392,13 @@ static int sh_pfc_probe(struct platform_device *pdev)
* PFC state as it is, given that there are already
* extant users of it that have succeeded by this point.
*/
- pr_notice("failed to init GPIO chip, ignoring...\n");
+ dev_notice(pfc->dev, "failed to init GPIO chip, ignoring...\n");
}
#endif
platform_set_drvdata(pdev, pfc);
- pr_info("%s support registered\n", info->name);
+ dev_info(pfc->dev, "%s support registered\n", info->name);
return 0;
}
@@ -555,6 +418,9 @@ static int sh_pfc_remove(struct platform_device *pdev)
}
static const struct platform_device_id sh_pfc_id_table[] = {
+#ifdef CONFIG_PINCTRL_PFC_R8A73A4
+ { "pfc-r8a73a4", (kernel_ulong_t)&r8a73a4_pinmux_info },
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7740
{ "pfc-r8a7740", (kernel_ulong_t)&r8a7740_pinmux_info },
#endif