[RFC PATCH] pinctrl: pinmux: Add pinmux-set debugfs file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This RFC is a change in approach from my previous RFC patch [1]. It adds
"pinnux-set" to debugfs. A function and group on the pin control device
will be activated when 2 integers "<function-selector> <group-selector>"
are written to the file. The debugfs write operation pinmux_set_write()
handles this by calling ops->set_mux() with fsel and gsel.

RFC question: should pinmux-set take function name and group name
instead of the selector numbers?

The following is an example on the PocketBeagle [2] which has the AM3358
SoC and binds to pinctrl-single. I added this to the device tree [3] to
represent two of the pins on the expansion header as an example: P1.36
and P2.01. Both of these header pins are designed to be set to PWM mode
by default [4] but can now be set back to gpio mode through pinmux-set.

	&am33xx_pinmux {

	/* use the pin controller itself as the owner device */
	pinctrl-names = "default",
			"P1_36_gpio", "P1_36_gpio_pu", "P1_36_gpio_pd",
			"P1_36_gpio_input", "P1_36_pwm",
			"P2_01_gpio", "P2_01_gpio_pu", "P2_01_gpio_pd",
			"P2_01_gpio_input", "P2_01_pwm";

	/* set hog for default mode */
	pinctrl-0 = < &P1_36_default_pin &P2_01_default_pin >;
	/* these will create pin functions for each mode */
	pinctrl-1 = <&P1_36_gpio_pin>;
	pinctrl-2 = <&P1_36_gpio_pu_pin>;
	pinctrl-3 = <&P1_36_gpio_pd_pin>;
	pinctrl-4 = <&P1_36_gpio_input_pin>;
	pinctrl-5 = <&P1_36_pwm_pin>;
	pinctrl-6 = <&P2_01_default_pin>;
	pinctrl-7 = <&P2_01_gpio_pin>;
	pinctrl-8 = <&P2_01_gpio_pu_pin>;
	pinctrl-9 = <&P2_01_gpio_pd_pin>;
	pinctrl-10 = <&P2_01_gpio_input_pin>;
	pinctrl-11 = <&P2_01_pwm_pin>;

	/* P1_36 (ZCZ ball A13) ehrpwm0a */
	P1_36_default_pin: pinmux_P1_36_default_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1) >; };
	P1_36_gpio_pin: pinmux_P1_36_gpio_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_OUTPUT | INPUT_EN | MUX_MODE7) >; };
	P1_36_gpio_pu_pin: pinmux_P1_36_gpio_pu_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7) >; };
	P1_36_gpio_pd_pin: pinmux_P1_36_gpio_pd_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7) >; };
	P1_36_gpio_input_pin: pinmux_P1_36_gpio_input_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_INPUT | MUX_MODE7) >; };
	P1_36_pwm_pin: pinmux_P1_36_pwm_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE1) >; };
	P1_36_spi_sclk_pin: pinmux_P1_36_spi_sclk_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE3) >; };
	P1_36_pruout_pin: pinmux_P1_36_pruout_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE5) >; };
	P1_36_pruin_pin: pinmux_P1_36_pruin_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0990, PIN_INPUT | MUX_MODE6) >; };

	/* P2_01 (ZCZ ball U14) ehrpwm1a */
	P2_01_default_pin: pinmux_P2_01_default_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0848, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6) >; };
	P2_01_gpio_pin: pinmux_P2_01_gpio_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0848, PIN_OUTPUT | INPUT_EN | MUX_MODE7) >; };
	P2_01_gpio_pu_pin: pinmux_P2_01_gpio_pu_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0848, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7) >; };
	P2_01_gpio_pd_pin: pinmux_P2_01_gpio_pd_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0848, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7) >; };
	P2_01_gpio_input_pin: pinmux_P2_01_gpio_input_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0848, PIN_INPUT | MUX_MODE7) >; };
	P2_01_pwm_pin: pinmux_P2_01_pwm_pin { pinctrl-single,pins = <
		AM33XX_IOPAD(0x0848, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE6) >; };

The following shows the pin functions registered for the pin controller:

root@beaglebone:/sys/kernel/debug/pinctrl/44e10800.pinmux-pinctrl-single# cat pinmux-functions
function: pinmux_P1_36_default_pin, groups = [ pinmux_P1_36_default_pin ]
function: pinmux_P2_01_default_pin, groups = [ pinmux_P2_01_default_pin ]
function: pinmux_P1_36_gpio_pin, groups = [ pinmux_P1_36_gpio_pin ]
function: pinmux_P1_36_gpio_pu_pin, groups = [ pinmux_P1_36_gpio_pu_pin ]
function: pinmux_P1_36_gpio_pd_pin, groups = [ pinmux_P1_36_gpio_pd_pin ]
function: pinmux_P1_36_gpio_input_pin, groups = [ pinmux_P1_36_gpio_input_pin ]
function: pinmux_P1_36_pwm_pin, groups = [ pinmux_P1_36_pwm_pin ]
function: pinmux_P2_01_gpio_pin, groups = [ pinmux_P2_01_gpio_pin ]
function: pinmux_P2_01_gpio_pu_pin, groups = [ pinmux_P2_01_gpio_pu_pin ]
function: pinmux_P2_01_gpio_pd_pin, groups = [ pinmux_P2_01_gpio_pd_pin ]
function: pinmux_P2_01_gpio_input_pin, groups = [ pinmux_P2_01_gpio_input_pin ]
function: pinmux_P2_01_pwm_pin, groups = [ pinmux_P2_01_pwm_pin ]
function: pinmux-uart0-pins, groups = [ pinmux-uart0-pins ]
function: pinmux-mmc0-pins, groups = [ pinmux-mmc0-pins ]
function: pinmux-i2c0-pins, groups = [ pinmux-i2c0-pins ]

Activate the pinmux_P1_36_gpio_pin function (fsel 2):

root@beaglebone:/sys/kernel/debug/pinctrl/44e10800.pinmux-pinctrl-single# echo '2 2' > pinmux-set

Extra debug output that I added shows that pinctrl-single's set_mux()
has set the register correctly for gpio mode:

pinmux core: DEBUG pinmux_set_write(): returned 0
pinmux core: DEBUG pinmux_set_write(): buf=[2 2]
pinmux core: DEBUG pinmux_set_write(): sscanf(2,2)
pinmux core: DEBUG pinmux_set_write(): call ops->set_mux(fsel=2, gsel=2)
pinctrl-single 44e10800.pinmux: DEBUG pcs_set_mux(): call pinmux_generic_get_function() on fselector=2
pinctrl-single 44e10800.pinmux: enabling (null) function2
pinctrl-single 44e10800.pinmux: DEBUG pcs_set_mux(): func->nvals=1
pinctrl-single 44e10800.pinmux: DEBUG pcs_set_mux(): offset=0x190 old_val=0x21 val=0x2f

Activate the pinmux_P1_36_pwm_pin function (fsel 6):

root@beaglebone:/sys/kernel/debug/pinctrl/44e10800.pinmux-pinctrl-single# echo '6 6' > pinmux-set

pinctrl-single set_mux() is able to set register correctly for pwm mode:

pinmux core: DEBUG pinmux_set_write(): returned 0
pinmux core: DEBUG pinmux_set_write(): buf=[6 6]
pinmux core: DEBUG pinmux_set_write(): sscanf(6,6)
pinmux core: DEBUG pinmux_set_write(): call ops->set_mux(fsel=6, gsel=6)
pinctrl-single 44e10800.pinmux: DEBUG pcs_set_mux(): call pinmux_generic_get_function() on fselector=6
pinctrl-single 44e10800.pinmux: enabling (null) function6
pinctrl-single 44e10800.pinmux: DEBUG pcs_set_mux(): func->nvals=1
pinctrl-single 44e10800.pinmux: DEBUG pcs_set_mux(): offset=0x190 old_val=0x2f val=0x21

I would appreciate any feedback on this approach.  Thank you!

-Drew

[1] https://lore.kernel.org/linux-gpio/20201218045134.4158709-1-drew@xxxxxxxxxxxxxxx/
[2] https://beagleboard.org/pocket
[3] arch/arm/boot/dts/am335x-pocketbeagle.dts
[4] https://github.com/beagleboard/pocketbeagle/wiki/System-Reference-Manual#70-connectors-

Cc: Pantelis Antoniou <pantelis.antoniou@xxxxxxxxxxxx>
Cc: Jason Kridner <jkridner@xxxxxxxxxxxxxxx>,
Cc: Robert Nelson <robertcnelson@xxxxxxxxxxxxxxx>,
Cc: Linus Walleij <linus.walleij@xxxxxxxxxx>,
Cc: Tony Lindgren <tony@xxxxxxxxxxx>,
Cc: Andy Shevchenko <andy.shevchenko@xxxxxxxxx>
Cc: Alexandre Belloni <alexandre.belloni@xxxxxxxxxxx>
Cc: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx>
Signed-off-by: Drew Fustini <drew@xxxxxxxxxxxxxxx>
---
 drivers/pinctrl/pinmux.c | 65 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index bab888fe3f8e..300e2b3d0ea8 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -673,6 +673,69 @@ void pinmux_show_setting(struct seq_file *s,
 DEFINE_SHOW_ATTRIBUTE(pinmux_functions);
 DEFINE_SHOW_ATTRIBUTE(pinmux_pins);
 
+static ssize_t pinmux_set_write(struct file *file, const char __user *user_buf,
+				   size_t cnt, loff_t *ppos)
+{
+	int err;
+	int fsel;
+	int gsel;
+	int ret;
+	char *buf;
+	struct seq_file *sfile;
+	struct pinctrl_dev *pctldev;
+	const struct pinmux_ops *ops;
+
+	if (*ppos != 0)
+		return -EINVAL;
+
+	if (cnt == 0)
+		return 0;
+
+	buf = memdup_user_nul(user_buf, cnt);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+
+	if (buf[cnt - 1] == '\n')
+		buf[cnt - 1] = '\0';
+
+	ret = sscanf(buf, "%d %d", &fsel, &gsel);
+	if (ret != 2) {
+		pr_warn("%s: sscanf() expects '<fsel> <gsel>'", __func__);
+		err = -EINVAL;
+		goto err_freebuf;
+	}
+
+	sfile = file->private_data;
+	pctldev = sfile->private;
+	ops = pctldev->desc->pmxops;
+	ret = ops->set_mux(pctldev, fsel, gsel);
+	if (ret != 0) {
+		pr_warn("%s(): set_mux() failed: %d", __func__, ret);
+		err = -EINVAL;
+		goto err_freebuf;
+	}
+	kfree(buf);
+	return cnt;
+
+err_freebuf:
+	kfree(buf);
+	return err;
+}
+
+static int pinmux_set_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, NULL, inode->i_private);
+}
+
+static const struct file_operations pinmux_set_ops = {
+	.owner = THIS_MODULE,
+	.open = pinmux_set_open,
+	.read = seq_read,
+	.write = pinmux_set_write,
+	.llseek = no_llseek,
+	.release = single_release,
+};
+
 void pinmux_init_device_debugfs(struct dentry *devroot,
 			 struct pinctrl_dev *pctldev)
 {
@@ -680,6 +743,8 @@ void pinmux_init_device_debugfs(struct dentry *devroot,
 			    devroot, pctldev, &pinmux_functions_fops);
 	debugfs_create_file("pinmux-pins", S_IFREG | S_IRUGO,
 			    devroot, pctldev, &pinmux_pins_fops);
+	debugfs_create_file("pinmux-set", S_IFREG | S_IWUSR,
+			    devroot, pctldev, &pinmux_set_ops);
 }
 
 #endif /* CONFIG_DEBUG_FS */
-- 
2.25.1




[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux