diff options
Diffstat (limited to 'arch/arm/mach-u300')
-rw-r--r-- | arch/arm/mach-u300/mmc.c | 148 |
1 files changed, 13 insertions, 135 deletions
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c index de1ac9ad2213..8bb4ef42ab04 100644 --- a/arch/arm/mach-u300/mmc.c +++ b/arch/arm/mach-u300/mmc.c | |||
@@ -13,11 +13,6 @@ | |||
13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
14 | #include <linux/amba/bus.h> | 14 | #include <linux/amba/bus.h> |
15 | #include <linux/mmc/host.h> | 15 | #include <linux/mmc/host.h> |
16 | #include <linux/input.h> | ||
17 | #include <linux/workqueue.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/regulator/consumer.h> | ||
20 | #include <linux/regulator/machine.h> | ||
21 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
22 | #include <linux/amba/mmci.h> | 17 | #include <linux/amba/mmci.h> |
23 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
@@ -25,137 +20,27 @@ | |||
25 | #include "mmc.h" | 20 | #include "mmc.h" |
26 | #include "padmux.h" | 21 | #include "padmux.h" |
27 | 22 | ||
28 | struct mmci_card_event { | 23 | static struct mmci_platform_data mmc0_plat_data = { |
29 | struct input_dev *mmc_input; | 24 | /* |
30 | int mmc_inserted; | 25 | * Do not set ocr_mask or voltage translation function, |
31 | struct work_struct workq; | 26 | * we have a regulator we can control instead. |
32 | struct mmci_platform_data mmc0_plat_data; | 27 | */ |
28 | /* Nominally 2.85V on our platform */ | ||
29 | .f_max = 24000000, | ||
30 | .gpio_wp = -1, | ||
31 | .gpio_cd = U300_GPIO_PIN_MMC_CD, | ||
32 | .cd_invert = true, | ||
33 | .capabilities = MMC_CAP_MMC_HIGHSPEED | | ||
34 | MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, | ||
33 | }; | 35 | }; |
34 | 36 | ||
35 | static unsigned int mmc_status(struct device *dev) | ||
36 | { | ||
37 | struct mmci_card_event *mmci_card = container_of( | ||
38 | dev->platform_data, | ||
39 | struct mmci_card_event, mmc0_plat_data); | ||
40 | |||
41 | return mmci_card->mmc_inserted; | ||
42 | } | ||
43 | |||
44 | static int mmci_callback(void *data) | ||
45 | { | ||
46 | struct mmci_card_event *mmci_card = data; | ||
47 | |||
48 | disable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD); | ||
49 | schedule_work(&mmci_card->workq); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | |||
55 | static ssize_t gpio_show(struct device *dev, struct device_attribute *attr, | ||
56 | char *buf) | ||
57 | { | ||
58 | struct mmci_card_event *mmci_card = container_of( | ||
59 | dev->platform_data, | ||
60 | struct mmci_card_event, mmc0_plat_data); | ||
61 | |||
62 | |||
63 | return sprintf(buf, "%d\n", !mmci_card->mmc_inserted); | ||
64 | } | ||
65 | |||
66 | static DEVICE_ATTR(mmc_inserted, S_IRUGO, gpio_show, NULL); | ||
67 | |||
68 | static void _mmci_callback(struct work_struct *ws) | ||
69 | { | ||
70 | |||
71 | struct mmci_card_event *mmci_card = container_of( | ||
72 | ws, | ||
73 | struct mmci_card_event, workq); | ||
74 | |||
75 | mdelay(20); | ||
76 | |||
77 | mmci_card->mmc_inserted = !gpio_get_value(U300_GPIO_PIN_MMC_CD); | ||
78 | |||
79 | input_report_switch(mmci_card->mmc_input, KEY_INSERT, | ||
80 | mmci_card->mmc_inserted); | ||
81 | input_sync(mmci_card->mmc_input); | ||
82 | |||
83 | pr_debug("MMC/SD card was %s\n", | ||
84 | mmci_card->mmc_inserted ? "inserted" : "removed"); | ||
85 | |||
86 | enable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD, mmci_card->mmc_inserted); | ||
87 | } | ||
88 | |||
89 | int __devinit mmc_init(struct amba_device *adev) | 37 | int __devinit mmc_init(struct amba_device *adev) |
90 | { | 38 | { |
91 | struct mmci_card_event *mmci_card; | ||
92 | struct device *mmcsd_device = &adev->dev; | 39 | struct device *mmcsd_device = &adev->dev; |
93 | struct pmx *pmx; | 40 | struct pmx *pmx; |
94 | int ret = 0; | 41 | int ret = 0; |
95 | 42 | ||
96 | mmci_card = kzalloc(sizeof(struct mmci_card_event), GFP_KERNEL); | 43 | mmcsd_device->platform_data = &mmc0_plat_data; |
97 | if (!mmci_card) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | /* | ||
101 | * Do not set ocr_mask or voltage translation function, | ||
102 | * we have a regulator we can control instead. | ||
103 | */ | ||
104 | /* Nominally 2.85V on our platform */ | ||
105 | mmci_card->mmc0_plat_data.f_max = 24000000; | ||
106 | mmci_card->mmc0_plat_data.status = mmc_status; | ||
107 | mmci_card->mmc0_plat_data.gpio_wp = -1; | ||
108 | mmci_card->mmc0_plat_data.gpio_cd = -1; | ||
109 | mmci_card->mmc0_plat_data.capabilities = MMC_CAP_MMC_HIGHSPEED | | ||
110 | MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; | ||
111 | |||
112 | mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data; | ||
113 | |||
114 | INIT_WORK(&mmci_card->workq, _mmci_callback); | ||
115 | |||
116 | ret = gpio_request(U300_GPIO_PIN_MMC_CD, "MMC card detection"); | ||
117 | if (ret) { | ||
118 | printk(KERN_CRIT "Could not allocate MMC card detection " \ | ||
119 | "GPIO pin\n"); | ||
120 | goto out; | ||
121 | } | ||
122 | |||
123 | ret = gpio_direction_input(U300_GPIO_PIN_MMC_CD); | ||
124 | if (ret) { | ||
125 | printk(KERN_CRIT "Invalid GPIO pin requested\n"); | ||
126 | goto out; | ||
127 | } | ||
128 | |||
129 | ret = sysfs_create_file(&mmcsd_device->kobj, | ||
130 | &dev_attr_mmc_inserted.attr); | ||
131 | if (ret) | ||
132 | goto out; | ||
133 | |||
134 | mmci_card->mmc_input = input_allocate_device(); | ||
135 | if (!mmci_card->mmc_input) { | ||
136 | printk(KERN_CRIT "Could not allocate MMC input device\n"); | ||
137 | return -ENOMEM; | ||
138 | } | ||
139 | |||
140 | mmci_card->mmc_input->name = "MMC insert notification"; | ||
141 | mmci_card->mmc_input->id.bustype = BUS_HOST; | ||
142 | mmci_card->mmc_input->id.vendor = 0; | ||
143 | mmci_card->mmc_input->id.product = 0; | ||
144 | mmci_card->mmc_input->id.version = 0x0100; | ||
145 | mmci_card->mmc_input->dev.parent = mmcsd_device; | ||
146 | input_set_capability(mmci_card->mmc_input, EV_SW, KEY_INSERT); | ||
147 | |||
148 | /* | ||
149 | * Since this must always be compiled into the kernel, this input | ||
150 | * is never unregistered or free:ed. | ||
151 | */ | ||
152 | ret = input_register_device(mmci_card->mmc_input); | ||
153 | if (ret) { | ||
154 | input_free_device(mmci_card->mmc_input); | ||
155 | goto out; | ||
156 | } | ||
157 | |||
158 | input_set_drvdata(mmci_card->mmc_input, mmci_card); | ||
159 | 44 | ||
160 | /* | 45 | /* |
161 | * Setup padmuxing for MMC. Since this must always be | 46 | * Setup padmuxing for MMC. Since this must always be |
@@ -171,12 +56,5 @@ int __devinit mmc_init(struct amba_device *adev) | |||
171 | pr_warning("Could not activate padmuxing\n"); | 56 | pr_warning("Could not activate padmuxing\n"); |
172 | } | 57 | } |
173 | 58 | ||
174 | ret = gpio_register_callback(U300_GPIO_PIN_MMC_CD, mmci_callback, | ||
175 | mmci_card); | ||
176 | |||
177 | schedule_work(&mmci_card->workq); | ||
178 | |||
179 | printk(KERN_INFO "Registered MMC insert/remove notification\n"); | ||
180 | out: | ||
181 | return ret; | 59 | return ret; |
182 | } | 60 | } |