]>
Commit | Line | Data |
---|---|---|
2a0a288e DN |
1 | /* |
2 | * NAND Flash Controller Device Driver | |
3 | * Copyright © 2009-2010, Intel Corporation and its suppliers. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | */ | |
da4734be MY |
14 | |
15 | #include <linux/errno.h> | |
16 | #include <linux/io.h> | |
2a0a288e DN |
17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> | |
19 | #include <linux/pci.h> | |
2a0a288e DN |
20 | |
21 | #include "denali.h" | |
22 | ||
23 | #define DENALI_NAND_NAME "denali-nand-pci" | |
24 | ||
1bb88666 MY |
25 | #define INTEL_CE4100 1 |
26 | #define INTEL_MRST 2 | |
27 | ||
2a0a288e | 28 | /* List of platforms this NAND controller has be integrated into */ |
94f7039a | 29 | static const struct pci_device_id denali_pci_ids[] = { |
2a0a288e DN |
30 | { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, |
31 | { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, | |
32 | { /* end: all zeroes */ } | |
33 | }; | |
34 | MODULE_DEVICE_TABLE(pci, denali_pci_ids); | |
35 | ||
7de117fd MY |
36 | NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15); |
37 | ||
2a0a288e DN |
38 | static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) |
39 | { | |
add243d5 | 40 | int ret; |
2a0a288e DN |
41 | resource_size_t csr_base, mem_base; |
42 | unsigned long csr_len, mem_len; | |
43 | struct denali_nand_info *denali; | |
44 | ||
add243d5 | 45 | denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL); |
2a0a288e DN |
46 | if (!denali) |
47 | return -ENOMEM; | |
48 | ||
add243d5 | 49 | ret = pcim_enable_device(dev); |
2a0a288e | 50 | if (ret) { |
af83a67c | 51 | dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n"); |
add243d5 | 52 | return ret; |
2a0a288e DN |
53 | } |
54 | ||
55 | if (id->driver_data == INTEL_CE4100) { | |
2a0a288e DN |
56 | mem_base = pci_resource_start(dev, 0); |
57 | mem_len = pci_resource_len(dev, 1); | |
58 | csr_base = pci_resource_start(dev, 1); | |
59 | csr_len = pci_resource_len(dev, 1); | |
60 | } else { | |
2a0a288e DN |
61 | csr_base = pci_resource_start(dev, 0); |
62 | csr_len = pci_resource_len(dev, 0); | |
63 | mem_base = pci_resource_start(dev, 1); | |
64 | mem_len = pci_resource_len(dev, 1); | |
65 | if (!mem_len) { | |
66 | mem_base = csr_base + csr_len; | |
67 | mem_len = csr_len; | |
68 | } | |
69 | } | |
70 | ||
71 | pci_set_master(dev); | |
72 | denali->dev = &dev->dev; | |
73 | denali->irq = dev->irq; | |
7de117fd MY |
74 | denali->ecc_caps = &denali_pci_ecc_caps; |
75 | denali->nand.ecc.options |= NAND_ECC_MAXIMIZE; | |
1bb88666 | 76 | denali->clk_x_rate = 200000000; /* 200 MHz */ |
2a0a288e DN |
77 | |
78 | ret = pci_request_regions(dev, DENALI_NAND_NAME); | |
79 | if (ret) { | |
af83a67c | 80 | dev_err(&dev->dev, "Spectra: Unable to request memory regions\n"); |
add243d5 | 81 | return ret; |
2a0a288e DN |
82 | } |
83 | ||
0d3a966d MY |
84 | denali->reg = ioremap_nocache(csr_base, csr_len); |
85 | if (!denali->reg) { | |
af83a67c | 86 | dev_err(&dev->dev, "Spectra: Unable to remap memory region\n"); |
add243d5 | 87 | return -ENOMEM; |
2a0a288e DN |
88 | } |
89 | ||
0d3a966d MY |
90 | denali->host = ioremap_nocache(mem_base, mem_len); |
91 | if (!denali->host) { | |
af83a67c | 92 | dev_err(&dev->dev, "Spectra: ioremap_nocache failed!"); |
2a0a288e DN |
93 | ret = -ENOMEM; |
94 | goto failed_remap_reg; | |
95 | } | |
96 | ||
97 | ret = denali_init(denali); | |
98 | if (ret) | |
99 | goto failed_remap_mem; | |
100 | ||
101 | pci_set_drvdata(dev, denali); | |
102 | ||
103 | return 0; | |
104 | ||
105 | failed_remap_mem: | |
0d3a966d | 106 | iounmap(denali->host); |
2a0a288e | 107 | failed_remap_reg: |
0d3a966d | 108 | iounmap(denali->reg); |
2a0a288e DN |
109 | return ret; |
110 | } | |
111 | ||
112 | /* driver exit point */ | |
113 | static void denali_pci_remove(struct pci_dev *dev) | |
114 | { | |
115 | struct denali_nand_info *denali = pci_get_drvdata(dev); | |
116 | ||
117 | denali_remove(denali); | |
0d3a966d MY |
118 | iounmap(denali->reg); |
119 | iounmap(denali->host); | |
2a0a288e DN |
120 | } |
121 | ||
122 | static struct pci_driver denali_pci_driver = { | |
123 | .name = DENALI_NAND_NAME, | |
124 | .id_table = denali_pci_ids, | |
125 | .probe = denali_pci_probe, | |
126 | .remove = denali_pci_remove, | |
127 | }; | |
128 | ||
2445d33d | 129 | module_pci_driver(denali_pci_driver); |