Skip to contentSkip to conversation

pcmcia: CompactFlash driver for PA Semi Electra boards

PATCH Superseded Olof Johansson 4 participants 14 messages Jun 25, 2007 – Aug 31, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 pcmcia: CompactFlash driver for PA Semi Electra boards

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

---

Fixed the comments from Russell on last post, this should be good to merge now.

drivers/pcmcia/Kconfig +7 -0
Index: powerpc/drivers/pcmcia/Kconfig
===================================================================
@@ -270,6 +270,13 @@ config AT91_CF
 	  Say Y here to support the CompactFlash controller on AT91 chips.
 	  Or choose M to compile the driver as a module named "at91_cf".
 
+config ELECTRA_CF
+	bool "Electra CompactFlash Controller"
+	depends on PCMCIA=y && PPC_PASEMI
+	help
+	  Say Y here to support the CompactFlash controller on the
+	  PA Semi Electra eval board.
+
 config PCCARD_NONSTATIC
 	tristate
 
drivers/pcmcia/Makefile +1 -0
Index: powerpc/drivers/pcmcia/Makefile
===================================================================
@@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4171)			+= vrc417
 obj-$(CONFIG_PCMCIA_VRC4173)			+= vrc4173_cardu.o
 obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
 obj-$(CONFIG_AT91_CF)				+= at91_cf.o
+obj-$(CONFIG_ELECTRA_CF)			+= electra_cf.o
 
 sa11xx_core-y					+= soc_common.o sa11xx_base.o
 pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
drivers/pcmcia/electra_cf.c new file +382 -0

382 lines not on this page · raw message

arch/powerpc/platforms/pasemi/setup.c +1 -0
Index: powerpc/arch/powerpc/platforms/pasemi/setup.c
===================================================================
@@ -205,6 +205,7 @@ static void __init pas_init_early(void)
 }
 
 static struct of_device_id pasemi_bus_ids[] = {
+	{ .type = "localbus", },
 	{ .type = "sdc", },
 	{},
 };
#1 lore raw
Quoted 6 lines
drivers/pcmcia/electra_cf.c new file +6 -0
+static int bus_notify(struct notifier_block *nb, unsigned long action,
+		      void *data)
+{
+	struct device *dev = data;
+
+	printk("bus notify called\n");

drivers/pcmcia/electra_cf.c line 343

Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10 -0
+
+	/* We are only intereted in device addition */
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		return 0;
+
+	/* We use the direct ops for localbus */
+	dev->archdata.dma_ops = &dma_direct_ops;
+
+	return 0;
+}

Sorry for not coming back to you after the last posting of the patch, but I still really this bit of the code. We don't set dma ops from a driver anywhere else in the tree, so I'd really prefer if you could handle this in architecture code somewhere. Especially as dma_direct_ops and the pcmcia_bug_type shouldn't really be something exported to users.

Also this code is unlogic if not buggy. Just because you have one electra bridge it doesn't mean all pcmcia is driven by it. In fact I'm pretty sure there are cardbus/pcmcia bridges that can be plugged into plain pci slots.

#2 lore raw
Quoted 23 lines · Christoph Hellwig
Quoted 6 lines
drivers/pcmcia/electra_cf.c new file +6 -0
+static int bus_notify(struct notifier_block *nb, unsigned long action,
+		      void *data)
+{
+	struct device *dev = data;
+
+	printk("bus notify called\n");

drivers/pcmcia/electra_cf.c line 343

Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10 -0
+
+	/* We are only intereted in device addition */
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		return 0;
+
+	/* We use the direct ops for localbus */
+	dev->archdata.dma_ops = &dma_direct_ops;
+
+	return 0;
+}

Sorry for not coming back to you after the last posting of the patch, but I still really this bit of the code. We don't set dma ops from a driver anywhere else in the tree, so I'd really prefer if you could handle this in architecture code somewhere. Especially as dma_direct_ops and the pcmcia_bug_type shouldn't really be something exported to users.

Quoted 4 lines

Also this code is unlogic if not buggy. Just because you have one electra bridge it doesn't mean all pcmcia is driven by it. In fact I'm pretty sure there are cardbus/pcmcia bridges that can be plugged into plain pci slots.

Yeah, all good points. Also, I obviously missed to take out the debug printk. I'll post an updated patch separately.

Thanks!

-Olof

#3 lore raw

PATCH v2 1/1 pcmcia: CompactFlash driver for PA Semi Electra boards

In reply to Olof Johansson

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

---

Chances since last post:
* Comments from Christoph:
- Moved bus notifier to arch code
- Checking for bus (socket driver) type before changing dma ops

drivers/pcmcia/Kconfig +7 -0
Index: mainline/drivers/pcmcia/Kconfig
===================================================================
@@ -270,6 +270,13 @@ config AT91_CF
 	  Say Y here to support the CompactFlash controller on AT91 chips.
 	  Or choose M to compile the driver as a module named "at91_cf".
 
+config ELECTRA_CF
+	bool "Electra CompactFlash Controller"
+	depends on PCMCIA=y && PPC_PASEMI
+	help
+	  Say Y here to support the CompactFlash controller on the
+	  PA Semi Electra eval board.
+
 config PCCARD_NONSTATIC
 	tristate
 
drivers/pcmcia/Makefile +1 -0
Index: mainline/drivers/pcmcia/Makefile
===================================================================
@@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4171)			+= vrc417
 obj-$(CONFIG_PCMCIA_VRC4173)			+= vrc4173_cardu.o
 obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
 obj-$(CONFIG_AT91_CF)				+= at91_cf.o
+obj-$(CONFIG_ELECTRA_CF)			+= electra_cf.o
 
 sa11xx_core-y					+= soc_common.o sa11xx_base.o
 pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
drivers/pcmcia/electra_cf.c new file +359 -0

359 lines not on this page · raw message

arch/powerpc/platforms/pasemi/setup.c +42 -0

61 lines not on this page · raw message

#4 lore raw
Quoted 6 lines · Olof Johansson

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

Looks good to me. The only odd thing is the inconsistant use of #ifdef CONFIG_PCMCIA in setup.c.

#5 lore raw
Quoted 10 lines · Christoph Hellwig
Quoted 6 lines · Olof Johansson

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

Looks good to me. The only odd thing is the inconsistant use of #ifdef CONFIG_PCMCIA in setup.c.

Thanks, and thanks for the review.

The ifdef is needed since for CONFIG_PCMCIA=n builds, the bus notifier isn't available. I wanted to do the bus notifier registration explicitly before the of_platform bus probe to avoid later surprises due to reordered initcalls in case it was split up in it's own initcall.

I could add the code under ifdef as well, but it didn't seem too critical. Once the second major board comes along I'll probably move it out to a per-board file, there's no real need for it just yet.

-Olof

#6 lore raw

PATCH v3 1/1 pcmcia: CompactFlash driver for PA Semi Electra boards

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

---

Quoted 8 lines · olof

The ifdef is needed since for CONFIG_PCMCIA=n builds, the bus notifier isn't available. I wanted to do the bus notifier registration explicitly before the of_platform bus probe to avoid later surprises due to reordered initcalls in case it was split up in it's own initcall.

I could add the code under ifdef as well, but it didn't seem too critical. Once the second major board comes along I'll probably move it out to a per-board file, there's no real need for it just yet.

Alright, turns out I still need to declare the extern bus type, which would mean two #ifdefs in one function. Moving it out instead.

I've addressed Milton's comments as well.

Who's maintaining PCMCIA? MAINTAINERS only lists a mailing list, no person. Seems weird for a component that's marked as maintained.

drivers/pcmcia/Kconfig +7 -0
Index: mainline/drivers/pcmcia/Kconfig
===================================================================
@@ -270,6 +270,13 @@ config AT91_CF
 	  Say Y here to support the CompactFlash controller on AT91 chips.
 	  Or choose M to compile the driver as a module named "at91_cf".
 
+config ELECTRA_CF
+	bool "Electra CompactFlash Controller"
+	depends on PCMCIA=y && PPC_PASEMI
+	help
+	  Say Y here to support the CompactFlash controller on the
+	  PA Semi Electra eval board.
+
 config PCCARD_NONSTATIC
 	tristate
 
drivers/pcmcia/Makefile +1 -0
Index: mainline/drivers/pcmcia/Makefile
===================================================================
@@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4171)			+= vrc417
 obj-$(CONFIG_PCMCIA_VRC4173)			+= vrc4173_cardu.o
 obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
 obj-$(CONFIG_AT91_CF)				+= at91_cf.o
+obj-$(CONFIG_ELECTRA_CF)			+= electra_cf.o
 
 sa11xx_core-y					+= soc_common.o sa11xx_base.o
 pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
drivers/pcmcia/electra_cf.c new file +374 -0

374 lines not on this page · raw message

arch/powerpc/platforms/pasemi/setup.c +56 -0

75 lines not on this page · raw message

#7 lore raw
Quoted 23 lines · On Thu, 5 Jul 2007 09:49:14 -0500 [email protected] (Olof Johansson) wrote:

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

---

Quoted 8 lines · olof

The ifdef is needed since for CONFIG_PCMCIA=n builds, the bus notifier isn't available. I wanted to do the bus notifier registration explicitly before the of_platform bus probe to avoid later surprises due to reordered initcalls in case it was split up in it's own initcall.

I could add the code under ifdef as well, but it didn't seem too critical. Once the second major board comes along I'll probably move it out to a per-board file, there's no real need for it just yet.

Quoted 7 lines

Alright, turns out I still need to declare the extern bus type, which would mean two #ifdefs in one function. Moving it out instead.

I've addressed Milton's comments as well.

Who's maintaining PCMCIA? MAINTAINERS only lists a mailing list, no person. Seems weird for a component that's marked as maintained.

Dominik Brodowski. He's having a bit of downtime at present (exams, I think). He expects to return. Meanwhile, cc'ing me usually has some effect.

Quoted 4 lines

...

(quoted diff) +1 -0
+static const char driver_name[] = "electra-cf";

Review

Quoted 10 lines
(quoted diff) +7 -0
 
...
 
+static struct of_device_id electra_cf_match[] =
+{
+	{
+		.compatible   = "electra-cf",
+	},
+	{},
+};

Could have reused driver_name[] here, if that was appropriate.

Review

Quoted 3 lines
(quoted diff) +3 -0
+static struct of_platform_driver electra_cf_driver =
+{
+	.name	   = (char *)driver_name,

ug. But it's not your fault - we should have always made it const.

arch/powerpc/platforms/pasemi/setup.c

Quoted 2 lines
arch/powerpc/platforms/pasemi/setup.c +0 -0

I never know who maintains random-scruffy-ppc code like this. From a peek in the git-whatchanged output, it appears to be yourself.

Have a few little fixies:

drivers/pcmcia/electra_cf.c renamed from drivers/pcmcia/electra_cf.c~pcmcia-compactflash-driver-for-pa-semi-electra-boards-fix +3 -8
@@ -201,9 +201,7 @@ static int __devinit electra_cf_probe(st
 	if (!cf)
 		return -ENOMEM;
 
-	init_timer(&cf->timer);
-	cf->timer.function = electra_cf_timer;
-	cf->timer.data = (unsigned long) cf;
+	setup_timer(&cf->timer, electra_cf_timer, (unsigned long)cf);
 	cf->irq = NO_IRQ;
 
 	cf->ofdev = ofdev;
@@ -340,16 +338,14 @@ static int __devexit electra_cf_remove(s
 	return 0;
 }
 
-static struct of_device_id electra_cf_match[] =
-{
+static struct of_device_id electra_cf_match[] = {
 	{
 		.compatible   = "electra-cf",
 	},
 	{},
 };
 
-static struct of_platform_driver electra_cf_driver =
-{
+static struct of_platform_driver electra_cf_driver = {
 	.name	   = (char *)driver_name,
 	.match_table    = electra_cf_match,
 	.probe	  = electra_cf_probe,
@@ -371,4 +367,3 @@ module_exit(electra_cf_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR ("Olof Johansson <[email protected]>");
 MODULE_DESCRIPTION("PA Semi Electra CF driver");
-

_

author Acked-by
#8 lore raw
Quoted 6 lines · Andrew Morton
Quoted 2 lines

Who's maintaining PCMCIA? MAINTAINERS only lists a mailing list, no person. Seems weird for a component that's marked as maintained.

Dominik Brodowski. He's having a bit of downtime at present (exams, I think). He expects to return. Meanwhile, cc'ing me usually has some effect.

Thanks!

Quoted 4 lines
Quoted 4 lines

+static const char driver_name[] = "electra-cf";

...

Quoted 9 lines

Review

Quoted 7 lines
(quoted diff) +7 -0
+static struct of_device_id electra_cf_match[] =
+{
+	{
+		.compatible   = "electra-cf",
+	},
+	{},
+};

Could have reused driver_name[] here, if that was appropriate.

Driver name and device tree compatible field is not neccessarily the same, even though they do coincide here.

Quoted 5 lines

arch/powerpc/platforms/pasemi/setup.c

Quoted 2 lines
arch/powerpc/platforms/pasemi/setup.c +0 -0

I never know who maintains random-scruffy-ppc code like this. From a peek in the git-whatchanged output, it appears to be yourself.

Check the top of the file. :) (Kumar started doing that, I kept it up, seems useful). And yes, we do tend to have per-platform maintainers on ppc.

Quoted 1 line

Have a few little fixies:

Thanks!

Quoted 2 lines
drivers/pcmcia/electra_cf.c renamed from drivers/pcmcia/electra_cf.c~pcmcia-compactflash-driver-for-pa-semi-electra-boards-fix +0 -0

[...]

#9 lore raw

PATCH 1/1 pcmcia: Updates to electra_cf driver

In reply to Olof Johansson

Fix build of electra_cf, since the IO space setup interfaces were changed when BenH rewrote it.

Also clean it up a bit, add 5V support, make it unloadable, remove some dead variables, etc.

---

Andrew,

I did this as an incremental patch that you can just merge into the base one that's already in -mm, but I could merge and resubmit the base patch instead if you prefer.

(The base patch is pcmcia-compactflash-driver-for-pa-semi-electra-boards.patch)

-Olof

drivers/pcmcia/electra_cf.c +23 -15
Index: linux-2.6/drivers/pcmcia/electra_cf.c
===================================================================
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/vmalloc.h>
 
 #include <pcmcia/ss.h>
 #include <asm/of_platform.h>
@@ -105,10 +106,8 @@ static int electra_cf_get_status(struct 
 
 	/* NOTE CF is always 3VCARD */
 	if (electra_cf_present(cf)) {
-		struct electra_cf_socket *cf;
-
 		*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
-		cf = container_of(s, struct electra_cf_socket, socket);
+
 		s->pci_irq = cf->irq;
 	} else
 		*sp = 0;
@@ -134,8 +133,10 @@ static int electra_cf_set_socket(struct 
 	case 33:
 		gpio = (1 << cf->gpio_3v);
 		break;
+	case 5:
+		gpio = (1 << cf->gpio_5v);
+		break;
 	default:
-		/* CF is 3.3V only */
 		return -EINVAL;
 	}
 
@@ -188,6 +189,7 @@ static int __devinit electra_cf_probe(st
 	int status;
 	const unsigned int *prop;
 	int err;
+	struct vm_struct *area;
 
 	err = of_address_to_resource(np, 0, &mem);
 	if (err)
@@ -206,22 +208,27 @@ static int __devinit electra_cf_probe(st
 
 	cf->ofdev = ofdev;
 	cf->mem_phys = mem.start;
-	cf->mem_base = ioremap(mem.start, mem.end - mem.start);
+	cf->mem_size = PAGE_ALIGN(mem.end - mem.start);
+	cf->mem_base = ioremap(cf->mem_phys, cf->mem_size);
 	cf->io_size = PAGE_ALIGN(io.end - io.start);
 
-	cf->io_virt = reserve_phb_iospace(cf->io_size);
+	area = __get_vm_area(cf->io_size, 0, PHB_IO_BASE, PHB_IO_END);
+	if (area == NULL)
+		return -ENOMEM;
+
+	cf->io_virt = (void __iomem *)(area->addr);
 
 	cf->gpio_base = ioremap(0xfc103000, 0x1000);
 	dev_set_drvdata(device, cf);
 
-	if (!cf->mem_base || !cf->io_virt || !cf->gpio_base) {
+	if (!cf->mem_base || !cf->io_virt || !cf->gpio_base ||
+	    (__ioremap_at(io.start, cf->io_virt, cf->io_size,
+		_PAGE_NO_CACHE | _PAGE_GUARDED) == NULL)) {
 		dev_err(device, "can't ioremap ranges\n");
 		status = -ENOMEM;
 		goto fail1;
 	}
 
-	__ioremap_explicit(io.start, (unsigned long)cf->io_virt, cf->io_size,
-			   _PAGE_NO_CACHE | _PAGE_GUARDED);
 
 	cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END;
 
@@ -263,8 +270,7 @@ static int __devinit electra_cf_probe(st
 	cf->socket.io_offset = cf->io_base;
 
 	/* reserve chip-select regions */
-	if (!request_mem_region(mem.start, mem.end + 1 - mem.start,
-				driver_name)) {
+	if (!request_mem_region(cf->mem_phys, cf->mem_size, driver_name)) {
 		status = -ENXIO;
 		dev_err(device, "Can't claim memory region\n");
 		goto fail1;
@@ -291,21 +297,22 @@ static int __devinit electra_cf_probe(st
 	}
 
 	dev_info(device, "at mem 0x%lx io 0x%lx irq %d\n",
-		 mem.start, io.start, cf->irq);
+		 cf->mem_phys, io.start, cf->irq);
 
 	cf->active = 1;
 	electra_cf_timer((unsigned long)cf);
 	return 0;
 
 fail3:
-	release_mem_region(io.start, io.end + 1 - io.start);
+	release_region(cf->io_base, cf->io_size);
 fail2:
-	release_mem_region(mem.start, mem.end + 1 - mem.start);
+	release_mem_region(cf->mem_phys, cf->mem_size);
 fail1:
 	if (cf->irq != NO_IRQ)
 		free_irq(cf->irq, cf);
 
-	/* XXX No way to undo the ioremap_explicit at this time */
+	if (cf->io_virt)
+		__iounmap_at(cf->io_virt, cf->io_size);
 	if (cf->mem_base)
 		iounmap(cf->mem_base);
 	if (cf->gpio_base)
@@ -328,6 +335,7 @@ static int __devexit electra_cf_remove(s
 	free_irq(cf->irq, cf);
 	del_timer_sync(&cf->timer);
 
+	__iounmap_at(cf->io_virt, cf->io_size);
 	iounmap(cf->mem_base);
 	iounmap(cf->gpio_base);
 	release_mem_region(cf->mem_phys, cf->mem_size);
drivers/pcmcia/Kconfig +2 -2
Index: linux-2.6/drivers/pcmcia/Kconfig
===================================================================
@@ -272,8 +272,8 @@ config AT91_CF
 	  Or choose M to compile the driver as a module named "at91_cf".
 
 config ELECTRA_CF
-	bool "Electra CompactFlash Controller"
-	depends on PCMCIA=y && PPC_PASEMI
+	tristate "Electra CompactFlash Controller"
+	depends on PCMCIA && PPC_PASEMI
 	help
 	  Say Y here to support the CompactFlash controller on the
 	  PA Semi Electra eval board.
#10 lore raw
In reply to Olof Johansson
Quoted 9 lines · Christoph Hellwig
Quoted 8 lines · Olof Johansson
Quoted 6 lines

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

Quoted 7 lines
Quoted 2 lines

Looks good to me. The only odd thing is the inconsistant use of #ifdef CONFIG_PCMCIA in setup.c.

The ifdef is needed since for CONFIG_PCMCIA=n builds, the bus notifier isn't available. I wanted to do the bus notifier registration explicitly before the of_platform bus probe to avoid later surprises due to reordered initcalls in case it was split up in it's own initcall.

If CONFIG_PCMCIA=m then your notifier is not registered. The modprobe of your of_driver loads ds.ko, registers the bus, then registers your driver. When the socket driver tries to dma, the BUG in dma_64 for no archdata.dma_ops triggers.

It seems like we need

(1) a notifier that a bus is registered, run before allowing any devices, so that platforms can register bus notifiers by bus name before the devices and drivers are registered.

(2) a powerpc64 generic pcmcia bus notifier that copys the dma ops from the parent socket.

(3) something to set the dma_ops to direct_dma_ops on the of device.

If we don't want (3) to be in the driver (as Christoph previosly mentioned), then it needs to be a seperate bus that reuses the of matching. This would be similar to how ibmebus is setup. If I remember the discussion, ibmebus is to provide the alternate dma ops and steals match etc code from the of_platform bus type.

Oh, is this why you have depends on PCMCIA=y ?

Quoted 3 lines

I could add the code under ifdef as well, but it didn't seem too critical. Once the second major board comes along I'll probably move it out to a per-board file, there's no real need for it just yet.

milton

#11 lore raw
Quoted 16 lines · Milton Miller

If CONFIG_PCMCIA=m then your notifier is not registered. The modprobe of your of_driver loads ds.ko, registers the bus, then registers your driver. When the socket driver tries to dma, the BUG in dma_64 for no archdata.dma_ops triggers.

It seems like we need

(1) a notifier that a bus is registered, run before allowing any devices, so that platforms can register bus notifiers by bus name before the devices and drivers are registered.

(2) a powerpc64 generic pcmcia bus notifier that copys the dma ops from the parent socket.

(3) something to set the dma_ops to direct_dma_ops on the of device.

Quoted 8 lines

If we don't want (3) to be in the driver (as Christoph previosly mentioned), then it needs to be a seperate bus that reuses the of
matching. This would be similar to how ibmebus is setup. If I
remember the discussion, ibmebus is to provide the alternate dma ops and steals match etc code from the of_platform bus type.

Oh, is this why you have depends on PCMCIA=y ?

Yes.

-Olof

#12 lore raw
In reply to Olof Johansson

Hi Olof.

Quoted 6 lines · Olof Johansson

Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.

The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.

...

Quoted 65 lines
drivers/pcmcia/electra_cf.c new file +45 -0
+
+static int __devinit electra_cf_probe(struct of_device *ofdev,
+                                     const struct of_device_id *match)
+{
+       struct device *device = &ofdev->dev;
+       struct device_node *np = ofdev->node;
+       struct electra_cf_socket   *cf;
+       struct resource mem, io;
+       int status;
+       const unsigned int *prop;
+       int err;
+
+       err = of_address_to_resource(np, 0, &mem);
+       if (err)
+               return -EINVAL;
+
+       err = of_address_to_resource(np, 1, &io);
+       if (err)
+               return -EINVAL;
+
+       cf = kzalloc(sizeof *cf, GFP_KERNEL);
+       if (!cf)
+               return -ENOMEM;
+
+       init_timer(&cf->timer);
+       cf->timer.function = electra_cf_timer;
+       cf->timer.data = (unsigned long) cf;
+
+       cf->ofdev = ofdev;
+       cf->mem_phys = mem.start;
+       cf->mem_base = ioremap(mem.start, mem.end - mem.start);
+       cf->io_size = PAGE_ALIGN(io.end - io.start);
+
+       cf->io_virt = reserve_phb_iospace(cf->io_size);
+
+       cf->gpio_base = ioremap(0xfc103000, 0x1000);
+       dev_set_drvdata(device, cf);
+
+       if (!cf->mem_base || !cf->io_virt || !cf->gpio_base) {
+               dev_err(device, "can't ioremap ranges\n");
+               status = -ENOMEM;
+               goto fail1;
+       }
+
+       __ioremap_explicit(io.start, (unsigned long)cf->io_virt, 

cf->io_size,

drivers/pcmcia/electra_cf.c new file +6 -0
+                          _PAGE_NO_CACHE | _PAGE_GUARDED);
+
+       cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END;
+
+       cf->iomem.start = (unsigned long)cf->mem_base;
+       cf->iomem.end = (unsigned long)cf->mem_base + (mem.end - 

mem.start);

drivers/pcmcia/electra_cf.c new file +12 -0
+       cf->iomem.flags = IORESOURCE_MEM;
+
+       cf->irq = irq_of_parse_and_map(np, 0);
+
+       status = request_irq(cf->irq, electra_cf_irq, IRQF_SHARED,
+                            driver_name, cf);
+       if (status < 0) {
+               dev_err(device, "request_irq failed\n");
+               goto fail1;
+       }
+
+       cf->socket.pci_irq = cf->irq;

drivers/pcmcia/electra_cf.c line 252

Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10 -0
+
+       prop = get_property(np, "card-detect-gpio", NULL);
+       cf->gpio_detect = *prop;
+       prop = get_property(np, "card-vsense-gpio", NULL);
+       cf->gpio_vsense = *prop;
+       prop = get_property(np, "card-3v-gpio", NULL);
+       cf->gpio_3v = *prop;
+       prop = get_property(np, "card-5v-gpio", NULL);
+       cf->gpio_5v = *prop;
+

get_property is now a #define for of_get_property. I think the use of get_property is being deprecated.

If of_get_property fails to find the property, then you will dereference a NULL pointer in a probe function and will leave the bus_type locked.

Quoted 33 lines
drivers/pcmcia/electra_cf.c new file +33 -0
+       cf->socket.io_offset = cf->io_base;
+
+       /* reserve chip-select regions */
+       if (!request_mem_region(mem.start, mem.end + 1 - mem.start,
+                               driver_name)) {
+               status = -ENXIO;
+               dev_err(device, "Can't claim memory region\n");
+               goto fail1;
+       }
+
+       if (!request_region(cf->io_base, cf->io_size, driver_name)) {
+               status = -ENXIO;
+               dev_err(device, "Can't claim I/O region\n");
+               goto fail2;
+       }
+
+       cf->socket.owner = THIS_MODULE;
+       cf->socket.dev.parent = &ofdev->dev;
+       cf->socket.ops = &electra_cf_ops;
+       cf->socket.resource_ops = &pccard_static_ops;
+       cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP |
+                               SS_CAP_MEM_ALIGN;
+       cf->socket.map_size = 0x800;
+
+       status = pcmcia_register_socket(&cf->socket);
+       if (status < 0) {
+               dev_err(device, "pcmcia_register_socket failed\n");
+               goto fail3;
+       }
+
+       dev_info(device, "at mem 0x%lx io 0x%lx irq %d\n",
+                mem.start, io.start, cf->irq);
+

drivers/pcmcia/electra_cf.c line 295

Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10 -0
+       cf->active = 1;
+       electra_cf_timer((unsigned long)cf);
+       return 0;
+
+fail3:
+       release_mem_region(io.start, io.end + 1 - io.start);
+fail2:
+       release_mem_region(mem.start, mem.end + 1 - mem.start);
+fail1:
+       /* XXX No way to undo the io reservation at this time */

What io reservation is this comment referring to?

Where is the request_irq undone?

Quoted 18 lines
drivers/pcmcia/electra_cf.c new file +17 -0
+       if (cf->mem_base)
+               iounmap(cf->mem_base);
+       if (cf->gpio_base)
+               iounmap(cf->gpio_base);
+       device_init_wakeup(&ofdev->dev, 0);
+       kfree(cf);
+       return status;
+
+}
+
+static int __devexit electra_cf_remove(struct of_device *ofdev)
+{
+       struct device *device = &ofdev->dev;
+       struct electra_cf_socket *cf;
+
+       cf = dev_get_drvdata(device);
+

drivers/pcmcia/electra_cf.c line 322

Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10 -0
+       cf->active = 0;
+       pcmcia_unregister_socket(&cf->socket);
+       free_irq(cf->irq, cf);
+       del_timer_sync(&cf->timer);
+
+       iounmap(cf->mem_base);
+       iounmap(cf->gpio_base);
+       release_mem_region(cf->mem_phys, cf->mem_size);
+       release_region(cf->io_base, cf->io_size);
+

irq_request?

Quoted 9 lines
drivers/pcmcia/electra_cf.c new file +9 -0
+       kfree(cf);
+
+       return 0;
+}
+
+static int bus_notify(struct notifier_block *nb, unsigned long action,
+                     void *data)
+{
+       struct device *dev = data;

drivers/pcmcia/electra_cf.c line 341

Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10 -0
+
+       printk("bus notify called\n");
+
+       /* We are only intereted in device addition */
+       if (action != BUS_NOTIFY_ADD_DEVICE)
+               return 0;
+
+       /* We use the direct ops for localbus */
+       dev->archdata.dma_ops = &dma_direct_ops;
+

I'm also replying to your reply to hch's reply. Is that enough of a reply? :-)

Quoted 24 lines
drivers/pcmcia/electra_cf.c new file +24 -0
+       return 0;
+}
+
+static struct notifier_block bus_notifier = {
+       .notifier_call = bus_notify,
+};
+
+static struct of_device_id electra_cf_match[] =
+{
+       {
+               .compatible   = "electra-cf",
+       },
+       {},
+};
+
+static struct of_platform_driver electra_cf_driver =
+{
+       .name      = (char *)driver_name,
+       .match_table    = electra_cf_match,
+       .probe    = electra_cf_probe,
+       .remove   = electra_cf_remove,
+};
+
+static int __init electra_cf_init(void)

drivers/pcmcia/electra_cf.c line 375

Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10 -0
+{
+       bus_register_notifier(&pcmcia_bus_type, &bus_notifier);
+       return of_register_platform_driver(&electra_cf_driver);
+}
+module_init(electra_cf_init);
+
+static void __exit electra_cf_exit(void)
+{
+       bus_unregister_notifier(&pcmcia_bus_type, &bus_notifier);
+       of_unregister_platform_driver(&electra_cf_driver);

Should these be reversed? (if we keep it here)

drivers/pcmcia/electra_cf.c line 382

Quoted 7 lines
drivers/pcmcia/electra_cf.c new file +7 -0
+}
+module_exit(electra_cf_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof at lixom.net>");
+MODULE_DESCRIPTION("PA Semi Electra CF driver");
+

cheers,
milton

#13 lore raw
Quoted 2 lines · Milton Miller

get_property is now a #define for of_get_property. I think the use of get_property is being deprecated.

Yeah, it's a pita. I've moved these over now.

Quoted 3 lines

If of_get_property fails to find the property, then you will dereference a NULL pointer in a probe function and will leave the bus_type locked.

Fixed.

Quoted 3 lines
Quoted 1 line

+ /* XXX No way to undo the io reservation at this time */

What io reservation is this comment referring to?

ioremap_explicit. I've updated the comment.

Quoted 1 line

Where is the request_irq undone?

Fixed.

Quoted 12 lines
Quoted 12 lines
drivers/pcmcia/electra_cf.c new file +12 -0
+static int __devexit electra_cf_remove(struct of_device *ofdev)
+{
+       struct device *device = &ofdev->dev;
+       struct electra_cf_socket *cf;
+
+       cf = dev_get_drvdata(device);
+
+       cf->active = 0;
+       pcmcia_unregister_socket(&cf->socket);
+       free_irq(cf->irq, cf);
+       del_timer_sync(&cf->timer);
+
Quoted 8 lines

drivers/pcmcia/electra_cf.c line 322

Quoted 6 lines
drivers/pcmcia/electra_cf.c new file +5 -0
+       iounmap(cf->mem_base);
+       iounmap(cf->gpio_base);
+       release_mem_region(cf->mem_phys, cf->mem_size);
+       release_region(cf->io_base, cf->io_size);
+

irq_request?

Huh?

-Olof