+// SPDX-License-Identifier: GPL-2.0
/*
* Pin Control driver for SuperH Pin Function Controller.
*
* Copyright (C) 2008 Magnus Damm
* Copyright (C) 2009 - 2012 Paul Mundt
* Copyright (C) 2017 Marek Vasut
- *
- * SPDX-License-Identifier: GPL-2.0
*/
#define DRV_NAME "sh-pfc"
#include <common.h>
#include <dm.h>
#include <errno.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include "sh_pfc.h"
-DECLARE_GLOBAL_DATA_PTR;
-
enum sh_pfc_model {
SH_PFC_R8A7790 = 0,
SH_PFC_R8A7791,
SH_PFC_R8A7794,
SH_PFC_R8A7795,
SH_PFC_R8A7796,
+ SH_PFC_R8A774A1,
+ SH_PFC_R8A77965,
SH_PFC_R8A77970,
+ SH_PFC_R8A77980,
+ SH_PFC_R8A77990,
SH_PFC_R8A77995,
};
BUG();
}
-u32 sh_pfc_read_reg(struct sh_pfc *pfc, u32 reg, unsigned int width)
+u32 sh_pfc_read(struct sh_pfc *pfc, u32 reg)
{
- return sh_pfc_read_raw_reg(pfc->regs + reg, width);
+ return sh_pfc_read_raw_reg((void __iomem *)(uintptr_t)reg, 32);
}
-void sh_pfc_write_reg(struct sh_pfc *pfc, u32 reg, unsigned int width, u32 data)
+void sh_pfc_write(struct sh_pfc *pfc, u32 reg, u32 data)
{
void __iomem *unlock_reg =
(void __iomem *)(uintptr_t)pfc->info->unlock_reg;
if (pfc->info->unlock_reg)
sh_pfc_write_raw_reg(unlock_reg, 32, ~data);
- sh_pfc_write_raw_reg(pfc->regs + reg, width, data);
+ sh_pfc_write_raw_reg((void __iomem *)(uintptr_t)reg, 32, data);
}
static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
return 0;
}
-const struct sh_pfc_bias_info *
-sh_pfc_pin_to_bias_info(const struct sh_pfc_bias_info *info,
- unsigned int num, unsigned int pin)
+const struct pinmux_bias_reg *
+sh_pfc_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin,
+ unsigned int *bit)
{
- unsigned int i;
+ unsigned int i, j;
- for (i = 0; i < num; i++)
- if (info[i].pin == pin)
- return &info[i];
+ for (i = 0; pfc->info->bias_regs[i].puen; i++) {
+ for (j = 0; j < ARRAY_SIZE(pfc->info->bias_regs[i].pins); j++) {
+ if (pfc->info->bias_regs[i].pins[j] == pin) {
+ *bit = j;
+ return &pfc->info->bias_regs[i];
+ }
+ }
+ }
- printf("Pin %u is not in bias info list\n", pin);
+ WARN_ONCE(1, "Pin %u is not in bias info list\n", pin);
return NULL;
}
return priv->pfc.info->functions[selector].name;
}
-int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector)
+static int sh_pfc_gpio_request_enable(struct udevice *dev,
+ unsigned pin_selector)
{
struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
struct sh_pfc_pinctrl *pmx = &priv->pmx;
struct sh_pfc *pfc = &priv->pfc;
struct sh_pfc_pin_config *cfg;
const struct sh_pfc_pin *pin = NULL;
- int i, idx;
+ int i, ret, idx;
- for (i = 1; i < pfc->info->nr_pins; i++) {
+ for (i = 0; i < pfc->info->nr_pins; i++) {
if (priv->pfc.info->pins[i].pin != pin_selector)
continue;
if (cfg->type != PINMUX_TYPE_NONE)
return -EBUSY;
- return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO);
+ ret = sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO);
+ if (ret)
+ return ret;
+
+ cfg->type = PINMUX_TYPE_GPIO;
+
+ return 0;
+}
+
+static int sh_pfc_gpio_disable_free(struct udevice *dev,
+ unsigned pin_selector)
+{
+ struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sh_pfc_pinctrl *pmx = &priv->pmx;
+ struct sh_pfc *pfc = &priv->pfc;
+ struct sh_pfc_pin_config *cfg;
+ const struct sh_pfc_pin *pin = NULL;
+ int i, idx;
+
+ for (i = 0; i < pfc->info->nr_pins; i++) {
+ if (priv->pfc.info->pins[i].pin != pin_selector)
+ continue;
+
+ pin = &priv->pfc.info->pins[i];
+ break;
+ }
+
+ if (!pin)
+ return -EINVAL;
+
+ idx = sh_pfc_get_pin_index(pfc, pin->pin);
+ cfg = &pmx->configs[idx];
+
+ cfg->type = PINMUX_TYPE_NONE;
+
+ return 0;
}
static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector,
strength = strength / step - 1;
val = sh_pfc_read_raw_reg(reg, 32);
- val &= ~GENMASK(offset + size - 1, offset);
+ val &= ~GENMASK(offset + 4 - 1, offset);
val |= strength << offset;
if (unlock_reg)
.pinmux_set = sh_pfc_pinctrl_pin_set,
.pinmux_group_set = sh_pfc_pinctrl_group_set,
.set_state = pinctrl_generic_set_state,
+
+ .gpio_request_enable = sh_pfc_gpio_request_enable,
+ .gpio_disable_free = sh_pfc_gpio_disable_free,
};
static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
if (model == SH_PFC_R8A7796)
priv->pfc.info = &r8a7796_pinmux_info;
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A774A1
+ if (model == SH_PFC_R8A774A1)
+ priv->pfc.info = &r8a774a1_pinmux_info;
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77965
+ if (model == SH_PFC_R8A77965)
+ priv->pfc.info = &r8a77965_pinmux_info;
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77970
if (model == SH_PFC_R8A77970)
priv->pfc.info = &r8a77970_pinmux_info;
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77980
+ if (model == SH_PFC_R8A77980)
+ priv->pfc.info = &r8a77980_pinmux_info;
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
+ if (model == SH_PFC_R8A77990)
+ priv->pfc.info = &r8a77990_pinmux_info;
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77995
if (model == SH_PFC_R8A77995)
priv->pfc.info = &r8a77995_pinmux_info;
{
.compatible = "renesas,pfc-r8a7796",
.data = SH_PFC_R8A7796,
- }, {
+ },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A774A1
+ {
+ .compatible = "renesas,pfc-r8a774a1",
+ .data = SH_PFC_R8A774A1,
+ },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77965
+ {
.compatible = "renesas,pfc-r8a77965",
- .data = SH_PFC_R8A7796,
+ .data = SH_PFC_R8A77965,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77970
.data = SH_PFC_R8A77970,
},
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77980
+ {
+ .compatible = "renesas,pfc-r8a77980",
+ .data = SH_PFC_R8A77980,
+ },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
+ {
+ .compatible = "renesas,pfc-r8a77990",
+ .data = SH_PFC_R8A77990,
+ },
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A77995
{
.compatible = "renesas,pfc-r8a77995",