Subject: Re: MPC52xx: sysfs failure on adding new device driver

From: Grant Likely <[email-masked]>
Date: Thu, 9 Jun 2005 12:48:38 -0600

On 6/9/05, Kumar Gala <[email-masked]> wrote:
> 
> >> That changes the semantic of the driver names for the platform bus
> >> however, making the dot a "special" char.
> > Who needs to be asked about this?  Should I take this discussion over
> > the the LKML?
> 
> GregKH would be the person to talk to about the driver core and taking
> this to LKML would be useful.  We probably have a similar issue with
> CPM comm channels.
> 
> I always assumed multiple drivers would get probed and the drivers
> would fail in probe if they were not suppose to bind to the given
> channel/psc, etc..
> 
I took another look at the sysfs layout, and it doesn't really look
like it is intended to support multiple drivers with the same name. 
:-(  I'll ask GregKH about it.

In the mean time, here's another option:  Leave
arch/ppc/syslib/mpc52xx_devices.c alone, but modify the table in the
board setup code to assign specific drivers to the PSC devices before
the table is parsed by the platform bus.  This has the added advantage
of eliminating the need for mpc52xx_match_psc_function() and it's
cousins.

Thoughts?  Will this scheme negatively affect portability?

Here's a working example patch:

--------------------------------------------------------------------------
diff -ruN linux-2.6.12rc6.orig/arch/ppc/platforms/lite5200.c
linux-2.6.12rc6.spi2/arch/ppc/platforms/lite5200.c
--- linux-2.6.12rc6.orig/arch/ppc/platforms/lite5200.c	2005-06-08
17:22:05.000000000 -0600
+++ linux-2.6.12rc6.spi2/arch/ppc/platforms/lite5200.c	2005-06-09
12:23:26.000000000 -0600
@@ -50,17 +50,6 @@
 /* Platform specific code                                                   */
 /* ======================================================================== */
 
-/* Supported PSC function in "preference" order */
-struct mpc52xx_psc_func mpc52xx_psc_functions[] = {
-		{       .id     = 0,
-			.func   = "uart",
-		},
-		{       .id     = -1,   /* End entry */
-			.func   = NULL,
-		}
-	};
-
-
 static int
 lite5200_show_cpuinfo(struct seq_file *m)
 {
@@ -198,6 +187,11 @@
 	isa_io_base		= 0;
 	isa_mem_base		= 0;
 
+	/* Assign driver names to PSC devices */
+	ppc_sys_platform_devices[MPC52xx_PSC1].name = "mpc52xx-psc.uart";
+	ppc_sys_platform_devices[MPC52xx_PSC2].name = "mpc52xx-psc.uart";
+	ppc_sys_platform_devices[MPC52xx_PSC3].name = "mpc52xx-psc.spi";
+
 	/* Powersave */
 	/* This is provided as an example on how to do it. But you
 	   need to be aware that NAP disable bus snoop and that may
diff -ruN linux-2.6.12rc6.orig/arch/ppc/syslib/mpc52xx_setup.c
linux-2.6.12rc6.spi2/arch/ppc/syslib/mpc52xx_setup.c
--- linux-2.6.12rc6.orig/arch/ppc/syslib/mpc52xx_setup.c	2005-06-08
17:22:05.000000000 -0600
+++ linux-2.6.12rc6.spi2/arch/ppc/syslib/mpc52xx_setup.c	2005-06-09
12:11:31.000000000 -0600
@@ -216,15 +216,3 @@
 	tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000);
 }
 
-int mpc52xx_match_psc_function(int psc_idx, const char *func)
-{
-	struct mpc52xx_psc_func *cf = mpc52xx_psc_functions;
-
-	while ((cf->id != -1) && (cf->func != NULL)) {
-		if ((cf->id == psc_idx) && !strcmp(cf->func,func))
-			return 1;
-		cf++;
-	}
-
-	return 0;
-}
diff -ruN linux-2.6.12rc6.orig/drivers/Kconfig
linux-2.6.12rc6.spi2/drivers/Kconfig
--- linux-2.6.12rc6.orig/drivers/Kconfig	2005-03-02 00:38:26.000000000 -0700
+++ linux-2.6.12rc6.spi2/drivers/Kconfig	2005-06-08 17:27:23.000000000 -0600
@@ -58,4 +58,6 @@
 
 source "drivers/infiniband/Kconfig"
 
+source "drivers/spi/Kconfig"
+
 endmenu
diff -ruN linux-2.6.12rc6.orig/drivers/Makefile
linux-2.6.12rc6.spi2/drivers/Makefile
--- linux-2.6.12rc6.orig/drivers/Makefile	2005-06-08 17:22:08.000000000 -0600
+++ linux-2.6.12rc6.spi2/drivers/Makefile	2005-06-08 17:27:13.000000000 -0600
@@ -64,3 +64,4 @@
 obj-$(CONFIG_BLK_DEV_SGIIOC4)	+= sn/
 obj-y				+= firmware/
 obj-$(CONFIG_CRYPTO)		+= crypto/
+obj-$(CONFIG_SPI)		+= spi/
diff -ruN linux-2.6.12rc6.orig/drivers/serial/mpc52xx_uart.c
linux-2.6.12rc6.spi2/drivers/serial/mpc52xx_uart.c
--- linux-2.6.12rc6.orig/drivers/serial/mpc52xx_uart.c	2005-06-08
17:22:23.000000000 -0600
+++ linux-2.6.12rc6.spi2/drivers/serial/mpc52xx_uart.c	2005-06-09
12:14:40.000000000 -0600
@@ -29,8 +29,9 @@
 /* Platform device Usage :
  *
  * Since PSCs can have multiple function, the correct driver for each one
- * is selected by calling mpc52xx_match_psc_function(...). The function
- * handled by this driver is "uart".
+ * is selected based on the name assigned to the psc.  By convention, the
+ * function is appended to the device name in the board setup code.  For
+ * example, this uart psc driver will only bind to mpc52xx_psc.uart devices.
  *
  * The driver init all necessary registers to place the PSC in uart
mode without
  * DCD. However, the pin multiplexing aren't changed and should be set either
@@ -730,9 +731,6 @@
 	if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
 		return -EINVAL;
 
-	if (!mpc52xx_match_psc_function(idx,"uart"))
-		return -ENODEV;
-
 	/* Init the port structure */
 	port = &mpc52xx_uart_ports[idx];
 
@@ -804,7 +802,7 @@
 #endif
 
 static struct device_driver mpc52xx_uart_platform_driver = {
-	.name		= "mpc52xx-psc",
+	.name		= "mpc52xx-psc.uart",
 	.bus		= &platform_bus_type,
 	.probe		= mpc52xx_uart_probe,
 	.remove		= mpc52xx_uart_remove,
diff -ruN linux-2.6.12rc6.orig/drivers/spi/Kconfig
linux-2.6.12rc6.spi2/drivers/spi/Kconfig
--- linux-2.6.12rc6.orig/drivers/spi/Kconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.12rc6.spi2/drivers/spi/Kconfig	2005-06-08 17:29:37.000000000 -0600
@@ -0,0 +1,19 @@
+#
+# Character device configuration
+#
+
+menu "SPI support"
+
+config SPI
+	tristate "SPI support"
+	---help---
+	  SPI is a serial bus protocol for connecting between ICs
+
+config SPI_MPC52XX_PSC
+	tristate "SPI bus via MPC5xxx PSC port"
+	depends on SPI
+	help
+	  Say Y here if you want SPI via an MPC5xxx PSC port.
+
+endmenu
+
diff -ruN linux-2.6.12rc6.orig/drivers/spi/Makefile
linux-2.6.12rc6.spi2/drivers/spi/Makefile
--- linux-2.6.12rc6.orig/drivers/spi/Makefile	1969-12-31
17:00:00.000000000 -0700
+++ linux-2.6.12rc6.spi2/drivers/spi/Makefile	2005-06-08
17:29:17.000000000 -0600
@@ -0,0 +1,6 @@
+#
+# Makefile for the spi core.
+#
+
+obj-$(CONFIG_SPI_MPC52XX_PSC)	+= spi-mpc5xxx-psc.o
+
diff -ruN linux-2.6.12rc6.orig/drivers/spi/spi-mpc5xxx-psc.c
linux-2.6.12rc6.spi2/drivers/spi/spi-mpc5xxx-psc.c
--- linux-2.6.12rc6.orig/drivers/spi/spi-mpc5xxx-psc.c	1969-12-31
17:00:00.000000000 -0700
+++ linux-2.6.12rc6.spi2/drivers/spi/spi-mpc5xxx-psc.c	2005-06-09
12:20:28.000000000 -0600
@@ -0,0 +1,54 @@
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+static int __devinit
+spi_mpc52xx_psc_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	/*struct resource *res = pdev->resource;*/
+	int idx = pdev->id;
+
+	printk(KERN_ALERT "spi-mpc52xx-psc: probing idx=%i\n", idx);
+
+	return 0;
+}
+
+static int 
+spi_mpc52xx_psc_remove(struct device *dev)
+{
+	return 0;
+}
+
+static struct device_driver spi_mpc52xx_psc_platform_driver = {
+	.name		= "mpc52xx-psc.spi",
+	.bus		= &platform_bus_type,
+	.probe		= spi_mpc52xx_psc_probe,
+	.remove		= spi_mpc52xx_psc_remove,
+};
+
+static int __init spi_mpc52xx_psc_init(void)
+{
+	int ret;
+
+	printk(KERN_ALERT "spi_mpc52xx_psc: initializing\n");
+
+	ret = driver_register(&spi_mpc52xx_psc_platform_driver);
+	return ret;
+}
+
+static void __exit spi_mpc52xx_psc_exit(void)
+{
+	driver_unregister(&spi_mpc52xx_psc_platform_driver);
+	printk(KERN_ALERT "spi_mpc52xx_psc: exiting\n");
+}
+
+module_init(spi_mpc52xx_psc_init);
+module_exit(spi_mpc52xx_psc_exit);
diff -ruN linux-2.6.12rc6.orig/include/asm-ppc/mpc52xx.h
linux-2.6.12rc6.spi2/include/asm-ppc/mpc52xx.h
--- linux-2.6.12rc6.orig/include/asm-ppc/mpc52xx.h	2005-06-08
17:22:29.000000000 -0600
+++ linux-2.6.12rc6.spi2/include/asm-ppc/mpc52xx.h	2005-06-09
12:11:19.000000000 -0600
@@ -415,17 +415,6 @@
 
 extern void mpc52xx_find_bridges(void);
 
-
-	/* Matching of PSC function */
-struct mpc52xx_psc_func {
-	int id;
-	char *func;
-};
-
-extern int mpc52xx_match_psc_function(int psc_idx, const char *func);
-extern struct  mpc52xx_psc_func mpc52xx_psc_functions[];
-	/* This array is to be defined in platform file */
-
 #endif /* __ASSEMBLY__ */