diff mbox series

[RFC,v4,net-next,13/23] pinctrl: ocelot: expose ocelot_pinctrl_core_probe interface

Message ID 20211116062328.1949151-14-colin.foster@in-advantage.com (mailing list archive)
State New, archived
Headers show
Series add support for VSC75XX control over SPI | expand

Commit Message

Colin Foster Nov. 16, 2021, 6:23 a.m. UTC
This is step 2 to allow a custom regmap interface into the driver. This
will allow regmaps that use other interfaces to fully utilize the pinctrl
features.

Signed-off-by: Colin Foster <colin.foster@in-advantage.com>
---
 drivers/pinctrl/pinctrl-ocelot.c | 150 ++++++++++++++++++++-----------
 include/soc/mscc/ocelot.h        |  18 ++++
 2 files changed, 118 insertions(+), 50 deletions(-)
diff mbox series

Patch

diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
index b9acb80d6b3f..f8d2494b335c 100644
--- a/drivers/pinctrl/pinctrl-ocelot.c
+++ b/drivers/pinctrl/pinctrl-ocelot.c
@@ -25,9 +25,6 @@ 
 #include "pinconf.h"
 #include "pinmux.h"
 
-#define ocelot_clrsetbits(addr, clear, set) \
-	writel((readl(addr) & ~(clear)) | (set), (addr))
-
 /* PINCONFIG bits (sparx5 only) */
 enum {
 	PINCONF_BIAS,
@@ -35,6 +32,9 @@  enum {
 	PINCONF_DRIVE_STRENGTH,
 };
 
+#define ocelot_pinctrl_determine_stride(desc) \
+	(1 + (desc->npins - 1) / 32)
+
 #define BIAS_PD_BIT BIT(4)
 #define BIAS_PU_BIT BIT(3)
 #define BIAS_BITS   (BIAS_PD_BIT|BIAS_PU_BIT)
@@ -149,10 +149,13 @@  struct ocelot_pin_caps {
 
 struct ocelot_pinctrl {
 	struct device *dev;
+	struct device_node *node;
 	struct pinctrl_dev *pctl;
 	struct gpio_chip gpio_chip;
 	struct regmap *map;
+	u32 regmap_offset;
 	struct regmap *pincfg;
+	u32 pincfg_offset;
 	struct pinctrl_desc *desc;
 	struct ocelot_pmx_func func[FUNC_MAX];
 	u8 stride;
@@ -714,7 +717,8 @@  static int ocelot_pin_function_idx(struct ocelot_pinctrl *info,
 	return -1;
 }
 
-#define REG_ALT(msb, info, p) (OCELOT_GPIO_ALT0 * (info)->stride + 4 * ((msb) + ((info)->stride * ((p) / 32))))
+#define REG_ALT(msb, info, p) (OCELOT_GPIO_ALT0 * (info)->stride + 4 * ((msb) + \
+			((info)->stride * ((p) / 32))) + (info)->regmap_offset)
 
 static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
 				 unsigned int selector, unsigned int group)
@@ -744,7 +748,8 @@  static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
 	return 0;
 }
 
-#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+#define REG(r, info, p) (((r) * (info)->stride + (4 * ((p) / 32))) + \
+		(info)->regmap_offset)
 
 static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev,
 				     struct pinctrl_gpio_range *range,
@@ -766,10 +771,8 @@  static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev,
 	struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
 	unsigned int p = offset % 32;
 
-	regmap_update_bits(info->map, REG_ALT(0, info, offset),
-			   BIT(p), 0);
-	regmap_update_bits(info->map, REG_ALT(1, info, offset),
-			   BIT(p), 0);
+	regmap_update_bits(info->map, REG_ALT(0, info, offset), BIT(p), 0);
+	regmap_update_bits(info->map, REG_ALT(1, info, offset), BIT(p), 0);
 
 	return 0;
 }
@@ -821,11 +824,11 @@  static int ocelot_hw_get_value(struct ocelot_pinctrl *info,
 	if (info->pincfg) {
 		u32 regcfg;
 
-		ret = regmap_read(info->pincfg, pin, &regcfg);
+		ret = regmap_read(info->pincfg, pin + info->pincfg_offset,
+				  &regcfg);
 		if (ret)
 			return ret;
 
-		ret = 0;
 		switch (reg) {
 		case PINCONF_BIAS:
 			*val = regcfg & BIAS_BITS;
@@ -853,14 +856,14 @@  static int ocelot_pincfg_clrsetbits(struct ocelot_pinctrl *info, u32 regaddr,
 	u32 val;
 	int ret;
 
-	ret = regmap_read(info->pincfg, regaddr, &val);
+	ret = regmap_read(info->pincfg, regaddr + info->pincfg_offset, &val);
 	if (ret)
 		return ret;
 
 	val &= ~clrbits;
 	val |= setbits;
 
-	ret = regmap_write(info->pincfg, regaddr, val);
+	ret = regmap_write(info->pincfg, regaddr + info->pincfg_offset, val);
 
 	return ret;
 }
@@ -873,7 +876,6 @@  static int ocelot_hw_set_value(struct ocelot_pinctrl *info,
 	int ret = -EOPNOTSUPP;
 
 	if (info->pincfg) {
-
 		ret = 0;
 		switch (reg) {
 		case PINCONF_BIAS:
@@ -1019,15 +1021,16 @@  static int ocelot_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
 			if (arg)
 				regmap_write(info->map,
 					     REG(OCELOT_GPIO_OUT_SET, info,
-						 pin),
+						 pin) + info->regmap_offset,
 					     BIT(p));
 			else
 				regmap_write(info->map,
 					     REG(OCELOT_GPIO_OUT_CLR, info,
-						 pin),
+						 pin) + info->regmap_offset,
 					     BIT(p));
 			regmap_update_bits(info->map,
-					   REG(OCELOT_GPIO_OE, info, pin),
+					   REG(OCELOT_GPIO_OE, info, pin) +
+					       info->regmap_offset,
 					   BIT(p),
 					   param == PIN_CONFIG_INPUT_ENABLE ?
 					   0 : BIT(p));
@@ -1138,20 +1141,20 @@  static int ocelot_create_group_func_map(struct device *dev,
 	return 0;
 }
 
-static int ocelot_pinctrl_register(struct platform_device *pdev,
+static int ocelot_pinctrl_register(struct device *dev,
 				   struct ocelot_pinctrl *info)
 {
 	int ret;
 
-	ret = ocelot_create_group_func_map(&pdev->dev, info);
+	ret = ocelot_create_group_func_map(dev, info);
 	if (ret) {
-		dev_err(&pdev->dev, "Unable to create group func map.\n");
+		dev_err(dev, "Unable to create group func map.\n");
 		return ret;
 	}
 
-	info->pctl = devm_pinctrl_register(&pdev->dev, info->desc, info);
+	info->pctl = devm_pinctrl_register(dev, info->desc, info);
 	if (IS_ERR(info->pctl)) {
-		dev_err(&pdev->dev, "Failed to register pinctrl\n");
+		dev_err(dev, "Failed to register pinctrl\n");
 		return PTR_ERR(info->pctl);
 	}
 
@@ -1320,7 +1323,7 @@  static void ocelot_irq_handler(struct irq_desc *desc)
 	}
 }
 
-static int ocelot_gpiochip_register(struct platform_device *pdev,
+static int ocelot_gpiochip_register(struct device *dev,
 				    struct ocelot_pinctrl *info)
 {
 	struct gpio_chip *gc;
@@ -1331,7 +1334,7 @@  static int ocelot_gpiochip_register(struct platform_device *pdev,
 
 	gc = &info->gpio_chip;
 	gc->ngpio = info->desc->npins;
-	gc->parent = &pdev->dev;
+	gc->parent = dev;
 	gc->base = -1;
 	gc->of_node = info->dev->of_node;
 	gc->label = "ocelot-gpio";
@@ -1342,8 +1345,7 @@  static int ocelot_gpiochip_register(struct platform_device *pdev,
 		girq->chip = &ocelot_irqchip;
 		girq->parent_handler = ocelot_irq_handler;
 		girq->num_parents = 1;
-		girq->parents = devm_kcalloc(&pdev->dev, 1,
-					     sizeof(*girq->parents),
+		girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
 					     GFP_KERNEL);
 		if (!girq->parents)
 			return -ENOMEM;
@@ -1352,7 +1354,7 @@  static int ocelot_gpiochip_register(struct platform_device *pdev,
 		girq->handler = handle_edge_irq;
 	}
 
-	return devm_gpiochip_add_data(&pdev->dev, gc, info);
+	return devm_gpiochip_add_data(dev, gc, info);
 }
 
 static const struct of_device_id ocelot_pinctrl_of_match[] = {
@@ -1384,56 +1386,104 @@  static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev)
 	return devm_regmap_init_mmio(&pdev->dev, base, &regmap_config);
 }
 
+static struct pinctrl_desc
+*ocelot_pinctrl_match_from_node(struct device_node *device_node)
+{
+	const struct of_device_id *match;
+
+	match = of_match_node(of_match_ptr(ocelot_pinctrl_of_match),
+			      device_node);
+
+	if (match)
+		return (struct pinctrl_desc *)match->data;
+
+	return NULL;
+}
+
+int ocelot_pinctrl_core_probe(struct device *dev,
+			      struct pinctrl_desc *pinctrl_desc,
+			      struct regmap *regmap_base, u32 regmap_offset,
+			      struct regmap *pincfg_base, u32 pincfg_offset,
+			      struct device_node *device_node)
+{
+	struct ocelot_pinctrl *info;
+	int ret;
+
+	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	if (!pinctrl_desc)
+		pinctrl_desc = ocelot_pinctrl_match_from_node(device_node);
+	if (!pinctrl_desc) {
+		dev_err(dev, "Failed to find device match\n");
+		return -ENODEV;
+	}
+
+	info->desc = pinctrl_desc;
+	info->stride = ocelot_pinctrl_determine_stride(info->desc);
+	info->dev = dev;
+	info->node = device_node;
+	info->map = regmap_base;
+	info->pincfg = pincfg_base;
+	info->regmap_offset = regmap_offset;
+	info->pincfg_offset = pincfg_offset;
+
+	ret = ocelot_pinctrl_register(dev, info);
+	if (ret)
+		return ret;
+
+	ret = ocelot_gpiochip_register(dev, info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(ocelot_pinctrl_core_probe);
+
 static int ocelot_pinctrl_probe(struct platform_device *pdev)
 {
+	struct pinctrl_desc *pinctrl_desc;
 	struct device *dev = &pdev->dev;
-	struct ocelot_pinctrl *info;
+	struct regmap *regmap;
 	struct regmap *pincfg;
 	void __iomem *base;
-	int ret;
+	int ret, stride;
 	struct regmap_config regmap_config = {
 		.reg_bits = 32,
 		.val_bits = 32,
 		.reg_stride = 4,
 	};
 
-	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	info->desc = (struct pinctrl_desc *)device_get_match_data(dev);
+	pinctrl_desc = (struct pinctrl_desc *)device_get_match_data(dev);
 
 	base = devm_ioremap_resource(dev,
 			platform_get_resource(pdev, IORESOURCE_MEM, 0));
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	info->stride = 1 + (info->desc->npins - 1) / 32;
+	stride = ocelot_pinctrl_determine_stride(pinctrl_desc);
 
-	regmap_config.max_register = OCELOT_GPIO_SD_MAP * info->stride + 15 * 4;
+	regmap_config.max_register = OCELOT_GPIO_SD_MAP * stride + 15 * 4;
 
-	info->map = devm_regmap_init_mmio(dev, base, &regmap_config);
-	if (IS_ERR(info->map)) {
+	regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
+	if (IS_ERR(regmap)) {
 		dev_err(dev, "Failed to create regmap\n");
-		return PTR_ERR(info->map);
+		return PTR_ERR(regmap);
 	}
-	dev_set_drvdata(dev, info->map);
-	info->dev = dev;
+	dev_set_drvdata(dev, regmap);
 
 	/* Pinconf registers */
-	if (info->desc->confops) {
+	if (pinctrl_desc->confops) {
 		pincfg = ocelot_pinctrl_create_pincfg(pdev);
-		if (IS_ERR(pincfg))
+		if (IS_ERR(pincfg)) {
 			dev_dbg(dev, "Failed to create pincfg regmap\n");
-		else
-			info->pincfg = pincfg;
+			pincfg = NULL;
+		}
 	}
 
-	ret = ocelot_pinctrl_register(pdev, info);
-	if (ret)
-		return ret;
-
-	ret = ocelot_gpiochip_register(pdev, info);
+	ret = ocelot_pinctrl_core_probe(dev, pinctrl_desc, regmap, 0, pincfg, 0,
+					dev->of_node);
 	if (ret)
 		return ret;
 
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 9a4ded4bff04..14acfe82d0a4 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -6,6 +6,7 @@ 
 #define _SOC_MSCC_OCELOT_H
 
 #include <linux/ptp_clock_kernel.h>
+#include <linux/pinctrl/pinctrl.h>
 #include <linux/net_tstamp.h>
 #include <linux/if_vlan.h>
 #include <linux/regmap.h>
@@ -912,4 +913,21 @@  ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port,
 }
 #endif
 
+#if IS_ENABLED(CONFIG_PINCTRL_OCELOT)
+int ocelot_pinctrl_core_probe(struct device *dev,
+			      struct pinctrl_desc *pinctrl_desc,
+			      struct regmap *regmap_base, u32 regmap_offset,
+			      struct regmap *pincfg_base, u32 pincfg_offset,
+			      struct device_node *device_node);
+#else
+int ocelot_pinctrl_core_probe(struct device *dev,
+			      struct pinctrl_desc *pinctrl_desc,
+			      struct regmap *regmap_base, u32 regmap_offset,
+			      struct regmap *pincfg_base, u32 pincfg_offset,
+			      struct device_node *device_node)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 #endif