aboutsummaryrefslogtreecommitdiff
path: root/drivers/pcmcia/at91_cf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia/at91_cf.c')
-rw-r--r--drivers/pcmcia/at91_cf.c291
1 files changed, 145 insertions, 146 deletions
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 40569f40e90..de24232c519 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -11,36 +11,37 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/atmel.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <pcmcia/ss.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/sizes.h>
-
-#include <asm/arch/at91rm9200.h>
-#include <asm/arch/board.h>
-#include <asm/arch/gpio.h>
+#include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
/*
* A0..A10 work in each range; A23 indicates I/O space; A25 is CFRNW;
* some other bit in {A24,A22..A11} is nREG to flag memory access
* (vs attributes). So more than 2KB/region would just be waste.
+ * Note: These are offsets from the physical base address.
*/
-#define CF_ATTR_PHYS (AT91_CF_BASE)
-#define CF_IO_PHYS (AT91_CF_BASE + (1 << 23))
-#define CF_MEM_PHYS (AT91_CF_BASE + 0x017ff800)
+#define CF_ATTR_PHYS (0)
+#define CF_IO_PHYS (1 << 23)
+#define CF_MEM_PHYS (0x017ff800)
/*--------------------------------------------------------------------------*/
-static const char driver_name[] = "at91_cf";
-
struct at91_cf_socket {
struct pcmcia_socket socket;
@@ -48,13 +49,13 @@ struct at91_cf_socket {
struct platform_device *pdev;
struct at91_cf_data *board;
-};
-#define SZ_2K (2 * SZ_1K)
+ unsigned long phys_baseaddr;
+};
static inline int at91_cf_present(struct at91_cf_socket *cf)
{
- return !at91_get_gpio_value(cf->board->det_pin);
+ return !gpio_get_value(cf->board->det_pin);
}
/*--------------------------------------------------------------------------*/
@@ -64,17 +65,17 @@ static int at91_cf_ss_init(struct pcmcia_socket *s)
return 0;
}
-static irqreturn_t at91_cf_irq(int irq, void *_cf, struct pt_regs *r)
+static irqreturn_t at91_cf_irq(int irq, void *_cf)
{
- struct at91_cf_socket *cf = (struct at91_cf_socket *) _cf;
+ struct at91_cf_socket *cf = _cf;
- if (irq == cf->board->det_pin) {
+ if (irq == gpio_to_irq(cf->board->det_pin)) {
unsigned present = at91_cf_present(cf);
/* kick pccard as needed */
if (present != cf->present) {
cf->present = present;
- pr_debug("%s: card %s\n", driver_name,
+ dev_dbg(&cf->pdev->dev, "card %s\n",
present ? "present" : "gone");
pcmcia_parse_events(&cf->socket, SS_DETECT);
}
@@ -94,13 +95,13 @@ static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp)
/* NOTE: CF is always 3VCARD */
if (at91_cf_present(cf)) {
- int rdy = cf->board->irq_pin; /* RDY/nIRQ */
- int vcc = cf->board->vcc_pin;
+ int rdy = gpio_is_valid(cf->board->irq_pin); /* RDY/nIRQ */
+ int vcc = gpio_is_valid(cf->board->vcc_pin);
*sp = SS_DETECT | SS_3VCARD;
- if (!rdy || at91_get_gpio_value(rdy))
+ if (!rdy || gpio_get_value(cf->board->irq_pin))
*sp |= SS_READY;
- if (!vcc || at91_get_gpio_value(vcc))
+ if (!vcc || gpio_get_value(cf->board->vcc_pin))
*sp |= SS_POWERON;
} else
*sp = 0;
@@ -116,24 +117,24 @@ at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
cf = container_of(sock, struct at91_cf_socket, socket);
/* switch Vcc if needed and possible */
- if (cf->board->vcc_pin) {
+ if (gpio_is_valid(cf->board->vcc_pin)) {
switch (s->Vcc) {
- case 0:
- at91_set_gpio_value(cf->board->vcc_pin, 0);
- break;
- case 33:
- at91_set_gpio_value(cf->board->vcc_pin, 1);
- break;
- default:
- return -EINVAL;
+ case 0:
+ gpio_set_value(cf->board->vcc_pin, 0);
+ break;
+ case 33:
+ gpio_set_value(cf->board->vcc_pin, 1);
+ break;
+ default:
+ return -EINVAL;
}
}
/* toggle reset if needed */
- at91_set_gpio_value(cf->board->rst_pin, s->flags & SS_RESET);
+ gpio_set_value(cf->board->rst_pin, s->flags & SS_RESET);
- pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
- driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
+ dev_dbg(&cf->pdev->dev, "Vcc %d, io_irq %d, flags %04x csc %04x\n",
+ s->Vcc, s->io_irq, s->flags, s->csc_mask);
return 0;
}
@@ -154,9 +155,8 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
/*
* Use 16 bit accesses unless/until we need 8-bit i/o space.
- * Always set CSR4 ... PCMCIA won't always unmap things.
*/
- csr = at91_sys_read(AT91_SMC_CSR(4)) & ~AT91_SMC_DBW;
+ csr = at91_ramc_read(0, AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW;
/*
* NOTE: this CF controller ignores IOIS16, so we can't really do
@@ -168,14 +168,14 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
* some cards only like that way to get at the odd byte, despite
* CF 3.0 spec table 35 also giving the D8-D15 option.
*/
- if (!(io->flags & (MAP_16BIT|MAP_AUTOSZ))) {
+ if (!(io->flags & (MAP_16BIT | MAP_AUTOSZ))) {
csr |= AT91_SMC_DBW_8;
- pr_debug("%s: 8bit i/o bus\n", driver_name);
+ dev_dbg(&cf->pdev->dev, "8bit i/o bus\n");
} else {
csr |= AT91_SMC_DBW_16;
- pr_debug("%s: 16bit i/o bus\n", driver_name);
+ dev_dbg(&cf->pdev->dev, "16bit i/o bus\n");
}
- at91_sys_write(AT91_SMC_CSR(4), csr);
+ at91_ramc_write(0, AT91_SMC_CSR(cf->board->chipselect), csr);
io->start = cf->socket.io_offset;
io->stop = io->start + SZ_2K - 1;
@@ -194,11 +194,11 @@ at91_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
cf = container_of(s, struct at91_cf_socket, socket);
- map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
+ map->flags &= (MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT);
if (map->flags & MAP_ATTRIB)
- map->static_start = CF_ATTR_PHYS;
+ map->static_start = cf->phys_baseaddr + CF_ATTR_PHYS;
else
- map->static_start = CF_MEM_PHYS;
+ map->static_start = cf->phys_baseaddr + CF_MEM_PHYS;
return 0;
}
@@ -214,63 +214,89 @@ static struct pccard_operations at91_cf_ops = {
/*--------------------------------------------------------------------------*/
-static int __init at91_cf_probe(struct platform_device *pdev)
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_cf_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-cf" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, at91_cf_dt_ids);
+
+static int at91_cf_dt_init(struct platform_device *pdev)
+{
+ struct at91_cf_data *board;
+
+ board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
+ if (!board)
+ return -ENOMEM;
+
+ board->irq_pin = of_get_gpio(pdev->dev.of_node, 0);
+ board->det_pin = of_get_gpio(pdev->dev.of_node, 1);
+ board->vcc_pin = of_get_gpio(pdev->dev.of_node, 2);
+ board->rst_pin = of_get_gpio(pdev->dev.of_node, 3);
+
+ pdev->dev.platform_data = board;
+
+ return 0;
+}
+#else
+static int at91_cf_dt_init(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif
+
+static int at91_cf_probe(struct platform_device *pdev)
{
struct at91_cf_socket *cf;
struct at91_cf_data *board = pdev->dev.platform_data;
struct resource *io;
- unsigned int csa;
int status;
- if (!board || !board->det_pin || !board->rst_pin)
+ if (!board) {
+ status = at91_cf_dt_init(pdev);
+ if (status)
+ return status;
+
+ board = pdev->dev.platform_data;
+ }
+
+ if (!gpio_is_valid(board->det_pin) || !gpio_is_valid(board->rst_pin))
return -ENODEV;
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!io)
return -ENODEV;
- cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
+ cf = devm_kzalloc(&pdev->dev, sizeof(*cf), GFP_KERNEL);
if (!cf)
return -ENOMEM;
cf->board = board;
cf->pdev = pdev;
+ cf->phys_baseaddr = io->start;
platform_set_drvdata(pdev, cf);
- /* CF takes over CS4, CS5, CS6 */
- csa = at91_sys_read(AT91_EBI_CSA);
- at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
-
- /* force poweron defaults for these pins ... */
- (void) at91_set_A_periph(AT91_PIN_PC9, 0); /* A25/CFRNW */
- (void) at91_set_A_periph(AT91_PIN_PC10, 0); /* NCS4/CFCS */
- (void) at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS5/CFCE1 */
- (void) at91_set_A_periph(AT91_PIN_PC12, 0); /* NCS6/CFCE2 */
+ /* must be a GPIO; ergo must trigger on both edges */
+ status = devm_gpio_request(&pdev->dev, board->det_pin, "cf_det");
+ if (status < 0)
+ return status;
- /* nWAIT is _not_ a default setting */
- (void) at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */
+ status = devm_request_irq(&pdev->dev, gpio_to_irq(board->det_pin),
+ at91_cf_irq, 0, "at91_cf detect", cf);
+ if (status < 0)
+ return status;
- /*
- * Static memory controller timing adjustments.
- * REVISIT: these timings are in terms of MCK cycles, so
- * when MCK changes (cpufreq etc) so must these values...
- */
- at91_sys_write(AT91_SMC_CSR(4),
- AT91_SMC_ACSS_STD
- | AT91_SMC_DBW_16
- | AT91_SMC_BAT
- | AT91_SMC_WSEN
- | AT91_SMC_NWS_(32) /* wait states */
- | AT91_SMC_RWSETUP_(6) /* setup time */
- | AT91_SMC_RWHOLD_(4) /* hold time */
- );
+ device_init_wakeup(&pdev->dev, 1);
- /* must be a GPIO; ergo must trigger on both edges */
- status = request_irq(board->det_pin, at91_cf_irq,
- IRQF_SAMPLE_RANDOM, driver_name, cf);
+ status = devm_gpio_request(&pdev->dev, board->rst_pin, "cf_rst");
if (status < 0)
- goto fail0;
- device_init_wakeup(&pdev->dev, 1);
+ goto fail0a;
+
+ if (gpio_is_valid(board->vcc_pin)) {
+ status = devm_gpio_request(&pdev->dev, board->vcc_pin, "cf_vcc");
+ if (status < 0)
+ goto fail0a;
+ }
/*
* The card driver will request this irq later as needed.
@@ -278,30 +304,38 @@ static int __init at91_cf_probe(struct platform_device *pdev)
* unless we report that we handle everything (sigh).
* (Note: DK board doesn't wire the IRQ pin...)
*/
- if (board->irq_pin) {
- status = request_irq(board->irq_pin, at91_cf_irq,
- IRQF_SHARED, driver_name, cf);
+ if (gpio_is_valid(board->irq_pin)) {
+ status = devm_gpio_request(&pdev->dev, board->irq_pin, "cf_irq");
+ if (status < 0)
+ goto fail0a;
+
+ status = devm_request_irq(&pdev->dev, gpio_to_irq(board->irq_pin),
+ at91_cf_irq, IRQF_SHARED, "at91_cf", cf);
if (status < 0)
goto fail0a;
- cf->socket.pci_irq = board->irq_pin;
+ cf->socket.pci_irq = gpio_to_irq(board->irq_pin);
} else
- cf->socket.pci_irq = NR_IRQS + 1;
+ cf->socket.pci_irq = nr_irqs + 1;
/* pcmcia layer only remaps "real" memory not iospace */
- cf->socket.io_offset = (unsigned long) ioremap(CF_IO_PHYS, SZ_2K);
- if (!cf->socket.io_offset)
- goto fail1;
+ cf->socket.io_offset = (unsigned long) devm_ioremap(&pdev->dev,
+ cf->phys_baseaddr + CF_IO_PHYS, SZ_2K);
+ if (!cf->socket.io_offset) {
+ status = -ENXIO;
+ goto fail0a;
+ }
- /* reserve CS4, CS5, and CS6 regions; but use just CS4 */
- if (!request_mem_region(io->start, io->end + 1 - io->start,
- driver_name))
- goto fail1;
+ /* reserve chip-select regions */
+ if (!devm_request_mem_region(&pdev->dev, io->start, resource_size(io), "at91_cf")) {
+ status = -ENXIO;
+ goto fail0a;
+ }
- pr_info("%s: irqs det #%d, io #%d\n", driver_name,
- board->det_pin, board->irq_pin);
+ dev_info(&pdev->dev, "irqs det #%d, io #%d\n",
+ gpio_to_irq(board->det_pin), gpio_to_irq(board->irq_pin));
cf->socket.owner = THIS_MODULE;
- cf->socket.dev.dev = &pdev->dev;
+ cf->socket.dev.parent = &pdev->dev;
cf->socket.ops = &at91_cf_ops;
cf->socket.resource_ops = &pccard_static_ops;
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
@@ -311,44 +345,22 @@ static int __init at91_cf_probe(struct platform_device *pdev)
status = pcmcia_register_socket(&cf->socket);
if (status < 0)
- goto fail2;
+ goto fail0a;
return 0;
-fail2:
- iounmap((void __iomem *) cf->socket.io_offset);
- release_mem_region(io->start, io->end + 1 - io->start);
-fail1:
- if (board->irq_pin)
- free_irq(board->irq_pin, cf);
fail0a:
- free_irq(board->det_pin, cf);
device_init_wakeup(&pdev->dev, 0);
-fail0:
- at91_sys_write(AT91_EBI_CSA, csa);
- kfree(cf);
return status;
}
-static int __exit at91_cf_remove(struct platform_device *pdev)
+static int at91_cf_remove(struct platform_device *pdev)
{
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
- struct at91_cf_data *board = cf->board;
- struct resource *io = cf->socket.io[0].res;
- unsigned int csa;
pcmcia_unregister_socket(&cf->socket);
- if (board->irq_pin)
- free_irq(board->irq_pin, cf);
- free_irq(board->det_pin, cf);
device_init_wakeup(&pdev->dev, 0);
- iounmap((void __iomem *) cf->socket.io_offset);
- release_mem_region(io->start, io->end + 1 - io->start);
-
- csa = at91_sys_read(AT91_EBI_CSA);
- at91_sys_write(AT91_EBI_CSA, csa & ~AT91_EBI_CS4A);
- kfree(cf);
return 0;
}
@@ -359,15 +371,11 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
struct at91_cf_data *board = cf->board;
- pcmcia_socket_dev_suspend(&pdev->dev, mesg);
- if (device_may_wakeup(&pdev->dev))
- enable_irq_wake(board->det_pin);
- else {
- disable_irq_wake(board->det_pin);
- disable_irq(board->det_pin);
+ if (device_may_wakeup(&pdev->dev)) {
+ enable_irq_wake(gpio_to_irq(board->det_pin));
+ if (gpio_is_valid(board->irq_pin))
+ enable_irq_wake(gpio_to_irq(board->irq_pin));
}
- if (board->irq_pin)
- disable_irq(board->irq_pin);
return 0;
}
@@ -376,11 +384,12 @@ static int at91_cf_resume(struct platform_device *pdev)
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
struct at91_cf_data *board = cf->board;
- if (board->irq_pin)
- enable_irq(board->irq_pin);
- if (!device_may_wakeup(&pdev->dev))
- enable_irq(board->det_pin);
- pcmcia_socket_dev_resume(&pdev->dev);
+ if (device_may_wakeup(&pdev->dev)) {
+ disable_irq_wake(gpio_to_irq(board->det_pin));
+ if (gpio_is_valid(board->irq_pin))
+ disable_irq_wake(gpio_to_irq(board->irq_pin));
+ }
+
return 0;
}
@@ -391,29 +400,19 @@ static int at91_cf_resume(struct platform_device *pdev)
static struct platform_driver at91_cf_driver = {
.driver = {
- .name = (char *) driver_name,
+ .name = "at91_cf",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_cf_dt_ids),
},
.probe = at91_cf_probe,
- .remove = __exit_p(at91_cf_remove),
+ .remove = at91_cf_remove,
.suspend = at91_cf_suspend,
.resume = at91_cf_resume,
};
-/*--------------------------------------------------------------------------*/
-
-static int __init at91_cf_init(void)
-{
- return platform_driver_register(&at91_cf_driver);
-}
-module_init(at91_cf_init);
-
-static void __exit at91_cf_exit(void)
-{
- platform_driver_unregister(&at91_cf_driver);
-}
-module_exit(at91_cf_exit);
+module_platform_driver(at91_cf_driver);
MODULE_DESCRIPTION("AT91 Compact Flash Driver");
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_cf");