From 738e686055332a11884081ea85514514cb12fa20 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 19 Aug 2008 11:45:55 +1000 Subject: hotplug/rpaphp: Remove unused error path code Commit f46753c5e354b857b20ab8e0fe7b2579831dc369 ("PCI: introduce pci_slot") removed the need for this error path. Eliminate this warning: drivers/pci/hotplug/rpaphp_slot.c: In function 'rpaphp_register_slot': drivers/pci/hotplug/rpaphp_slot.c:151: warning: label 'sysfs_fail' defined but not used Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/pci/hotplug/rpaphp_slot.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 9b714ea93d2..50884507b8b 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -147,9 +147,5 @@ int rpaphp_register_slot(struct slot *slot) list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); info("Slot [%s] registered\n", slot->name); return 0; - -sysfs_fail: - pci_hp_deregister(php_slot); - return retval; } -- cgit v1.2.3 From f6f11018dc7ea62482f36846e9f6eb0f27df7c3c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 11 Aug 2008 17:04:32 +1000 Subject: powerpc/drivers: Use linux/of_device.h instead of asm/of_device.h Signed-off-by: Stephen Rothwell Acked-by: Takashi Iwai Signed-off-by: Paul Mackerras --- drivers/hwmon/ams/ams.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h index a6221e5dd98..221ef6915a5 100644 --- a/drivers/hwmon/ams/ams.h +++ b/drivers/hwmon/ams/ams.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include enum ams_irq { AMS_IRQ_FREEFALL = 0x01, -- cgit v1.2.3 From 7cfc4e5e7f9b5fa598aa69b5344b6fd0539f71d6 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 4 Aug 2008 08:27:52 -0500 Subject: serial/cpm_uart: Remove dead Kconfig options With the change to device tree based setup we no longer need the explicit Kconfig options for each SCC{1,4} or SMC{1,2} port. Signed-off-by: Kumar Gala --- drivers/serial/Kconfig | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 77cb34270fc..b87b1cf9df6 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1136,42 +1136,6 @@ config SERIAL_CPM_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_CPM_SCC1 - bool "Support for SCC1 serial port" - depends on SERIAL_CPM=y - help - Select this option to use SCC1 as a serial port - -config SERIAL_CPM_SCC2 - bool "Support for SCC2 serial port" - depends on SERIAL_CPM=y - help - Select this option to use SCC2 as a serial port - -config SERIAL_CPM_SCC3 - bool "Support for SCC3 serial port" - depends on SERIAL_CPM=y - help - Select this option to use SCC3 as a serial port - -config SERIAL_CPM_SCC4 - bool "Support for SCC4 serial port" - depends on SERIAL_CPM=y - help - Select this option to use SCC4 as a serial port - -config SERIAL_CPM_SMC1 - bool "Support for SMC1 serial port" - depends on SERIAL_CPM=y - help - Select this option to use SMC1 as a serial port - -config SERIAL_CPM_SMC2 - bool "Support for SMC2 serial port" - depends on SERIAL_CPM=y - help - Select this option to use SMC2 as a serial port - config SERIAL_SGI_L1_CONSOLE bool "SGI Altix L1 serial console support" depends on IA64_GENERIC || IA64_SGI_SN2 -- cgit v1.2.3 From 8b05cefca73bfbd98c89f16327f5d7da52ab7c3c Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Fri, 12 Sep 2008 10:42:56 -0500 Subject: cpm_uart: Pass actual dev ptr to dma_* in ucc and cpm_uart serial We're currently passing NULL, and really shouldn't be. Signed-off-by: Becky Bruce Acked-By: Timur Tabi Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart_core.c | 3 +++ drivers/serial/cpm_uart/cpm_uart_cpm1.c | 6 +++--- drivers/serial/cpm_uart/cpm_uart_cpm2.c | 6 +++--- drivers/serial/ucc_uart.c | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 25efca5a7a1..a6c4d744495 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -1333,6 +1333,9 @@ static int __devinit cpm_uart_probe(struct of_device *ofdev, if (ret) return ret; + /* initialize the device pointer for the port */ + pinfo->port.dev = &ofdev->dev; + return uart_add_one_port(&cpm_reg, &pinfo->port); } diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 0f0aff06c59..1b94c56ec23 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -100,7 +100,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); dma_addr = (u32)cpm_dpram_phys(mem_addr); } else - mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, + mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, GFP_KERNEL); if (mem_addr == NULL) { @@ -127,8 +127,8 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) void cpm_uart_freebuf(struct uart_cpm_port *pinfo) { - dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos * - pinfo->rx_fifosize) + + dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * + pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize), pinfo->mem_addr, pinfo->dma_addr); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index b8db4d3eed3..141c0a3333a 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -136,7 +136,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) dma_addr = virt_to_bus(mem_addr); } else - mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, + mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, GFP_KERNEL); if (mem_addr == NULL) { @@ -163,8 +163,8 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) void cpm_uart_freebuf(struct uart_cpm_port *pinfo) { - dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos * - pinfo->rx_fifosize) + + dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * + pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize), (void __force *)pinfo->mem_addr, pinfo->dma_addr); diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c index 5c5d18dcb6a..539c933b335 100644 --- a/drivers/serial/ucc_uart.c +++ b/drivers/serial/ucc_uart.c @@ -1009,7 +1009,7 @@ static int qe_uart_request_port(struct uart_port *port) rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize); - bd_virt = dma_alloc_coherent(NULL, rx_size + tx_size, &bd_dma_addr, + bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr, GFP_KERNEL); if (!bd_virt) { dev_err(port->dev, "could not allocate buffer descriptors\n"); @@ -1051,7 +1051,7 @@ static void qe_uart_release_port(struct uart_port *port) container_of(port, struct uart_qe_port, port); struct ucc_slow_private *uccs = qe_port->us_private; - dma_free_coherent(NULL, qe_port->bd_size, qe_port->bd_virt, + dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt, qe_port->bd_dma_addr); ucc_slow_free(uccs); -- cgit v1.2.3 From 68e1ee62f0f8e556642a59ebaf0c2cc2ac6ccfa6 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 22 Sep 2008 14:41:31 -0700 Subject: powerpc: convert CONFIG_PPC_MERGE to CONFIG_PPC for legacy io checks Now that arch/ppc is dead CONFIG_PPC_MERGE is always defined for all powerpc platforms and we want to get rid of CONFIG_PPC_MERGE use CONFIG_PPC instead. Signed-off-by: Kumar Gala Acked-by: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Kumar Gala --- drivers/block/floppy.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 2 +- drivers/i2c/busses/i2c-pca-isa.c | 2 +- drivers/input/serio/i8042-io.h | 2 +- drivers/pnp/isapnp/core.c | 2 +- drivers/pnp/pnpbios/core.c | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 395f8ea7981..5813e0d1a92 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4165,7 +4165,7 @@ static int __init floppy_init(void) int i, unit, drive; int err, dr; -#if defined(CONFIG_PPC_MERGE) +#if defined(CONFIG_PPC) if (check_legacy_ioport(FDC1)) return -ENODEV; #endif diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 8e8afb6141f..3123bf57ad9 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2695,7 +2695,7 @@ static __devinit void default_find_bmc(void) for (i = 0; ; i++) { if (!ipmi_defaults[i].port) break; -#ifdef CONFIG_PPC_MERGE +#ifdef CONFIG_PPC if (check_legacy_ioport(ipmi_defaults[i].port)) continue; #endif diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index a119784bae1..28d8463b74a 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -113,7 +113,7 @@ static int __devinit pca_isa_probe(struct device *dev, unsigned int id) dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq); -#ifdef CONFIG_PPC_MERGE +#ifdef CONFIG_PPC if (check_legacy_ioport(base)) { dev_err(dev, "I/O address %#08lx is not available\n", base); goto out; diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index f451c7351a9..847f4aad7ed 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -67,7 +67,7 @@ static inline int i8042_platform_init(void) * On some platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on such boxes. */ -#if defined(CONFIG_PPC_MERGE) +#if defined(CONFIG_PPC) if (check_legacy_ioport(I8042_DATA_REG)) return -ENODEV; #endif diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index 101a835e875..46455fbab6d 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -1012,7 +1012,7 @@ static int __init isapnp_init(void) printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n"); return 0; } -#ifdef CONFIG_PPC_MERGE +#ifdef CONFIG_PPC if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP)) return -EINVAL; #endif diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 19a4be1a9a3..0797dd17036 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -519,7 +519,7 @@ static int __init pnpbios_init(void) { int ret; -#if defined(CONFIG_PPC_MERGE) +#if defined(CONFIG_PPC) if (check_legacy_ioport(PNPBIOS_BASE)) return -ENODEV; #endif @@ -577,7 +577,7 @@ static int __init pnpbios_thread_init(void) { struct task_struct *task; -#if defined(CONFIG_PPC_MERGE) +#if defined(CONFIG_PPC) if (check_legacy_ioport(PNPBIOS_BASE)) return 0; #endif -- cgit v1.2.3 From 8d1fb8cbaa74938d8c4379adb693d1d5f5c9e130 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 1 Aug 2008 11:09:34 -0500 Subject: serial/mpc52xx_uart: remove code associated with !CONFIG_PPC_MERGE Now that arch/ppc is gone we don't need CONFIG_PPC_MERGE anymore remove the dead code associated with !CONFIG_PPC_MERGE. Signed-off-by: Kumar Gala --- drivers/serial/mpc52xx_uart.c | 181 +----------------------------------------- 1 file changed, 1 insertion(+), 180 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 36126070d9a..6117d3db0b6 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -72,13 +72,8 @@ #include #include #include - -#if defined(CONFIG_PPC_MERGE) #include #include -#else -#include -#endif #include #include @@ -107,12 +102,11 @@ static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM]; * it's cleared, then a memset(...,0,...) should be added to * the console_init */ -#if defined(CONFIG_PPC_MERGE) + /* lookup table for matching device nodes to index numbers */ static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; static void mpc52xx_uart_of_enumerate(void); -#endif #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) @@ -255,17 +249,12 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) /* Search for bus-frequency property in this node or a parent */ static unsigned long mpc52xx_getuartclk(void *p) { -#if defined(CONFIG_PPC_MERGE) /* * 5200 UARTs have a / 32 prescaler * but the generic serial code assumes 16 * so return ipb freq / 2 */ return mpc52xx_find_ipb_freq(p) / 2; -#else - pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n"); - return NULL; -#endif } static struct psc_ops mpc52xx_psc_ops = { @@ -886,10 +875,6 @@ mpc52xx_console_get_options(struct uart_port *port, /* CT{U,L}R are write-only ! */ *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; -#if !defined(CONFIG_PPC_MERGE) - if (__res.bi_baudrate) - *baud = __res.bi_baudrate; -#endif /* Parse them */ switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { @@ -946,42 +931,6 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count) psc_ops->cw_restore_ints(port); } -#if !defined(CONFIG_PPC_MERGE) -static int __init -mpc52xx_console_setup(struct console *co, char *options) -{ - struct uart_port *port = &mpc52xx_uart_ports[co->index]; - - int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM) - return -EINVAL; - - /* Basic port init. Needed since we use some uart_??? func before - * real init for early access */ - spin_lock_init(&port->lock); - port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ - port->ops = &mpc52xx_uart_ops; - port->mapbase = MPC52xx_PA(MPC52xx_PSCx_OFFSET(co->index+1)); - - /* We ioremap ourself */ - port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE); - if (port->membase == NULL) - return -EINVAL; - - /* Setup the port parameters accoding to options */ - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -#else static int __init mpc52xx_console_setup(struct console *co, char *options) @@ -1053,7 +1002,6 @@ mpc52xx_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -#endif /* defined(CONFIG_PPC_MERGE) */ static struct uart_driver mpc52xx_uart_driver; @@ -1072,9 +1020,7 @@ static struct console mpc52xx_console = { static int __init mpc52xx_console_init(void) { -#if defined(CONFIG_PPC_MERGE) mpc52xx_uart_of_enumerate(); -#endif register_console(&mpc52xx_console); return 0; } @@ -1100,115 +1046,6 @@ static struct uart_driver mpc52xx_uart_driver = { .cons = MPC52xx_PSC_CONSOLE, }; - -#if !defined(CONFIG_PPC_MERGE) -/* ======================================================================== */ -/* Platform Driver */ -/* ======================================================================== */ - -static int __devinit -mpc52xx_uart_probe(struct platform_device *dev) -{ - struct resource *res = dev->resource; - - struct uart_port *port = NULL; - int i, idx, ret; - - /* Check validity & presence */ - idx = dev->id; - 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]; - - spin_lock_init(&port->lock); - port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ - port->fifosize = 512; - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF | - (uart_console(port) ? 0 : UPF_IOREMAP); - port->line = idx; - port->ops = &mpc52xx_uart_ops; - port->dev = &dev->dev; - - /* Search for IRQ and mapbase */ - for (i = 0 ; i < dev->num_resources ; i++, res++) { - if (res->flags & IORESOURCE_MEM) - port->mapbase = res->start; - else if (res->flags & IORESOURCE_IRQ) - port->irq = res->start; - } - if (!port->irq || !port->mapbase) - return -EINVAL; - - /* Add the port to the uart sub-system */ - ret = uart_add_one_port(&mpc52xx_uart_driver, port); - if (!ret) - platform_set_drvdata(dev, (void *)port); - - return ret; -} - -static int -mpc52xx_uart_remove(struct platform_device *dev) -{ - struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev); - - platform_set_drvdata(dev, NULL); - - if (port) - uart_remove_one_port(&mpc52xx_uart_driver, port); - - return 0; -} - -#ifdef CONFIG_PM -static int -mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state) -{ - struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev); - - if (port) - uart_suspend_port(&mpc52xx_uart_driver, port); - - return 0; -} - -static int -mpc52xx_uart_resume(struct platform_device *dev) -{ - struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev); - - if (port) - uart_resume_port(&mpc52xx_uart_driver, port); - - return 0; -} -#endif - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:mpc52xx-psc"); - -static struct platform_driver mpc52xx_uart_platform_driver = { - .probe = mpc52xx_uart_probe, - .remove = mpc52xx_uart_remove, -#ifdef CONFIG_PM - .suspend = mpc52xx_uart_suspend, - .resume = mpc52xx_uart_resume, -#endif - .driver = { - .owner = THIS_MODULE, - .name = "mpc52xx-psc", - }, -}; -#endif /* !defined(CONFIG_PPC_MERGE) */ - - -#if defined(CONFIG_PPC_MERGE) /* ======================================================================== */ /* OF Platform Driver */ /* ======================================================================== */ @@ -1402,7 +1239,6 @@ static struct of_platform_driver mpc52xx_uart_of_driver = { .name = "mpc52xx-psc-uart", }, }; -#endif /* defined(CONFIG_PPC_MERGE) */ /* ======================================================================== */ @@ -1423,7 +1259,6 @@ mpc52xx_uart_init(void) return ret; } -#if defined(CONFIG_PPC_MERGE) mpc52xx_uart_of_enumerate(); ret = of_register_platform_driver(&mpc52xx_uart_of_driver); @@ -1433,16 +1268,6 @@ mpc52xx_uart_init(void) uart_unregister_driver(&mpc52xx_uart_driver); return ret; } -#else - psc_ops = &mpc52xx_psc_ops; - ret = platform_driver_register(&mpc52xx_uart_platform_driver); - if (ret) { - printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", - __FILE__, ret); - uart_unregister_driver(&mpc52xx_uart_driver); - return ret; - } -#endif return 0; } @@ -1450,11 +1275,7 @@ mpc52xx_uart_init(void) static void __exit mpc52xx_uart_exit(void) { -#if defined(CONFIG_PPC_MERGE) of_unregister_platform_driver(&mpc52xx_uart_of_driver); -#else - platform_driver_unregister(&mpc52xx_uart_platform_driver); -#endif uart_unregister_driver(&mpc52xx_uart_driver); } -- cgit v1.2.3 From b68d185ab12b1fc8000432c5d5ab5404d4788b4c Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 4 Sep 2008 02:57:57 +0000 Subject: ibm_newemac: Allow the "no flow control" EMAC feature to work Some PowerPC 40x chips have errata that force us not to use the integrated flow control. We have the feature defined, but it currently can't be used because it is never added to EMAC_FTRS_POSSIBLE. This adds a Kconfig option for affected platforms to select and puts the feature in the EMAC_FTRS_POSSIBLE list. This is set for PowerPC 405EZ platforms as well. Signed-off-by: Josh Boyer Acked-by: Benjamin Herrenschmidt Acked-by: Jeff Garzik Signed-off-by: Josh Boyer --- drivers/net/ibm_newemac/Kconfig | 4 ++++ drivers/net/ibm_newemac/core.c | 2 ++ drivers/net/ibm_newemac/core.h | 3 +++ 3 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig index 70a3272ee99..dfb6547c37c 100644 --- a/drivers/net/ibm_newemac/Kconfig +++ b/drivers/net/ibm_newemac/Kconfig @@ -62,3 +62,7 @@ config IBM_NEW_EMAC_TAH config IBM_NEW_EMAC_EMAC4 bool default n + +config IBM_NEW_EMAC_NO_FLOW_CTRL + bool + default n diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index ccd9d9058f6..4e633870e6e 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2567,6 +2567,8 @@ static int __devinit emac_init_config(struct emac_instance *dev) if (of_device_is_compatible(np, "ibm,emac-440ep") || of_device_is_compatible(np, "ibm,emac-440gr")) dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; + if (of_device_is_compatible(np, "ibm,emac-405ez")) + dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x; } /* Fixup some feature bits based on the device tree */ diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h index 6545e69d12c..59e5a5d802f 100644 --- a/drivers/net/ibm_newemac/core.h +++ b/drivers/net/ibm_newemac/core.h @@ -340,6 +340,9 @@ enum { #endif #ifdef CONFIG_IBM_NEW_EMAC_RGMII EMAC_FTR_HAS_RGMII | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL + EMAC_FTR_NO_FLOW_CONTROL_40x | #endif EMAC_FTR_440EP_PHY_CLK_FIX, }; -- cgit v1.2.3 From ec4f9945b5b3e9e491a04eb1efe1c959371fa6de Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 4 Sep 2008 04:03:45 +0000 Subject: ibm_newemac: Introduce mal_has_feature There are some PowerPC SoCs that do odd things with the MAL handling. In order to accommodate them, we need to introduce a feature mechanism that is similar to the existing emac_has_feature function. This adds a feature variable to the mal_instance structure, and adds a mal_has_feature function. Two features are defined and are guarded by Kconfig options that are selected by the affected platforms. MAL_FTR_CLEAR_ICINSTAT is used for platforms that need to clear the interrupt bits in the ICINTSTAT SDR for txeob/rxeob. This is common on MAL implementations that have interrupt coalescing. MAL_FTR_COMMON_ERR_INT is used for platforms that have SERR, TXDE, and RXDE OR'd into a single interrupt bit. Signed-off-by: Josh Boyer Acked-by: Benjamin Herrenschmidt Acked-by: Jeff Garzik Signed-off-by: Josh Boyer --- drivers/net/ibm_newemac/Kconfig | 8 ++++++++ drivers/net/ibm_newemac/mal.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig index dfb6547c37c..44e5a0e9922 100644 --- a/drivers/net/ibm_newemac/Kconfig +++ b/drivers/net/ibm_newemac/Kconfig @@ -66,3 +66,11 @@ config IBM_NEW_EMAC_EMAC4 config IBM_NEW_EMAC_NO_FLOW_CTRL bool default n + +config IBM_NEW_EMAC_MAL_CLR_ICINTSTAT + bool + default n + +config IBM_NEW_EMAC_MAL_COMMON_ERR + bool + default n diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h index eaa7262dc07..0b2413839b7 100644 --- a/drivers/net/ibm_newemac/mal.h +++ b/drivers/net/ibm_newemac/mal.h @@ -213,6 +213,8 @@ struct mal_instance { struct of_device *ofdev; int index; spinlock_t lock; + + unsigned int features; }; static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) @@ -225,6 +227,38 @@ static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) dcr_write(mal->dcr_host, reg, val); } +/* Features of various MAL implementations */ + +/* Set if you have interrupt coalescing and you have to clear the SDR + * register for TXEOB and RXEOB interrupts to work + */ +#define MAL_FTR_CLEAR_ICINTSTAT 0x00000001 + +/* Set if your MAL has SERR, TXDE, and RXDE OR'd into a single UIC + * interrupt + */ +#define MAL_FTR_COMMON_ERR_INT 0x00000002 + +enum { + MAL_FTRS_ALWAYS = 0, + + MAL_FTRS_POSSIBLE = +#ifdef CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT + MAL_FTR_CLEAR_ICINTSTAT | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR + MAL_FTR_COMMON_ERR_INT | +#endif + 0, +}; + +static inline int mal_has_feature(struct mal_instance *dev, + unsigned long feature) +{ + return (MAL_FTRS_ALWAYS & feature) || + (MAL_FTRS_POSSIBLE & dev->features & feature); +} + /* Register MAL devices */ int mal_init(void); void mal_exit(void); -- cgit v1.2.3 From fbcc4bacee30cad4e4a13d05492a9ed0c9c3e8c7 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 4 Sep 2008 04:08:20 +0000 Subject: ibm_newemac: MAL support for PowerPC 405EZ The PowerPC 405EZ SoC has some differences in the interrupt layout and handling for the MAL. The SERR, TXDE, and RXDE interrupts are OR'd into a single interrupt. Also, due to the possibility for interrupt coalescing, the TXEOB and RXEOB interrupts require an interrupt bit to be cleared in the ICINTSTAT SDR. This sets the proper MAL feature bits for 405EZ boards, and adds a common shared handler for SERR, TXDE, and RXDE. The defines for the ICINTSTAT DCR are added to the proper header file as well. This has been adapted from code originally written by Stefan Roese. Signed-off-by: Josh Boyer Acked-by: Benjamin Herrenschmidt Acked-by: Jeff Garzik Signed-off-by: Josh Boyer --- drivers/net/ibm_newemac/mal.c | 60 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 10c267b2b96..1839d3f154a 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c @@ -28,6 +28,7 @@ #include #include "core.h" +#include static int mal_count; @@ -279,6 +280,10 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance) mal_schedule_poll(mal); set_mal_dcrn(mal, MAL_TXEOBISR, r); + if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT)) + mtdcri(SDR0, DCRN_SDR_ICINTSTAT, + (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICTX)); + return IRQ_HANDLED; } @@ -293,6 +298,10 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance) mal_schedule_poll(mal); set_mal_dcrn(mal, MAL_RXEOBISR, r); + if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT)) + mtdcri(SDR0, DCRN_SDR_ICINTSTAT, + (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICRX)); + return IRQ_HANDLED; } @@ -336,6 +345,25 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance) return IRQ_HANDLED; } +static irqreturn_t mal_int(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + u32 esr = get_mal_dcrn(mal, MAL_ESR); + + if (esr & MAL_ESR_EVB) { + /* descriptor error */ + if (esr & MAL_ESR_DE) { + if (esr & MAL_ESR_CIDT) + return mal_rxde(irq, dev_instance); + else + return mal_txde(irq, dev_instance); + } else { /* SERR */ + return mal_serr(irq, dev_instance); + } + } + return IRQ_HANDLED; +} + void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) { /* Spinlock-type semantics: only one caller disable poll at a time */ @@ -493,6 +521,8 @@ static int __devinit mal_probe(struct of_device *ofdev, unsigned int dcr_base; const u32 *prop; u32 cfg; + unsigned long irqflags; + irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde; mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); if (!mal) { @@ -542,11 +572,21 @@ static int __devinit mal_probe(struct of_device *ofdev, goto fail; } + if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez")) + mal->features |= (MAL_FTR_CLEAR_ICINTSTAT | + MAL_FTR_COMMON_ERR_INT); + mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0); mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1); mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2); - mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); - mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); + + if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { + mal->txde_irq = mal->rxde_irq = mal->serr_irq; + } else { + mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); + mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); + } + if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ || mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ || mal->rxde_irq == NO_IRQ) { @@ -608,16 +648,26 @@ static int __devinit mal_probe(struct of_device *ofdev, sizeof(struct mal_descriptor) * mal_rx_bd_offset(mal, i)); - err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal); + if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { + irqflags = IRQF_SHARED; + hdlr_serr = hdlr_txde = hdlr_rxde = mal_int; + } else { + irqflags = 0; + hdlr_serr = mal_serr; + hdlr_txde = mal_txde; + hdlr_rxde = mal_rxde; + } + + err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal); if (err) goto fail2; - err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal); + err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal); if (err) goto fail3; err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); if (err) goto fail4; - err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); + err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal); if (err) goto fail5; err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); -- cgit v1.2.3 From 9e3cb29497561c846d0e7efc445731764d93c749 Mon Sep 17 00:00:00 2001 From: Victor Gallardo Date: Wed, 1 Oct 2008 23:37:57 -0700 Subject: ibm_newemac: Add support for GPCS, SGMII and M88E1112 PHY Add support for the phy types found on the Arches and other PowerPC 460 based boards. Signed-off-by: Victor Gallardo Acked-by: Benjamin Herrenschmidt Acked-by: Jeff Garzik Signed-off-by: Josh Boyer --- drivers/net/ibm_newemac/core.c | 58 ++++++++++++++++++++++++----- drivers/net/ibm_newemac/core.h | 8 ++++ drivers/net/ibm_newemac/phy.c | 84 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/ibm_newemac/phy.h | 2 + 4 files changed, 143 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 4e633870e6e..efcf21c9f5c 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -130,6 +130,7 @@ static inline void emac_report_timeout_error(struct emac_instance *dev, const char *error) { if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX | + EMAC_FTR_460EX_PHY_CLK_FIX | EMAC_FTR_440EP_PHY_CLK_FIX)) DBG(dev, "%s" NL, error); else if (net_ratelimit()) @@ -201,13 +202,15 @@ static inline int emac_phy_supports_gige(int phy_mode) { return phy_mode == PHY_MODE_GMII || phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_SGMII || phy_mode == PHY_MODE_TBI || phy_mode == PHY_MODE_RTBI; } static inline int emac_phy_gpcs(int phy_mode) { - return phy_mode == PHY_MODE_TBI || + return phy_mode == PHY_MODE_SGMII || + phy_mode == PHY_MODE_TBI || phy_mode == PHY_MODE_RTBI; } @@ -351,10 +354,24 @@ static int emac_reset(struct emac_instance *dev) emac_tx_disable(dev); } +#ifdef CONFIG_PPC_DCR_NATIVE + /* Enable internal clock source */ + if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) + dcri_clrset(SDR0, SDR0_ETH_CFG, + 0, SDR0_ETH_CFG_ECS << dev->cell_index); +#endif + out_be32(&p->mr0, EMAC_MR0_SRST); while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) --n; +#ifdef CONFIG_PPC_DCR_NATIVE + /* Enable external clock source */ + if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) + dcri_clrset(SDR0, SDR0_ETH_CFG, + SDR0_ETH_CFG_ECS << dev->cell_index, 0); +#endif + if (n) { dev->reset_failed = 0; return 0; @@ -547,8 +564,9 @@ static int emac_configure(struct emac_instance *dev) switch (dev->phy.speed) { case SPEED_1000: if (emac_phy_gpcs(dev->phy.mode)) { - mr1 |= EMAC_MR1_MF_1000GPCS | - EMAC_MR1_MF_IPPA(dev->phy.address); + mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA( + (dev->phy.gpcs_address != 0xffffffff) ? + dev->phy.gpcs_address : dev->phy.address); /* Put some arbitrary OUI, Manuf & Rev IDs so we can * identify this GPCS PHY later. @@ -660,8 +678,12 @@ static int emac_configure(struct emac_instance *dev) out_be32(&p->iser, r); /* We need to take GPCS PHY out of isolate mode after EMAC reset */ - if (emac_phy_gpcs(dev->phy.mode)) - emac_mii_reset_phy(&dev->phy); + if (emac_phy_gpcs(dev->phy.mode)) { + if (dev->phy.gpcs_address != 0xffffffff) + emac_mii_reset_gpcs(&dev->phy); + else + emac_mii_reset_phy(&dev->phy); + } return 0; } @@ -866,7 +888,9 @@ static int emac_mdio_read(struct net_device *ndev, int id, int reg) struct emac_instance *dev = netdev_priv(ndev); int res; - res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev, + res = __emac_mdio_read((dev->mdio_instance && + dev->phy.gpcs_address != id) ? + dev->mdio_instance : dev, (u8) id, (u8) reg); return res; } @@ -875,7 +899,9 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) { struct emac_instance *dev = netdev_priv(ndev); - __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev, + __emac_mdio_write((dev->mdio_instance && + dev->phy.gpcs_address != id) ? + dev->mdio_instance : dev, (u8) id, (u8) reg, (u16) val); } @@ -2367,7 +2393,11 @@ static int __devinit emac_init_phy(struct emac_instance *dev) * XXX I probably should move these settings to the dev tree */ dev->phy.address = -1; - dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; + dev->phy.features = SUPPORTED_MII; + if (emac_phy_supports_gige(dev->phy_mode)) + dev->phy.features |= SUPPORTED_1000baseT_Full; + else + dev->phy.features |= SUPPORTED_100baseT_Full; dev->phy.pause = 1; return 0; @@ -2406,7 +2436,9 @@ static int __devinit emac_init_phy(struct emac_instance *dev) * Note that the busy_phy_map is currently global * while it should probably be per-ASIC... */ - dev->phy.address = dev->cell_index; + dev->phy.gpcs_address = dev->gpcs_address; + if (dev->phy.gpcs_address == 0xffffffff) + dev->phy.address = dev->cell_index; } emac_configure(dev); @@ -2516,6 +2548,8 @@ static int __devinit emac_init_config(struct emac_instance *dev) dev->phy_address = 0xffffffff; if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0)) dev->phy_map = 0xffffffff; + if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0)) + dev->gpcs_address = 0xffffffff; if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1)) return -ENXIO; if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0)) @@ -2559,6 +2593,9 @@ static int __devinit emac_init_config(struct emac_instance *dev) /* Check EMAC version */ if (of_device_is_compatible(np, "ibm,emac4sync")) { dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC); + if (of_device_is_compatible(np, "ibm,emac-460ex") || + of_device_is_compatible(np, "ibm,emac-460gt")) + dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX; } else if (of_device_is_compatible(np, "ibm,emac4")) { dev->features |= EMAC_FTR_EMAC4; if (of_device_is_compatible(np, "ibm,emac-440gx")) @@ -2826,6 +2863,9 @@ static int __devinit emac_probe(struct of_device *ofdev, ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + if (dev->phy_mode == PHY_MODE_SGMII) + printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name); + if (dev->phy.address >= 0) printk("%s: found %s PHY (0x%02x)\n", ndev->name, dev->phy.def->name, dev->phy.address); diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h index 59e5a5d802f..18d56c6c423 100644 --- a/drivers/net/ibm_newemac/core.h +++ b/drivers/net/ibm_newemac/core.h @@ -190,6 +190,9 @@ struct emac_instance { struct delayed_work link_work; int link_polling; + /* GPCS PHY infos */ + u32 gpcs_address; + /* Shared MDIO if any */ u32 mdio_ph; struct of_device *mdio_dev; @@ -317,6 +320,10 @@ struct emac_instance { * The 405EX and 460EX contain the EMAC4SYNC core */ #define EMAC_FTR_EMAC4SYNC 0x00000200 +/* + * Set if we need phy clock workaround for 460ex or 460gt + */ +#define EMAC_FTR_460EX_PHY_CLK_FIX 0x00000400 /* Right now, we don't quite handle the always/possible masks on the @@ -344,6 +351,7 @@ enum { #ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL EMAC_FTR_NO_FLOW_CONTROL_40x | #endif + EMAC_FTR_460EX_PHY_CLK_FIX | EMAC_FTR_440EP_PHY_CLK_FIX, }; diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c index 37bfeea8788..606db53ef78 100644 --- a/drivers/net/ibm_newemac/phy.c +++ b/drivers/net/ibm_newemac/phy.c @@ -38,6 +38,16 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val) phy->mdio_write(phy->dev, phy->address, reg, val); } +static inline int gpcs_phy_read(struct mii_phy *phy, int reg) +{ + return phy->mdio_read(phy->dev, phy->gpcs_address, reg); +} + +static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val) +{ + phy->mdio_write(phy->dev, phy->gpcs_address, reg, val); +} + int emac_mii_reset_phy(struct mii_phy *phy) { int val; @@ -62,6 +72,37 @@ int emac_mii_reset_phy(struct mii_phy *phy) return limit <= 0; } +int emac_mii_reset_gpcs(struct mii_phy *phy) +{ + int val; + int limit = 10000; + + val = gpcs_phy_read(phy, MII_BMCR); + val &= ~(BMCR_ISOLATE | BMCR_ANENABLE); + val |= BMCR_RESET; + gpcs_phy_write(phy, MII_BMCR, val); + + udelay(300); + + while (limit--) { + val = gpcs_phy_read(phy, MII_BMCR); + if (val >= 0 && (val & BMCR_RESET) == 0) + break; + udelay(10); + } + if ((val & BMCR_ISOLATE) && limit > 0) + gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); + + if (limit > 0 && phy->mode == PHY_MODE_SGMII) { + /* Configure GPCS interface to recommended setting for SGMII */ + gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */ + gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */ + gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX */ + } + + return limit <= 0; +} + static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) { int ctl, adv; @@ -332,6 +373,33 @@ static int m88e1111_init(struct mii_phy *phy) return 0; } +static int m88e1112_init(struct mii_phy *phy) +{ + /* + * Marvell 88E1112 PHY needs to have the SGMII MAC + * interace (page 2) properly configured to + * communicate with the 460EX/GT GPCS interface. + */ + + u16 reg_short; + + pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__); + + /* Set access to Page 2 */ + phy_write(phy, 0x16, 0x0002); + + phy_write(phy, 0x00, 0x0040); /* 1Gbps */ + reg_short = (u16)(phy_read(phy, 0x1a)); + reg_short |= 0x8000; /* bypass Auto-Negotiation */ + phy_write(phy, 0x1a, reg_short); + emac_mii_reset_phy(phy); /* reset MAC interface */ + + /* Reset access to Page 0 */ + phy_write(phy, 0x16, 0x0000); + + return 0; +} + static int et1011c_init(struct mii_phy *phy) { u16 reg_short; @@ -384,11 +452,27 @@ static struct mii_phy_def m88e1111_phy_def = { .ops = &m88e1111_phy_ops, }; +static struct mii_phy_ops m88e1112_phy_ops = { + .init = m88e1112_init, + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def m88e1112_phy_def = { + .phy_id = 0x01410C90, + .phy_id_mask = 0x0ffffff0, + .name = "Marvell 88E1112 Ethernet", + .ops = &m88e1112_phy_ops, +}; + static struct mii_phy_def *mii_phy_table[] = { &et1011c_phy_def, &cis8201_phy_def, &bcm5248_phy_def, &m88e1111_phy_def, + &m88e1112_phy_def, &genmii_phy_def, NULL }; diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h index 1b65c81f655..5d2bf4cbe50 100644 --- a/drivers/net/ibm_newemac/phy.h +++ b/drivers/net/ibm_newemac/phy.h @@ -57,6 +57,7 @@ struct mii_phy { or determined automaticaly */ int address; /* PHY address */ int mode; /* PHY mode */ + int gpcs_address; /* GPCS PHY address */ /* 1: autoneg enabled, 0: disabled */ int autoneg; @@ -81,5 +82,6 @@ struct mii_phy { */ int emac_mii_phy_probe(struct mii_phy *phy, int address); int emac_mii_reset_phy(struct mii_phy *phy); +int emac_mii_reset_gpcs(struct mii_phy *phy); #endif /* __IBM_NEWEMAC_PHY_H */ -- cgit v1.2.3 From 0bb08107edb3d38b89be8fb623b46df73f2aa8c8 Mon Sep 17 00:00:00 2001 From: Johann Felix Soden Date: Sun, 21 Sep 2008 09:02:36 +0000 Subject: powerpc/iseries: Remove unused variable in viodasd.c The variable statindex in send_request is never read, so remove it. Signed-off-by: Johann Felix Soden Signed-off-by: Benjamin Herrenschmidt --- drivers/block/viodasd.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index f1c8feb5510..1730d29e604 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -249,7 +249,6 @@ static int send_request(struct request *req) struct HvLpEvent *hev; struct scatterlist sg[VIOMAXBLOCKDMA]; int sgindex; - int statindex; struct viodasd_device *d; unsigned long flags; @@ -258,11 +257,9 @@ static int send_request(struct request *req) if (rq_data_dir(req) == READ) { direction = DMA_FROM_DEVICE; viocmd = viomajorsubtype_blockio | vioblockread; - statindex = 0; } else { direction = DMA_TO_DEVICE; viocmd = viomajorsubtype_blockio | vioblockwrite; - statindex = 1; } d = req->rq_disk->private_data; -- cgit v1.2.3 From a897ea13f7a801e6baba8d4985f459042712244c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 8 Oct 2008 09:02:11 -0600 Subject: powerpc/mpc5200: fix build warnings on mpc52xx_psc_spi driver The register definitions have been changed for the mpc5200 PSC ports to cover some of the changes in the mpc5200b. One change is that the ccr register is now a u32 instead of a u16. However, for the purposes of this driver we want to continue to use 16 bit access to avoid changing the existing (working) behaviour. This patch allows the driver to continue to do 16 bit accesses without the compiler complaining about it. Signed-off-by: Grant Likely --- drivers/spi/mpc52xx_psc_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index 25eda71f4bf..cdb3d319171 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -108,13 +108,13 @@ static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi) * Because psc->ccr is defined as 16bit register instead of 32bit * just set the lower byte of BitClkDiv */ - ccr = in_be16(&psc->ccr); + ccr = in_be16((u16 __iomem *)&psc->ccr); ccr &= 0xFF00; if (cs->speed_hz) ccr |= (MCLK / cs->speed_hz - 1) & 0xFF; else /* by default SPI Clk 1MHz */ ccr |= (MCLK / 1000000 - 1) & 0xFF; - out_be16(&psc->ccr, ccr); + out_be16((u16 __iomem *)&psc->ccr, ccr); mps->bits_per_word = cs->bits_per_word; if (mps->activate_cs) @@ -347,7 +347,7 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) /* Configure 8bit codec mode as a SPI master and use EOF flags */ /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */ out_be32(&psc->sicr, 0x0180C800); - out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */ + out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */ /* Set 2ms DTL delay */ out_8(&psc->ctur, 0x00); -- cgit v1.2.3 From 618b26d52843c0f85b8eb143cf2695d7f6fd072d Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Wed, 8 Oct 2008 11:36:42 -0600 Subject: i2c-mpc: suppress I2C device probing This patch suppresses I2C device probing by clearing the class field of the "struct i2c_adapter" for the MPC I2C bus adapters. Some board configurations which rely on probing must be fixed up by adding a proper I2C device node to the DTS file, like the TQM85xx modules. Signed-off-by: Wolfgang Grandegger Signed-off-by: Grant Likely --- drivers/i2c/busses/i2c-mpc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 27443f073bc..a9a45fcc854 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -312,7 +312,6 @@ static struct i2c_adapter mpc_ops = { .name = "MPC adapter", .id = I2C_HW_MPC107, .algo = &mpc_algo, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, .timeout = 1, }; -- cgit v1.2.3 From 4c3ed7d61bd474380e0d3e1eb0da164942f7c84e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 23 Sep 2008 14:12:19 +0400 Subject: OF: add fsl,mcu-mpc8349emitx to the exception list of/base.c matches on the first (most specific) entries, which isn't quite practical but it was discussed[1] that this won't change. The bindings specifies verbose information for the devices, but it doesn't fit in the I2C ID's 20 characters limit. The limit won't change[2], and the bindings won't change either as they're correct. So we have to put an exception for the MPC8349E-mITX-compatible MCUs. [1] http://www.mail-archive.com/linuxppc-dev@ozlabs.org/msg21196.html [2] http://www.nabble.com/-PATCH-1-2--i2c:-expand-I2C's-id.name-to-23-characters-td19577063.html Signed-off-by: Anton Vorontsov Signed-off-by: Grant Likely --- drivers/of/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index ad8ac1a8af2..a7264644003 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -410,7 +410,7 @@ struct of_modalias_table { char *modalias; }; static struct of_modalias_table of_modalias_table[] = { - /* Empty for now; add entries as needed */ + { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" }, }; /** -- cgit v1.2.3 From 4538d0ca71b4f8991c4c0f433d7d17805738326e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 6 Oct 2008 07:26:54 +0000 Subject: powerpc: Fix no interrupt handling in pata_of_platform When no interrupt is specified the pata_of_platform fills the irq_res resource with -1, which is wrong to do for two reasons: 1. By definition, 'no irq' should be IRQ 0, not some negative integer; 2. pata_platform checks for irq_res.start > 0, but since irq_res.start is unsigned type, the check will be true for `-1'. Reported-by: Steven A. Falco Signed-off-by: Anton Vorontsov Signed-off-by: Benjamin Herrenschmidt --- drivers/ata/pata_of_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index 408da30594c..1f18ad9e4fe 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -52,7 +52,7 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev, ret = of_irq_to_resource(dn, 0, &irq_res); if (ret == NO_IRQ) - irq_res.start = irq_res.end = -1; + irq_res.start = irq_res.end = 0; else irq_res.flags = 0; -- cgit v1.2.3 From 58f467ce1476f5b2a347cee3a32275b737fbd667 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 8 Oct 2008 05:05:29 +0000 Subject: powerpc/of-bindings: Don't support linux, "compatible" values Compatible property values in the form linux, is not documented anywhere and using it leaks Linux implementation details into the device tree data (which is bad). Remove support for compatible values of this form. If any platforms exist which depended on this code (and I don't know of any), then they can be fixed up by adding legacy translations to the lookup table in this file. Signed-off-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt --- drivers/of/base.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index ad8ac1a8af2..cd1ce7ab851 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -420,13 +420,12 @@ static struct of_modalias_table of_modalias_table[] = { * @len: Length of modalias value * * Based on the value of the compatible property, this routine will determine - * an appropriate modalias value for a particular device tree node. Three - * separate methods are used to derive a modalias value. + * an appropriate modalias value for a particular device tree node. Two + * separate methods are attempted to derive a modalias value. * * First method is to lookup the compatible value in of_modalias_table. - * Second is to look for a "linux," entry in the compatible list - * and used that for modalias. Third is to strip off the manufacturer - * prefix from the first compatible entry and use the remainder as modalias + * Second is to strip off the manufacturer prefix from the first + * compatible entry and use the remainder as modalias * * This routine returns 0 on success */ @@ -449,21 +448,7 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) if (!compatible) return -ENODEV; - /* 2. search for linux, entry */ - p = compatible; - while (cplen > 0) { - if (!strncmp(p, "linux,", 6)) { - p += 6; - strlcpy(modalias, p, len); - return 0; - } - - i = strlen(p) + 1; - p += i; - cplen -= i; - } - - /* 3. take first compatible entry and strip manufacturer */ + /* 2. take first compatible entry and strip manufacturer */ p = strchr(compatible, ','); if (!p) return -ENODEV; -- cgit v1.2.3 From 64b60e096fa391c56f93e6216115e6757bf86b7e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 10 Oct 2008 04:43:17 +0000 Subject: of: Add new helper of_parse_phandles_with_args() The helper is factored out of of_get_gpio(). Will be used by the QE pin multiplexing functions (they need to parse the gpios = <> too). Signed-off-by: Anton Vorontsov Signed-off-by: Benjamin Herrenschmidt --- drivers/of/base.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/of/gpio.c | 81 ++++++++++------------------------------ 2 files changed, 128 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index cd1ce7ab851..4270eb4a26a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -458,3 +458,112 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) } EXPORT_SYMBOL_GPL(of_modalias_node); +/** + * of_parse_phandles_with_args - Find a node pointed by phandle in a list + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @index: index of a phandle to parse out + * @out_node: pointer to device_node struct pointer (will be filled) + * @out_args: pointer to arguments pointer (will be filled) + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_node and out_args, on error returns + * appropriate errno value. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * node3 { + * list = <&phandle1 1 2 &phandle2 3>; + * } + * + * To get a device_node of the `node2' node you may call this: + * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); + */ +int of_parse_phandles_with_args(struct device_node *np, const char *list_name, + const char *cells_name, int index, + struct device_node **out_node, + const void **out_args) +{ + int ret = -EINVAL; + const u32 *list; + const u32 *list_end; + int size; + int cur_index = 0; + struct device_node *node = NULL; + const void *args; + + list = of_get_property(np, list_name, &size); + if (!list) { + ret = -ENOENT; + goto err0; + } + list_end = list + size / sizeof(*list); + + while (list < list_end) { + const u32 *cells; + const phandle *phandle; + + phandle = list; + args = list + 1; + + /* one cell hole in the list = <>; */ + if (!*phandle) { + list++; + goto next; + } + + node = of_find_node_by_phandle(*phandle); + if (!node) { + pr_debug("%s: could not find phandle\n", + np->full_name); + goto err0; + } + + cells = of_get_property(node, cells_name, &size); + if (!cells || size != sizeof(*cells)) { + pr_debug("%s: could not get %s for %s\n", + np->full_name, cells_name, node->full_name); + goto err1; + } + + /* Next phandle is at offset of one phandle cell + #cells */ + list += 1 + *cells; + if (list > list_end) { + pr_debug("%s: insufficient arguments length\n", + np->full_name); + goto err1; + } +next: + if (cur_index == index) + break; + + of_node_put(node); + node = NULL; + cur_index++; + } + + if (!node) { + ret = -ENOENT; + goto err0; + } + + *out_node = node; + *out_args = args; + + return 0; +err1: + of_node_put(node); +err0: + pr_debug("%s failed with status %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL(of_parse_phandles_with_args); diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 1c9cab844f1..7cd7301b583 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -28,78 +28,35 @@ */ int of_get_gpio(struct device_node *np, int index) { - int ret = -EINVAL; + int ret; struct device_node *gc; struct of_gpio_chip *of_gc = NULL; int size; - const u32 *gpios; - u32 nr_cells; - int i; const void *gpio_spec; const u32 *gpio_cells; - int gpio_index = 0; - gpios = of_get_property(np, "gpios", &size); - if (!gpios) { - ret = -ENOENT; + ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, + &gc, &gpio_spec); + if (ret) { + pr_debug("%s: can't parse gpios property\n", __func__); goto err0; } - nr_cells = size / sizeof(u32); - - for (i = 0; i < nr_cells; gpio_index++) { - const phandle *gpio_phandle; - - gpio_phandle = gpios + i; - gpio_spec = gpio_phandle + 1; - - /* one cell hole in the gpios = <>; */ - if (!*gpio_phandle) { - if (gpio_index == index) - return -ENOENT; - i++; - continue; - } - - gc = of_find_node_by_phandle(*gpio_phandle); - if (!gc) { - pr_debug("%s: could not find phandle for gpios\n", - np->full_name); - goto err0; - } - - of_gc = gc->data; - if (!of_gc) { - pr_debug("%s: gpio controller %s isn't registered\n", - np->full_name, gc->full_name); - goto err1; - } - - gpio_cells = of_get_property(gc, "#gpio-cells", &size); - if (!gpio_cells || size != sizeof(*gpio_cells) || - *gpio_cells != of_gc->gpio_cells) { - pr_debug("%s: wrong #gpio-cells for %s\n", - np->full_name, gc->full_name); - goto err1; - } - - /* Next phandle is at phandle cells + #gpio-cells */ - i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells; - if (i >= nr_cells + 1) { - pr_debug("%s: insufficient gpio-spec length\n", - np->full_name); - goto err1; - } - - if (gpio_index == index) - break; - - of_gc = NULL; - of_node_put(gc); - } + of_gc = gc->data; if (!of_gc) { - ret = -ENOENT; - goto err0; + pr_debug("%s: gpio controller %s isn't registered\n", + np->full_name, gc->full_name); + ret = -ENODEV; + goto err1; + } + + gpio_cells = of_get_property(gc, "#gpio-cells", &size); + if (!gpio_cells || size != sizeof(*gpio_cells) || + *gpio_cells != of_gc->gpio_cells) { + pr_debug("%s: wrong #gpio-cells for %s\n", + np->full_name, gc->full_name); + ret = -EINVAL; + goto err1; } ret = of_gc->xlate(of_gc, np, gpio_spec); -- cgit v1.2.3 From 7e7385ce4115830bf5e0b43d62087a94871b78de Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 23 Sep 2008 18:12:19 +0400 Subject: OF: add fsl,mcu-mpc8349emitx to the exception list of/base.c matches on the first (most specific) entries, which isn't quite practical but it was discussed[1] that this won't change. The bindings specifies verbose information for the devices, but it doesn't fit in the I2C ID's 20 characters limit. The limit won't change[2], and the bindings won't change either as they're correct. So we have to put an exception for the MPC8349E-mITX-compatible MCUs. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- drivers/of/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 4270eb4a26a..7c79e94a35e 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -410,7 +410,7 @@ struct of_modalias_table { char *modalias; }; static struct of_modalias_table of_modalias_table[] = { - /* Empty for now; add entries as needed */ + { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" }, }; /** -- cgit v1.2.3 From d6c3db83c5567b3a4d8d0bf33dc5687abdf65274 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 23 Sep 2008 18:13:00 +0400 Subject: i2c: MPC8349E-mITX Power Management and GPIO expander driver On MPC8349E-mITX, MPC8315E-RDB and MPC837x-RDB boards there is a Freescale MC9S08QG8 (MCU) chip with the custom firmware pre-programmed. The chip is used to power-off the board by the software, and to control some GPIO pins. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- drivers/i2c/chips/Kconfig | 11 ++ drivers/i2c/chips/Makefile | 1 + drivers/i2c/chips/mcu_mpc8349emitx.c | 209 +++++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 drivers/i2c/chips/mcu_mpc8349emitx.c (limited to 'drivers') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index a95cb9465d6..17356827b93 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -172,4 +172,15 @@ config MENELAUS and other features that are often used in portable devices like cell phones and PDAs. +config MCU_MPC8349EMITX + tristate "MPC8349E-mITX MCU driver" + depends on I2C && PPC_83xx + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + help + Say Y here to enable soft power-off functionality on the Freescale + boards with the MPC8349E-mITX-compatible MCU chips. This driver will + also register MCU GPIOs with the generic GPIO API, so you'll able + to use MCU pins as GPIOs. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 39e3e69ed12..ca520fa143d 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o +obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/mcu_mpc8349emitx.c b/drivers/i2c/chips/mcu_mpc8349emitx.c new file mode 100644 index 00000000000..82a9bcb858b --- /dev/null +++ b/drivers/i2c/chips/mcu_mpc8349emitx.c @@ -0,0 +1,209 @@ +/* + * Power Management and GPIO expander driver for MPC8349E-mITX-compatible MCU + * + * Copyright (c) 2008 MontaVista Software, Inc. + * + * Author: Anton Vorontsov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * I don't have specifications for the MCU firmware, I found this register + * and bits positions by the trial&error method. + */ +#define MCU_REG_CTRL 0x20 +#define MCU_CTRL_POFF 0x40 + +#define MCU_NUM_GPIO 2 + +struct mcu { + struct mutex lock; + struct device_node *np; + struct i2c_client *client; + struct of_gpio_chip of_gc; + u8 reg_ctrl; +}; + +static struct mcu *glob_mcu; + +static void mcu_power_off(void) +{ + struct mcu *mcu = glob_mcu; + + pr_info("Sending power-off request to the MCU...\n"); + mutex_lock(&mcu->lock); + i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL, + mcu->reg_ctrl | MCU_CTRL_POFF); + mutex_unlock(&mcu->lock); +} + +static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_gpio_chip *of_gc = to_of_gpio_chip(gc); + struct mcu *mcu = container_of(of_gc, struct mcu, of_gc); + u8 bit = 1 << (4 + gpio); + + mutex_lock(&mcu->lock); + if (val) + mcu->reg_ctrl &= ~bit; + else + mcu->reg_ctrl |= bit; + + i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, mcu->reg_ctrl); + mutex_unlock(&mcu->lock); +} + +static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + mcu_gpio_set(gc, gpio, val); + return 0; +} + +static int mcu_gpiochip_add(struct mcu *mcu) +{ + struct device_node *np; + struct of_gpio_chip *of_gc = &mcu->of_gc; + struct gpio_chip *gc = &of_gc->gc; + int ret; + + np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx"); + if (!np) + return -ENODEV; + + gc->owner = THIS_MODULE; + gc->label = np->full_name; + gc->can_sleep = 1; + gc->ngpio = MCU_NUM_GPIO; + gc->base = -1; + gc->set = mcu_gpio_set; + gc->direction_output = mcu_gpio_dir_out; + of_gc->gpio_cells = 2; + of_gc->xlate = of_gpio_simple_xlate; + + np->data = of_gc; + mcu->np = np; + + /* + * We don't want to lose the node, its ->data and ->full_name... + * So, if succeeded, we don't put the node here. + */ + ret = gpiochip_add(gc); + if (ret) + of_node_put(np); + return ret; +} + +static int mcu_gpiochip_remove(struct mcu *mcu) +{ + int ret; + + ret = gpiochip_remove(&mcu->of_gc.gc); + if (ret) + return ret; + of_node_put(mcu->np); + + return 0; +} + +static int __devinit mcu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mcu *mcu; + int ret; + + mcu = kzalloc(sizeof(*mcu), GFP_KERNEL); + if (!mcu) + return -ENOMEM; + + mutex_init(&mcu->lock); + mcu->client = client; + i2c_set_clientdata(client, mcu); + + ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL); + if (ret < 0) + goto err; + mcu->reg_ctrl = ret; + + ret = mcu_gpiochip_add(mcu); + if (ret) + goto err; + + /* XXX: this is potentially racy, but there is no lock for ppc_md */ + if (!ppc_md.power_off) { + glob_mcu = mcu; + ppc_md.power_off = mcu_power_off; + dev_info(&client->dev, "will provide power-off service\n"); + } + + return 0; +err: + kfree(mcu); + return ret; +} + +static int __devexit mcu_remove(struct i2c_client *client) +{ + struct mcu *mcu = i2c_get_clientdata(client); + int ret; + + if (glob_mcu == mcu) { + ppc_md.power_off = NULL; + glob_mcu = NULL; + } + + ret = mcu_gpiochip_remove(mcu); + if (ret) + return ret; + i2c_set_clientdata(client, NULL); + kfree(mcu); + return 0; +} + +static const struct i2c_device_id mcu_ids[] = { + { "mcu-mpc8349emitx", }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, mcu_ids); + +static struct i2c_driver mcu_driver = { + .driver = { + .name = "mcu-mpc8349emitx", + .owner = THIS_MODULE, + }, + .probe = mcu_probe, + .remove = __devexit_p(mcu_remove), + .id_table = mcu_ids, +}; + +static int __init mcu_init(void) +{ + return i2c_add_driver(&mcu_driver); +} +module_init(mcu_init); + +static void __exit mcu_exit(void) +{ + i2c_del_driver(&mcu_driver); +} +module_exit(mcu_exit); + +MODULE_DESCRIPTION("Power Management and GPIO expander driver for " + "MPC8349E-mITX-compatible MCU"); +MODULE_AUTHOR("Anton Vorontsov "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From eef2622a9fcfa964073333ea72c7c9cd20ad45e6 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Sun, 12 Oct 2008 21:51:31 +0000 Subject: hvc_console: Fix free_irq in spinlocked section commit 611e097d7707741a336a0677d9d69bec40f29f3d Author: Christian Borntraeger hvc_console: rework setup to replace irq functions with callbacks introduced a spinlock recursion problem. The notifier_del is called with a lock held, and in turns calls free_irq which then complains when manipulating procfs. This fixes it by moving the call to the notifier to outside of the locked section. Signed-off-by: Christian Borntraeger Signed-off-by: Benjamin Herrenschmidt --- drivers/char/hvc_console.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index fd64137b1ab..f2e4caf7059 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -367,13 +367,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_lock_irqsave(&hp->lock, flags); if (--hp->count == 0) { - if (hp->ops->notifier_del) - hp->ops->notifier_del(hp, hp->data); - /* We are done with the tty pointer now. */ hp->tty = NULL; spin_unlock_irqrestore(&hp->lock, flags); + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); + /* * Chain calls chars_in_buffer() and returns immediately if * there is no buffered data otherwise sleeps on a wait queue @@ -416,11 +416,11 @@ static void hvc_hangup(struct tty_struct *tty) hp->n_outbuf = 0; hp->tty = NULL; + spin_unlock_irqrestore(&hp->lock, flags); + if (hp->ops->notifier_del) hp->ops->notifier_del(hp, hp->data); - spin_unlock_irqrestore(&hp->lock, flags); - while(temp_open_count) { --temp_open_count; kref_put(&hp->kref, destroy_hvc_struct); -- cgit v1.2.3