diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-03-30 03:07:39 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-03-30 03:07:43 -0400 |
commit | 9f644c4ba86b76159d36747fda7da496f72a1872 (patch) | |
tree | 31e025a5f283aff691fb636bf07fd0b445cf07a3 /drivers | |
parent | 1b7155f7de119870f0d3fad89f125de2ff6c16be (diff) | |
parent | 0ce790e7d736cedc563e1fb4e998babf5a4dbc3d (diff) |
Merge commit 'v2.6.39-rc1' into perf/urgent
Merge reason: use the post-merge-window tree.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers')
119 files changed, 7156 insertions, 2899 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a18e497f1c3c..31e9e10f657e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -824,11 +824,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
824 | device->backlight->props.brightness = | 824 | device->backlight->props.brightness = |
825 | acpi_video_get_brightness(device->backlight); | 825 | acpi_video_get_brightness(device->backlight); |
826 | 826 | ||
827 | result = sysfs_create_link(&device->backlight->dev.kobj, | ||
828 | &device->dev->dev.kobj, "device"); | ||
829 | if (result) | ||
830 | printk(KERN_ERR PREFIX "Create sysfs link\n"); | ||
831 | |||
832 | device->cooling_dev = thermal_cooling_device_register("LCD", | 827 | device->cooling_dev = thermal_cooling_device_register("LCD", |
833 | device->dev, &video_cooling_ops); | 828 | device->dev, &video_cooling_ops); |
834 | if (IS_ERR(device->cooling_dev)) { | 829 | if (IS_ERR(device->cooling_dev)) { |
@@ -1381,7 +1376,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) | |||
1381 | "Cant remove video notify handler\n"); | 1376 | "Cant remove video notify handler\n"); |
1382 | } | 1377 | } |
1383 | if (device->backlight) { | 1378 | if (device->backlight) { |
1384 | sysfs_remove_link(&device->backlight->dev.kobj, "device"); | ||
1385 | backlight_device_unregister(device->backlight); | 1379 | backlight_device_unregister(device->backlight); |
1386 | device->backlight = NULL; | 1380 | device->backlight = NULL; |
1387 | } | 1381 | } |
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 5253b271b3fe..f6b3f995f58a 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c | |||
@@ -167,7 +167,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) | |||
167 | 167 | ||
168 | irq = platform_get_irq(pdev, 0); | 168 | irq = platform_get_irq(pdev, 0); |
169 | if (irq) | 169 | if (irq) |
170 | set_irq_type(irq, IRQ_TYPE_EDGE_RISING); | 170 | irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); |
171 | 171 | ||
172 | /* Setup expansion bus chip selects */ | 172 | /* Setup expansion bus chip selects */ |
173 | *data->cs0_cfg = data->cs0_bits; | 173 | *data->cs0_cfg = data->cs0_bits; |
diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index baeaf938d55b..1b9d10d9c5d9 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c | |||
@@ -60,10 +60,10 @@ static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance) | |||
60 | struct rb532_cf_info *info = ah->private_data; | 60 | struct rb532_cf_info *info = ah->private_data; |
61 | 61 | ||
62 | if (gpio_get_value(info->gpio_line)) { | 62 | if (gpio_get_value(info->gpio_line)) { |
63 | set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); | 63 | irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); |
64 | ata_sff_interrupt(info->irq, dev_instance); | 64 | ata_sff_interrupt(info->irq, dev_instance); |
65 | } else { | 65 | } else { |
66 | set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); | 66 | irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); |
67 | } | 67 | } |
68 | 68 | ||
69 | return IRQ_HANDLED; | 69 | return IRQ_HANDLED; |
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index f0ae63d2df65..76210ba401ac 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c | |||
@@ -29,8 +29,6 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <asm/kmap_types.h> | 30 | #include <asm/kmap_types.h> |
31 | 31 | ||
32 | #include <asm-generic/bitops/le.h> | ||
33 | |||
34 | #include "drbd_int.h" | 32 | #include "drbd_int.h" |
35 | 33 | ||
36 | 34 | ||
@@ -1184,10 +1182,10 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, | |||
1184 | p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo), km); | 1182 | p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo), km); |
1185 | 1183 | ||
1186 | if (find_zero_bit) | 1184 | if (find_zero_bit) |
1187 | i = generic_find_next_zero_le_bit(p_addr, | 1185 | i = find_next_zero_bit_le(p_addr, |
1188 | PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); | 1186 | PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); |
1189 | else | 1187 | else |
1190 | i = generic_find_next_le_bit(p_addr, | 1188 | i = find_next_bit_le(p_addr, |
1191 | PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); | 1189 | PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); |
1192 | 1190 | ||
1193 | __bm_unmap(p_addr, km); | 1191 | __bm_unmap(p_addr, km); |
@@ -1287,9 +1285,9 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, | |||
1287 | last_page_nr = page_nr; | 1285 | last_page_nr = page_nr; |
1288 | } | 1286 | } |
1289 | if (val) | 1287 | if (val) |
1290 | c += (0 == generic___test_and_set_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); | 1288 | c += (0 == __test_and_set_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr)); |
1291 | else | 1289 | else |
1292 | c -= (0 != generic___test_and_clear_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); | 1290 | c -= (0 != __test_and_clear_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr)); |
1293 | } | 1291 | } |
1294 | if (p_addr) | 1292 | if (p_addr) |
1295 | __bm_unmap(p_addr, km); | 1293 | __bm_unmap(p_addr, km); |
@@ -1438,7 +1436,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) | |||
1438 | bm_print_lock_info(mdev); | 1436 | bm_print_lock_info(mdev); |
1439 | if (bitnr < b->bm_bits) { | 1437 | if (bitnr < b->bm_bits) { |
1440 | p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr)); | 1438 | p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr)); |
1441 | i = generic_test_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0; | 1439 | i = test_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0; |
1442 | bm_unmap(p_addr); | 1440 | bm_unmap(p_addr); |
1443 | } else if (bitnr == b->bm_bits) { | 1441 | } else if (bitnr == b->bm_bits) { |
1444 | i = -1; | 1442 | i = -1; |
@@ -1482,7 +1480,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi | |||
1482 | ERR_IF (bitnr >= b->bm_bits) { | 1480 | ERR_IF (bitnr >= b->bm_bits) { |
1483 | dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); | 1481 | dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); |
1484 | } else { | 1482 | } else { |
1485 | c += (0 != generic_test_le_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); | 1483 | c += (0 != test_bit_le(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); |
1486 | } | 1484 | } |
1487 | } | 1485 | } |
1488 | if (p_addr) | 1486 | if (p_addr) |
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 1f46f1cd9225..7beb0e25f1e1 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -980,7 +980,7 @@ int tpm_open(struct inode *inode, struct file *file) | |||
980 | return -EBUSY; | 980 | return -EBUSY; |
981 | } | 981 | } |
982 | 982 | ||
983 | chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); | 983 | chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); |
984 | if (chip->data_buffer == NULL) { | 984 | if (chip->data_buffer == NULL) { |
985 | clear_bit(0, &chip->is_open); | 985 | clear_bit(0, &chip->is_open); |
986 | put_device(chip->dev); | 986 | put_device(chip->dev); |
diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index dd8ebc75b667..ab8a4eff072a 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c | |||
@@ -94,9 +94,9 @@ static struct ipu_irq_map *src2map(unsigned int src) | |||
94 | return NULL; | 94 | return NULL; |
95 | } | 95 | } |
96 | 96 | ||
97 | static void ipu_irq_unmask(unsigned int irq) | 97 | static void ipu_irq_unmask(struct irq_data *d) |
98 | { | 98 | { |
99 | struct ipu_irq_map *map = get_irq_chip_data(irq); | 99 | struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); |
100 | struct ipu_irq_bank *bank; | 100 | struct ipu_irq_bank *bank; |
101 | uint32_t reg; | 101 | uint32_t reg; |
102 | unsigned long lock_flags; | 102 | unsigned long lock_flags; |
@@ -106,7 +106,7 @@ static void ipu_irq_unmask(unsigned int irq) | |||
106 | bank = map->bank; | 106 | bank = map->bank; |
107 | if (!bank) { | 107 | if (!bank) { |
108 | spin_unlock_irqrestore(&bank_lock, lock_flags); | 108 | spin_unlock_irqrestore(&bank_lock, lock_flags); |
109 | pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq); | 109 | pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); |
110 | return; | 110 | return; |
111 | } | 111 | } |
112 | 112 | ||
@@ -117,9 +117,9 @@ static void ipu_irq_unmask(unsigned int irq) | |||
117 | spin_unlock_irqrestore(&bank_lock, lock_flags); | 117 | spin_unlock_irqrestore(&bank_lock, lock_flags); |
118 | } | 118 | } |
119 | 119 | ||
120 | static void ipu_irq_mask(unsigned int irq) | 120 | static void ipu_irq_mask(struct irq_data *d) |
121 | { | 121 | { |
122 | struct ipu_irq_map *map = get_irq_chip_data(irq); | 122 | struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); |
123 | struct ipu_irq_bank *bank; | 123 | struct ipu_irq_bank *bank; |
124 | uint32_t reg; | 124 | uint32_t reg; |
125 | unsigned long lock_flags; | 125 | unsigned long lock_flags; |
@@ -129,7 +129,7 @@ static void ipu_irq_mask(unsigned int irq) | |||
129 | bank = map->bank; | 129 | bank = map->bank; |
130 | if (!bank) { | 130 | if (!bank) { |
131 | spin_unlock_irqrestore(&bank_lock, lock_flags); | 131 | spin_unlock_irqrestore(&bank_lock, lock_flags); |
132 | pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq); | 132 | pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); |
133 | return; | 133 | return; |
134 | } | 134 | } |
135 | 135 | ||
@@ -140,9 +140,9 @@ static void ipu_irq_mask(unsigned int irq) | |||
140 | spin_unlock_irqrestore(&bank_lock, lock_flags); | 140 | spin_unlock_irqrestore(&bank_lock, lock_flags); |
141 | } | 141 | } |
142 | 142 | ||
143 | static void ipu_irq_ack(unsigned int irq) | 143 | static void ipu_irq_ack(struct irq_data *d) |
144 | { | 144 | { |
145 | struct ipu_irq_map *map = get_irq_chip_data(irq); | 145 | struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); |
146 | struct ipu_irq_bank *bank; | 146 | struct ipu_irq_bank *bank; |
147 | unsigned long lock_flags; | 147 | unsigned long lock_flags; |
148 | 148 | ||
@@ -151,7 +151,7 @@ static void ipu_irq_ack(unsigned int irq) | |||
151 | bank = map->bank; | 151 | bank = map->bank; |
152 | if (!bank) { | 152 | if (!bank) { |
153 | spin_unlock_irqrestore(&bank_lock, lock_flags); | 153 | spin_unlock_irqrestore(&bank_lock, lock_flags); |
154 | pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq); | 154 | pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); |
155 | return; | 155 | return; |
156 | } | 156 | } |
157 | 157 | ||
@@ -167,7 +167,7 @@ static void ipu_irq_ack(unsigned int irq) | |||
167 | */ | 167 | */ |
168 | bool ipu_irq_status(unsigned int irq) | 168 | bool ipu_irq_status(unsigned int irq) |
169 | { | 169 | { |
170 | struct ipu_irq_map *map = get_irq_chip_data(irq); | 170 | struct ipu_irq_map *map = irq_get_chip_data(irq); |
171 | struct ipu_irq_bank *bank; | 171 | struct ipu_irq_bank *bank; |
172 | unsigned long lock_flags; | 172 | unsigned long lock_flags; |
173 | bool ret; | 173 | bool ret; |
@@ -269,7 +269,7 @@ int ipu_irq_unmap(unsigned int source) | |||
269 | /* Chained IRQ handler for IPU error interrupt */ | 269 | /* Chained IRQ handler for IPU error interrupt */ |
270 | static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) | 270 | static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) |
271 | { | 271 | { |
272 | struct ipu *ipu = get_irq_data(irq); | 272 | struct ipu *ipu = irq_get_handler_data(irq); |
273 | u32 status; | 273 | u32 status; |
274 | int i, line; | 274 | int i, line; |
275 | 275 | ||
@@ -310,7 +310,7 @@ static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) | |||
310 | /* Chained IRQ handler for IPU function interrupt */ | 310 | /* Chained IRQ handler for IPU function interrupt */ |
311 | static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc) | 311 | static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc) |
312 | { | 312 | { |
313 | struct ipu *ipu = get_irq_data(irq); | 313 | struct ipu *ipu = irq_desc_get_handler_data(desc); |
314 | u32 status; | 314 | u32 status; |
315 | int i, line; | 315 | int i, line; |
316 | 316 | ||
@@ -345,10 +345,10 @@ static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc) | |||
345 | } | 345 | } |
346 | 346 | ||
347 | static struct irq_chip ipu_irq_chip = { | 347 | static struct irq_chip ipu_irq_chip = { |
348 | .name = "ipu_irq", | 348 | .name = "ipu_irq", |
349 | .ack = ipu_irq_ack, | 349 | .irq_ack = ipu_irq_ack, |
350 | .mask = ipu_irq_mask, | 350 | .irq_mask = ipu_irq_mask, |
351 | .unmask = ipu_irq_unmask, | 351 | .irq_unmask = ipu_irq_unmask, |
352 | }; | 352 | }; |
353 | 353 | ||
354 | /* Install the IRQ handler */ | 354 | /* Install the IRQ handler */ |
@@ -366,26 +366,26 @@ int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev) | |||
366 | int ret; | 366 | int ret; |
367 | 367 | ||
368 | irq = irq_base + i; | 368 | irq = irq_base + i; |
369 | ret = set_irq_chip(irq, &ipu_irq_chip); | 369 | ret = irq_set_chip(irq, &ipu_irq_chip); |
370 | if (ret < 0) | 370 | if (ret < 0) |
371 | return ret; | 371 | return ret; |
372 | ret = set_irq_chip_data(irq, irq_map + i); | 372 | ret = irq_set_chip_data(irq, irq_map + i); |
373 | if (ret < 0) | 373 | if (ret < 0) |
374 | return ret; | 374 | return ret; |
375 | irq_map[i].ipu = ipu; | 375 | irq_map[i].ipu = ipu; |
376 | irq_map[i].irq = irq; | 376 | irq_map[i].irq = irq; |
377 | irq_map[i].source = -EINVAL; | 377 | irq_map[i].source = -EINVAL; |
378 | set_irq_handler(irq, handle_level_irq); | 378 | irq_set_handler(irq, handle_level_irq); |
379 | #ifdef CONFIG_ARM | 379 | #ifdef CONFIG_ARM |
380 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 380 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
381 | #endif | 381 | #endif |
382 | } | 382 | } |
383 | 383 | ||
384 | set_irq_data(ipu->irq_fn, ipu); | 384 | irq_set_handler_data(ipu->irq_fn, ipu); |
385 | set_irq_chained_handler(ipu->irq_fn, ipu_irq_fn); | 385 | irq_set_chained_handler(ipu->irq_fn, ipu_irq_fn); |
386 | 386 | ||
387 | set_irq_data(ipu->irq_err, ipu); | 387 | irq_set_handler_data(ipu->irq_err, ipu); |
388 | set_irq_chained_handler(ipu->irq_err, ipu_irq_err); | 388 | irq_set_chained_handler(ipu->irq_err, ipu_irq_err); |
389 | 389 | ||
390 | return 0; | 390 | return 0; |
391 | } | 391 | } |
@@ -397,17 +397,17 @@ void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev) | |||
397 | 397 | ||
398 | irq_base = pdata->irq_base; | 398 | irq_base = pdata->irq_base; |
399 | 399 | ||
400 | set_irq_chained_handler(ipu->irq_fn, NULL); | 400 | irq_set_chained_handler(ipu->irq_fn, NULL); |
401 | set_irq_data(ipu->irq_fn, NULL); | 401 | irq_set_handler_data(ipu->irq_fn, NULL); |
402 | 402 | ||
403 | set_irq_chained_handler(ipu->irq_err, NULL); | 403 | irq_set_chained_handler(ipu->irq_err, NULL); |
404 | set_irq_data(ipu->irq_err, NULL); | 404 | irq_set_handler_data(ipu->irq_err, NULL); |
405 | 405 | ||
406 | for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) { | 406 | for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) { |
407 | #ifdef CONFIG_ARM | 407 | #ifdef CONFIG_ARM |
408 | set_irq_flags(irq, 0); | 408 | set_irq_flags(irq, 0); |
409 | #endif | 409 | #endif |
410 | set_irq_chip(irq, NULL); | 410 | irq_set_chip(irq, NULL); |
411 | set_irq_chip_data(irq, NULL); | 411 | irq_set_chip_data(irq, NULL); |
412 | } | 412 | } |
413 | } | 413 | } |
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 0be30e978c85..31e71c4fc831 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -2679,7 +2679,7 @@ static int __init amd64_edac_init(void) | |||
2679 | mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL); | 2679 | mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL); |
2680 | ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL); | 2680 | ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL); |
2681 | if (!(mcis && ecc_stngs)) | 2681 | if (!(mcis && ecc_stngs)) |
2682 | goto err_ret; | 2682 | goto err_free; |
2683 | 2683 | ||
2684 | msrs = msrs_alloc(); | 2684 | msrs = msrs_alloc(); |
2685 | if (!msrs) | 2685 | if (!msrs) |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d8d0cda2641d..d3b295305542 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -414,4 +414,9 @@ config GPIO_JANZ_TTL | |||
414 | This driver provides support for driving the pins in output | 414 | This driver provides support for driving the pins in output |
415 | mode only. Input mode is not supported. | 415 | mode only. Input mode is not supported. |
416 | 416 | ||
417 | config AB8500_GPIO | ||
418 | bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" | ||
419 | depends on AB8500_CORE && BROKEN | ||
420 | help | ||
421 | Select this to enable the AB8500 IC GPIO driver | ||
417 | endif | 422 | endif |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 3351cf87b0ed..becef5954356 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -42,3 +42,4 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o | |||
42 | obj-$(CONFIG_GPIO_SX150X) += sx150x.o | 42 | obj-$(CONFIG_GPIO_SX150X) += sx150x.o |
43 | obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o | 43 | obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o |
44 | obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o | 44 | obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o |
45 | obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o | ||
diff --git a/drivers/gpio/ab8500-gpio.c b/drivers/gpio/ab8500-gpio.c new file mode 100644 index 000000000000..e7b834d054b7 --- /dev/null +++ b/drivers/gpio/ab8500-gpio.c | |||
@@ -0,0 +1,522 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2011 | ||
3 | * | ||
4 | * Author: BIBEK BASU <bibek.basu@stericsson.com> | ||
5 | * License terms: GNU General Public License (GPL) version 2 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/gpio.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/mfd/ab8500.h> | ||
23 | #include <linux/mfd/abx500.h> | ||
24 | #include <linux/mfd/ab8500/gpio.h> | ||
25 | |||
26 | /* | ||
27 | * GPIO registers offset | ||
28 | * Bank: 0x10 | ||
29 | */ | ||
30 | #define AB8500_GPIO_SEL1_REG 0x00 | ||
31 | #define AB8500_GPIO_SEL2_REG 0x01 | ||
32 | #define AB8500_GPIO_SEL3_REG 0x02 | ||
33 | #define AB8500_GPIO_SEL4_REG 0x03 | ||
34 | #define AB8500_GPIO_SEL5_REG 0x04 | ||
35 | #define AB8500_GPIO_SEL6_REG 0x05 | ||
36 | |||
37 | #define AB8500_GPIO_DIR1_REG 0x10 | ||
38 | #define AB8500_GPIO_DIR2_REG 0x11 | ||
39 | #define AB8500_GPIO_DIR3_REG 0x12 | ||
40 | #define AB8500_GPIO_DIR4_REG 0x13 | ||
41 | #define AB8500_GPIO_DIR5_REG 0x14 | ||
42 | #define AB8500_GPIO_DIR6_REG 0x15 | ||
43 | |||
44 | #define AB8500_GPIO_OUT1_REG 0x20 | ||
45 | #define AB8500_GPIO_OUT2_REG 0x21 | ||
46 | #define AB8500_GPIO_OUT3_REG 0x22 | ||
47 | #define AB8500_GPIO_OUT4_REG 0x23 | ||
48 | #define AB8500_GPIO_OUT5_REG 0x24 | ||
49 | #define AB8500_GPIO_OUT6_REG 0x25 | ||
50 | |||
51 | #define AB8500_GPIO_PUD1_REG 0x30 | ||
52 | #define AB8500_GPIO_PUD2_REG 0x31 | ||
53 | #define AB8500_GPIO_PUD3_REG 0x32 | ||
54 | #define AB8500_GPIO_PUD4_REG 0x33 | ||
55 | #define AB8500_GPIO_PUD5_REG 0x34 | ||
56 | #define AB8500_GPIO_PUD6_REG 0x35 | ||
57 | |||
58 | #define AB8500_GPIO_IN1_REG 0x40 | ||
59 | #define AB8500_GPIO_IN2_REG 0x41 | ||
60 | #define AB8500_GPIO_IN3_REG 0x42 | ||
61 | #define AB8500_GPIO_IN4_REG 0x43 | ||
62 | #define AB8500_GPIO_IN5_REG 0x44 | ||
63 | #define AB8500_GPIO_IN6_REG 0x45 | ||
64 | #define AB8500_GPIO_ALTFUN_REG 0x45 | ||
65 | #define ALTFUN_REG_INDEX 6 | ||
66 | #define AB8500_NUM_GPIO 42 | ||
67 | #define AB8500_NUM_VIR_GPIO_IRQ 16 | ||
68 | |||
69 | enum ab8500_gpio_action { | ||
70 | NONE, | ||
71 | STARTUP, | ||
72 | SHUTDOWN, | ||
73 | MASK, | ||
74 | UNMASK | ||
75 | }; | ||
76 | |||
77 | struct ab8500_gpio { | ||
78 | struct gpio_chip chip; | ||
79 | struct ab8500 *parent; | ||
80 | struct device *dev; | ||
81 | struct mutex lock; | ||
82 | u32 irq_base; | ||
83 | enum ab8500_gpio_action irq_action; | ||
84 | u16 rising; | ||
85 | u16 falling; | ||
86 | }; | ||
87 | /** | ||
88 | * to_ab8500_gpio() - get the pointer to ab8500_gpio | ||
89 | * @chip: Member of the structure ab8500_gpio | ||
90 | */ | ||
91 | static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip) | ||
92 | { | ||
93 | return container_of(chip, struct ab8500_gpio, chip); | ||
94 | } | ||
95 | |||
96 | static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg, | ||
97 | unsigned offset, int val) | ||
98 | { | ||
99 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
100 | u8 pos = offset % 8; | ||
101 | int ret; | ||
102 | |||
103 | reg = reg + (offset / 8); | ||
104 | ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev, | ||
105 | AB8500_MISC, reg, 1 << pos, val << pos); | ||
106 | if (ret < 0) | ||
107 | dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); | ||
108 | return ret; | ||
109 | } | ||
110 | /** | ||
111 | * ab8500_gpio_get() - Get the particular GPIO value | ||
112 | * @chip: Gpio device | ||
113 | * @offset: GPIO number to read | ||
114 | */ | ||
115 | static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
116 | { | ||
117 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
118 | u8 mask = 1 << (offset % 8); | ||
119 | u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8); | ||
120 | int ret; | ||
121 | u8 data; | ||
122 | ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC, | ||
123 | reg, &data); | ||
124 | if (ret < 0) { | ||
125 | dev_err(ab8500_gpio->dev, "%s read failed\n", __func__); | ||
126 | return ret; | ||
127 | } | ||
128 | return (data & mask) >> (offset % 8); | ||
129 | } | ||
130 | |||
131 | static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
132 | { | ||
133 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
134 | int ret; | ||
135 | /* Write the data */ | ||
136 | ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1); | ||
137 | if (ret < 0) | ||
138 | dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); | ||
139 | } | ||
140 | |||
141 | static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | ||
142 | int val) | ||
143 | { | ||
144 | int ret; | ||
145 | /* set direction as output */ | ||
146 | ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | /* disable pull down */ | ||
150 | ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1); | ||
151 | if (ret < 0) | ||
152 | return ret; | ||
153 | /* set the output as 1 or 0 */ | ||
154 | return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); | ||
155 | |||
156 | } | ||
157 | |||
158 | static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
159 | { | ||
160 | /* set the register as input */ | ||
161 | return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0); | ||
162 | } | ||
163 | |||
164 | static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
165 | { | ||
166 | /* | ||
167 | * Only some GPIOs are interrupt capable, and they are | ||
168 | * organized in discontiguous clusters: | ||
169 | * | ||
170 | * GPIO6 to GPIO13 | ||
171 | * GPIO24 and GPIO25 | ||
172 | * GPIO36 to GPIO41 | ||
173 | */ | ||
174 | static struct ab8500_gpio_irq_cluster { | ||
175 | int start; | ||
176 | int end; | ||
177 | } clusters[] = { | ||
178 | {.start = 6, .end = 13}, | ||
179 | {.start = 24, .end = 25}, | ||
180 | {.start = 36, .end = 41}, | ||
181 | }; | ||
182 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
183 | int base = ab8500_gpio->irq_base; | ||
184 | int i; | ||
185 | |||
186 | for (i = 0; i < ARRAY_SIZE(clusters); i++) { | ||
187 | struct ab8500_gpio_irq_cluster *cluster = &clusters[i]; | ||
188 | |||
189 | if (offset >= cluster->start && offset <= cluster->end) | ||
190 | return base + offset - cluster->start; | ||
191 | |||
192 | /* Advance by the number of gpios in this cluster */ | ||
193 | base += cluster->end - cluster->start + 1; | ||
194 | } | ||
195 | |||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | static struct gpio_chip ab8500gpio_chip = { | ||
200 | .label = "ab8500_gpio", | ||
201 | .owner = THIS_MODULE, | ||
202 | .direction_input = ab8500_gpio_direction_input, | ||
203 | .get = ab8500_gpio_get, | ||
204 | .direction_output = ab8500_gpio_direction_output, | ||
205 | .set = ab8500_gpio_set, | ||
206 | .to_irq = ab8500_gpio_to_irq, | ||
207 | }; | ||
208 | |||
209 | static unsigned int irq_to_rising(unsigned int irq) | ||
210 | { | ||
211 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
212 | int offset = irq - ab8500_gpio->irq_base; | ||
213 | int new_irq = offset + AB8500_INT_GPIO6R | ||
214 | + ab8500_gpio->parent->irq_base; | ||
215 | return new_irq; | ||
216 | } | ||
217 | |||
218 | static unsigned int irq_to_falling(unsigned int irq) | ||
219 | { | ||
220 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
221 | int offset = irq - ab8500_gpio->irq_base; | ||
222 | int new_irq = offset + AB8500_INT_GPIO6F | ||
223 | + ab8500_gpio->parent->irq_base; | ||
224 | return new_irq; | ||
225 | |||
226 | } | ||
227 | |||
228 | static unsigned int rising_to_irq(unsigned int irq, void *dev) | ||
229 | { | ||
230 | struct ab8500_gpio *ab8500_gpio = dev; | ||
231 | int offset = irq - AB8500_INT_GPIO6R | ||
232 | - ab8500_gpio->parent->irq_base ; | ||
233 | int new_irq = offset + ab8500_gpio->irq_base; | ||
234 | return new_irq; | ||
235 | } | ||
236 | |||
237 | static unsigned int falling_to_irq(unsigned int irq, void *dev) | ||
238 | { | ||
239 | struct ab8500_gpio *ab8500_gpio = dev; | ||
240 | int offset = irq - AB8500_INT_GPIO6F | ||
241 | - ab8500_gpio->parent->irq_base ; | ||
242 | int new_irq = offset + ab8500_gpio->irq_base; | ||
243 | return new_irq; | ||
244 | |||
245 | } | ||
246 | |||
247 | /* | ||
248 | * IRQ handler | ||
249 | */ | ||
250 | |||
251 | static irqreturn_t handle_rising(int irq, void *dev) | ||
252 | { | ||
253 | |||
254 | handle_nested_irq(rising_to_irq(irq , dev)); | ||
255 | return IRQ_HANDLED; | ||
256 | } | ||
257 | |||
258 | static irqreturn_t handle_falling(int irq, void *dev) | ||
259 | { | ||
260 | |||
261 | handle_nested_irq(falling_to_irq(irq, dev)); | ||
262 | return IRQ_HANDLED; | ||
263 | } | ||
264 | |||
265 | static void ab8500_gpio_irq_lock(unsigned int irq) | ||
266 | { | ||
267 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
268 | mutex_lock(&ab8500_gpio->lock); | ||
269 | } | ||
270 | |||
271 | static void ab8500_gpio_irq_sync_unlock(unsigned int irq) | ||
272 | { | ||
273 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
274 | int offset = irq - ab8500_gpio->irq_base; | ||
275 | bool rising = ab8500_gpio->rising & BIT(offset); | ||
276 | bool falling = ab8500_gpio->falling & BIT(offset); | ||
277 | int ret; | ||
278 | |||
279 | switch (ab8500_gpio->irq_action) { | ||
280 | case STARTUP: | ||
281 | if (rising) | ||
282 | ret = request_threaded_irq(irq_to_rising(irq), | ||
283 | NULL, handle_rising, | ||
284 | IRQF_TRIGGER_RISING, | ||
285 | "ab8500-gpio-r", ab8500_gpio); | ||
286 | if (falling) | ||
287 | ret = request_threaded_irq(irq_to_falling(irq), | ||
288 | NULL, handle_falling, | ||
289 | IRQF_TRIGGER_FALLING, | ||
290 | "ab8500-gpio-f", ab8500_gpio); | ||
291 | break; | ||
292 | case SHUTDOWN: | ||
293 | if (rising) | ||
294 | free_irq(irq_to_rising(irq), ab8500_gpio); | ||
295 | if (falling) | ||
296 | free_irq(irq_to_falling(irq), ab8500_gpio); | ||
297 | break; | ||
298 | case MASK: | ||
299 | if (rising) | ||
300 | disable_irq(irq_to_rising(irq)); | ||
301 | if (falling) | ||
302 | disable_irq(irq_to_falling(irq)); | ||
303 | break; | ||
304 | case UNMASK: | ||
305 | if (rising) | ||
306 | enable_irq(irq_to_rising(irq)); | ||
307 | if (falling) | ||
308 | enable_irq(irq_to_falling(irq)); | ||
309 | break; | ||
310 | case NONE: | ||
311 | break; | ||
312 | } | ||
313 | ab8500_gpio->irq_action = NONE; | ||
314 | ab8500_gpio->rising &= ~(BIT(offset)); | ||
315 | ab8500_gpio->falling &= ~(BIT(offset)); | ||
316 | mutex_unlock(&ab8500_gpio->lock); | ||
317 | } | ||
318 | |||
319 | |||
320 | static void ab8500_gpio_irq_mask(unsigned int irq) | ||
321 | { | ||
322 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
323 | ab8500_gpio->irq_action = MASK; | ||
324 | } | ||
325 | |||
326 | static void ab8500_gpio_irq_unmask(unsigned int irq) | ||
327 | { | ||
328 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
329 | ab8500_gpio->irq_action = UNMASK; | ||
330 | } | ||
331 | |||
332 | static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type) | ||
333 | { | ||
334 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
335 | int offset = irq - ab8500_gpio->irq_base; | ||
336 | |||
337 | if (type == IRQ_TYPE_EDGE_BOTH) { | ||
338 | ab8500_gpio->rising = BIT(offset); | ||
339 | ab8500_gpio->falling = BIT(offset); | ||
340 | } else if (type == IRQ_TYPE_EDGE_RISING) { | ||
341 | ab8500_gpio->rising = BIT(offset); | ||
342 | } else { | ||
343 | ab8500_gpio->falling = BIT(offset); | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | unsigned int ab8500_gpio_irq_startup(unsigned int irq) | ||
349 | { | ||
350 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
351 | ab8500_gpio->irq_action = STARTUP; | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | void ab8500_gpio_irq_shutdown(unsigned int irq) | ||
356 | { | ||
357 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
358 | ab8500_gpio->irq_action = SHUTDOWN; | ||
359 | } | ||
360 | |||
361 | static struct irq_chip ab8500_gpio_irq_chip = { | ||
362 | .name = "ab8500-gpio", | ||
363 | .startup = ab8500_gpio_irq_startup, | ||
364 | .shutdown = ab8500_gpio_irq_shutdown, | ||
365 | .bus_lock = ab8500_gpio_irq_lock, | ||
366 | .bus_sync_unlock = ab8500_gpio_irq_sync_unlock, | ||
367 | .mask = ab8500_gpio_irq_mask, | ||
368 | .unmask = ab8500_gpio_irq_unmask, | ||
369 | .set_type = ab8500_gpio_irq_set_type, | ||
370 | }; | ||
371 | |||
372 | static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio) | ||
373 | { | ||
374 | u32 base = ab8500_gpio->irq_base; | ||
375 | int irq; | ||
376 | |||
377 | for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) { | ||
378 | set_irq_chip_data(irq, ab8500_gpio); | ||
379 | set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip, | ||
380 | handle_simple_irq); | ||
381 | set_irq_nested_thread(irq, 1); | ||
382 | #ifdef CONFIG_ARM | ||
383 | set_irq_flags(irq, IRQF_VALID); | ||
384 | #else | ||
385 | set_irq_noprobe(irq); | ||
386 | #endif | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio) | ||
393 | { | ||
394 | int base = ab8500_gpio->irq_base; | ||
395 | int irq; | ||
396 | |||
397 | for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) { | ||
398 | #ifdef CONFIG_ARM | ||
399 | set_irq_flags(irq, 0); | ||
400 | #endif | ||
401 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
402 | set_irq_chip_data(irq, NULL); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | static int __devinit ab8500_gpio_probe(struct platform_device *pdev) | ||
407 | { | ||
408 | struct ab8500_platform_data *ab8500_pdata = | ||
409 | dev_get_platdata(pdev->dev.parent); | ||
410 | struct ab8500_gpio_platform_data *pdata; | ||
411 | struct ab8500_gpio *ab8500_gpio; | ||
412 | int ret; | ||
413 | int i; | ||
414 | |||
415 | pdata = ab8500_pdata->gpio; | ||
416 | if (!pdata) { | ||
417 | dev_err(&pdev->dev, "gpio platform data missing\n"); | ||
418 | return -ENODEV; | ||
419 | } | ||
420 | |||
421 | ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL); | ||
422 | if (ab8500_gpio == NULL) { | ||
423 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
424 | return -ENOMEM; | ||
425 | } | ||
426 | ab8500_gpio->dev = &pdev->dev; | ||
427 | ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent); | ||
428 | ab8500_gpio->chip = ab8500gpio_chip; | ||
429 | ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO; | ||
430 | ab8500_gpio->chip.dev = &pdev->dev; | ||
431 | ab8500_gpio->chip.base = pdata->gpio_base; | ||
432 | ab8500_gpio->irq_base = pdata->irq_base; | ||
433 | /* initialize the lock */ | ||
434 | mutex_init(&ab8500_gpio->lock); | ||
435 | /* | ||
436 | * AB8500 core will handle and clear the IRQ | ||
437 | * configre GPIO based on config-reg value. | ||
438 | * These values are for selecting the PINs as | ||
439 | * GPIO or alternate function | ||
440 | */ | ||
441 | for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++) { | ||
442 | ret = abx500_set_register_interruptible(ab8500_gpio->dev, | ||
443 | AB8500_MISC, i, | ||
444 | pdata->config_reg[i]); | ||
445 | if (ret < 0) | ||
446 | goto out_free; | ||
447 | } | ||
448 | ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC, | ||
449 | AB8500_GPIO_ALTFUN_REG, | ||
450 | pdata->config_reg[ALTFUN_REG_INDEX]); | ||
451 | if (ret < 0) | ||
452 | goto out_free; | ||
453 | |||
454 | ret = ab8500_gpio_irq_init(ab8500_gpio); | ||
455 | if (ret) | ||
456 | goto out_free; | ||
457 | ret = gpiochip_add(&ab8500_gpio->chip); | ||
458 | if (ret) { | ||
459 | dev_err(&pdev->dev, "unable to add gpiochip: %d\n", | ||
460 | ret); | ||
461 | goto out_rem_irq; | ||
462 | } | ||
463 | platform_set_drvdata(pdev, ab8500_gpio); | ||
464 | return 0; | ||
465 | |||
466 | out_rem_irq: | ||
467 | ab8500_gpio_irq_remove(ab8500_gpio); | ||
468 | out_free: | ||
469 | mutex_destroy(&ab8500_gpio->lock); | ||
470 | kfree(ab8500_gpio); | ||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * ab8500_gpio_remove() - remove Ab8500-gpio driver | ||
476 | * @pdev : Platform device registered | ||
477 | */ | ||
478 | static int __devexit ab8500_gpio_remove(struct platform_device *pdev) | ||
479 | { | ||
480 | struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev); | ||
481 | int ret; | ||
482 | |||
483 | ret = gpiochip_remove(&ab8500_gpio->chip); | ||
484 | if (ret < 0) { | ||
485 | dev_err(ab8500_gpio->dev, "unable to remove gpiochip:\ | ||
486 | %d\n", ret); | ||
487 | return ret; | ||
488 | } | ||
489 | |||
490 | platform_set_drvdata(pdev, NULL); | ||
491 | mutex_destroy(&ab8500_gpio->lock); | ||
492 | kfree(ab8500_gpio); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static struct platform_driver ab8500_gpio_driver = { | ||
498 | .driver = { | ||
499 | .name = "ab8500-gpio", | ||
500 | .owner = THIS_MODULE, | ||
501 | }, | ||
502 | .probe = ab8500_gpio_probe, | ||
503 | .remove = __devexit_p(ab8500_gpio_remove), | ||
504 | }; | ||
505 | |||
506 | static int __init ab8500_gpio_init(void) | ||
507 | { | ||
508 | return platform_driver_register(&ab8500_gpio_driver); | ||
509 | } | ||
510 | arch_initcall(ab8500_gpio_init); | ||
511 | |||
512 | static void __exit ab8500_gpio_exit(void) | ||
513 | { | ||
514 | platform_driver_unregister(&ab8500_gpio_driver); | ||
515 | } | ||
516 | module_exit(ab8500_gpio_exit); | ||
517 | |||
518 | MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>"); | ||
519 | MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins\ | ||
520 | to be used as GPIO"); | ||
521 | MODULE_ALIAS("AB8500 GPIO driver"); | ||
522 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index f141a1de519c..89aa9fb743af 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c | |||
@@ -116,7 +116,7 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data, | |||
116 | return 0; | 116 | return 0; |
117 | 117 | ||
118 | INIT_WORK(&fan_data->alarm_work, fan_alarm_notify); | 118 | INIT_WORK(&fan_data->alarm_work, fan_alarm_notify); |
119 | set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH); | 119 | irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH); |
120 | err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED, | 120 | err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED, |
121 | "GPIO fan alarm", fan_data); | 121 | "GPIO fan alarm", fan_data); |
122 | if (err) | 122 | if (err) |
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index b732870ecc89..71f744a8e686 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c | |||
@@ -809,7 +809,7 @@ static int lm8323_suspend(struct device *dev) | |||
809 | struct lm8323_chip *lm = i2c_get_clientdata(client); | 809 | struct lm8323_chip *lm = i2c_get_clientdata(client); |
810 | int i; | 810 | int i; |
811 | 811 | ||
812 | set_irq_wake(client->irq, 0); | 812 | irq_set_irq_wake(client->irq, 0); |
813 | disable_irq(client->irq); | 813 | disable_irq(client->irq); |
814 | 814 | ||
815 | mutex_lock(&lm->lock); | 815 | mutex_lock(&lm->lock); |
@@ -838,7 +838,7 @@ static int lm8323_resume(struct device *dev) | |||
838 | led_classdev_resume(&lm->pwm[i].cdev); | 838 | led_classdev_resume(&lm->pwm[i].cdev); |
839 | 839 | ||
840 | enable_irq(client->irq); | 840 | enable_irq(client->irq); |
841 | set_irq_wake(client->irq, 1); | 841 | irq_set_irq_wake(client->irq, 1); |
842 | 842 | ||
843 | return 0; | 843 | return 0; |
844 | } | 844 | } |
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index ebe955325677..4b2a42f9f0bb 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c | |||
@@ -149,7 +149,7 @@ static int __init ams_delta_serio_init(void) | |||
149 | * at FIQ level, switch back from edge to simple interrupt handler | 149 | * at FIQ level, switch back from edge to simple interrupt handler |
150 | * to avoid bad interaction. | 150 | * to avoid bad interaction. |
151 | */ | 151 | */ |
152 | set_irq_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), | 152 | irq_set_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), |
153 | handle_simple_irq); | 153 | handle_simple_irq); |
154 | 154 | ||
155 | serio_register_port(ams_delta_serio); | 155 | serio_register_port(ams_delta_serio); |
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index b6b8b1c7ecea..3242e7076258 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c | |||
@@ -219,7 +219,7 @@ static int wm97xx_acc_startup(struct wm97xx *wm) | |||
219 | } | 219 | } |
220 | 220 | ||
221 | wm->pen_irq = gpio_to_irq(irq); | 221 | wm->pen_irq = gpio_to_irq(irq); |
222 | set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); | 222 | irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); |
223 | } else /* pen irq not supported */ | 223 | } else /* pen irq not supported */ |
224 | pen_int = 0; | 224 | pen_int = 0; |
225 | 225 | ||
diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index 048849867643..5b0f15ec874a 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c | |||
@@ -193,7 +193,7 @@ static int zylonite_wm97xx_probe(struct platform_device *pdev) | |||
193 | gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26); | 193 | gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26); |
194 | 194 | ||
195 | wm->pen_irq = IRQ_GPIO(gpio_touch_irq); | 195 | wm->pen_irq = IRQ_GPIO(gpio_touch_irq); |
196 | set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); | 196 | irq_set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); |
197 | 197 | ||
198 | wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, | 198 | wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, |
199 | WM97XX_GPIO_POL_HIGH, | 199 | WM97XX_GPIO_POL_HIGH, |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 06ecea751a39..8b66e04c2ea6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1777,12 +1777,6 @@ int md_integrity_register(mddev_t *mddev) | |||
1777 | continue; | 1777 | continue; |
1778 | if (rdev->raid_disk < 0) | 1778 | if (rdev->raid_disk < 0) |
1779 | continue; | 1779 | continue; |
1780 | /* | ||
1781 | * If at least one rdev is not integrity capable, we can not | ||
1782 | * enable data integrity for the md device. | ||
1783 | */ | ||
1784 | if (!bdev_get_integrity(rdev->bdev)) | ||
1785 | return -EINVAL; | ||
1786 | if (!reference) { | 1780 | if (!reference) { |
1787 | /* Use the first rdev as the reference */ | 1781 | /* Use the first rdev as the reference */ |
1788 | reference = rdev; | 1782 | reference = rdev; |
@@ -1793,6 +1787,8 @@ int md_integrity_register(mddev_t *mddev) | |||
1793 | rdev->bdev->bd_disk) < 0) | 1787 | rdev->bdev->bd_disk) < 0) |
1794 | return -EINVAL; | 1788 | return -EINVAL; |
1795 | } | 1789 | } |
1790 | if (!reference || !bdev_get_integrity(reference->bdev)) | ||
1791 | return 0; | ||
1796 | /* | 1792 | /* |
1797 | * All component devices are integrity capable and have matching | 1793 | * All component devices are integrity capable and have matching |
1798 | * profiles, register the common profile for the md device. | 1794 | * profiles, register the common profile for the md device. |
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 767406c95291..700d420a59ac 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/swab.h> | 23 | #include <linux/swab.h> |
24 | #include "r592.h" | 24 | #include "r592.h" |
25 | 25 | ||
26 | static int enable_dma = 1; | 26 | static int r592_enable_dma = 1; |
27 | static int debug; | 27 | static int debug; |
28 | 28 | ||
29 | static const char *tpc_names[] = { | 29 | static const char *tpc_names[] = { |
@@ -267,7 +267,7 @@ static void r592_stop_dma(struct r592_device *dev, int error) | |||
267 | /* Test if hardware supports DMA */ | 267 | /* Test if hardware supports DMA */ |
268 | static void r592_check_dma(struct r592_device *dev) | 268 | static void r592_check_dma(struct r592_device *dev) |
269 | { | 269 | { |
270 | dev->dma_capable = enable_dma && | 270 | dev->dma_capable = r592_enable_dma && |
271 | (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & | 271 | (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & |
272 | R592_FIFO_DMA_SETTINGS_CAP); | 272 | R592_FIFO_DMA_SETTINGS_CAP); |
273 | } | 273 | } |
@@ -898,7 +898,7 @@ static void __exit r592_module_exit(void) | |||
898 | module_init(r592_module_init); | 898 | module_init(r592_module_init); |
899 | module_exit(r592_module_exit); | 899 | module_exit(r592_module_exit); |
900 | 900 | ||
901 | module_param(enable_dma, bool, S_IRUGO); | 901 | module_param_named(enable_dma, r592_enable_dma, bool, S_IRUGO); |
902 | MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); | 902 | MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); |
903 | module_param(debug, int, S_IRUGO | S_IWUSR); | 903 | module_param(debug, int, S_IRUGO | S_IWUSR); |
904 | MODULE_PARM_DESC(debug, "Debug level (0-3)"); | 904 | MODULE_PARM_DESC(debug, "Debug level (0-3)"); |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e986f91fff9c..e2fea580585a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -60,15 +60,6 @@ config MFD_ASIC3 | |||
60 | This driver supports the ASIC3 multifunction chip found on many | 60 | This driver supports the ASIC3 multifunction chip found on many |
61 | PDAs (mainly iPAQ and HTC based ones) | 61 | PDAs (mainly iPAQ and HTC based ones) |
62 | 62 | ||
63 | config MFD_SH_MOBILE_SDHI | ||
64 | bool "Support for SuperH Mobile SDHI" | ||
65 | depends on SUPERH || ARCH_SHMOBILE | ||
66 | select MFD_CORE | ||
67 | select TMIO_MMC_DMA | ||
68 | ---help--- | ||
69 | This driver supports the SDHI hardware block found in many | ||
70 | SuperH Mobile SoCs. | ||
71 | |||
72 | config MFD_DAVINCI_VOICECODEC | 63 | config MFD_DAVINCI_VOICECODEC |
73 | tristate | 64 | tristate |
74 | select MFD_CORE | 65 | select MFD_CORE |
@@ -266,11 +257,6 @@ config MFD_TMIO | |||
266 | bool | 257 | bool |
267 | default n | 258 | default n |
268 | 259 | ||
269 | config TMIO_MMC_DMA | ||
270 | bool | ||
271 | select DMA_ENGINE | ||
272 | select DMADEVICES | ||
273 | |||
274 | config MFD_T7L66XB | 260 | config MFD_T7L66XB |
275 | bool "Support Toshiba T7L66XB" | 261 | bool "Support Toshiba T7L66XB" |
276 | depends on ARM && HAVE_CLK | 262 | depends on ARM && HAVE_CLK |
@@ -592,7 +578,7 @@ config AB3550_CORE | |||
592 | config MFD_CS5535 | 578 | config MFD_CS5535 |
593 | tristate "Support for CS5535 and CS5536 southbridge core functions" | 579 | tristate "Support for CS5535 and CS5536 southbridge core functions" |
594 | select MFD_CORE | 580 | select MFD_CORE |
595 | depends on PCI | 581 | depends on PCI && X86 |
596 | ---help--- | 582 | ---help--- |
597 | This is the core driver for CS5535/CS5536 MFD functions. This is | 583 | This is the core driver for CS5535/CS5536 MFD functions. This is |
598 | necessary for using the board's GPIO and MFGPT functionality. | 584 | necessary for using the board's GPIO and MFGPT functionality. |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ef489f253402..419caa9d7dcf 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -6,7 +6,6 @@ | |||
6 | obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o | 6 | obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o |
7 | obj-$(CONFIG_MFD_SM501) += sm501.o | 7 | obj-$(CONFIG_MFD_SM501) += sm501.o |
8 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o | 8 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o |
9 | obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o | ||
10 | 9 | ||
11 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 10 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
12 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o | 11 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 62e33e2258d4..67d01c938284 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -362,6 +362,15 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) | |||
362 | } | 362 | } |
363 | } | 363 | } |
364 | 364 | ||
365 | static struct resource ab8500_gpio_resources[] = { | ||
366 | { | ||
367 | .name = "GPIO_INT6", | ||
368 | .start = AB8500_INT_GPIO6R, | ||
369 | .end = AB8500_INT_GPIO41F, | ||
370 | .flags = IORESOURCE_IRQ, | ||
371 | } | ||
372 | }; | ||
373 | |||
365 | static struct resource ab8500_gpadc_resources[] = { | 374 | static struct resource ab8500_gpadc_resources[] = { |
366 | { | 375 | { |
367 | .name = "HW_CONV_END", | 376 | .name = "HW_CONV_END", |
@@ -596,6 +605,11 @@ static struct mfd_cell ab8500_devs[] = { | |||
596 | .name = "ab8500-regulator", | 605 | .name = "ab8500-regulator", |
597 | }, | 606 | }, |
598 | { | 607 | { |
608 | .name = "ab8500-gpio", | ||
609 | .num_resources = ARRAY_SIZE(ab8500_gpio_resources), | ||
610 | .resources = ab8500_gpio_resources, | ||
611 | }, | ||
612 | { | ||
599 | .name = "ab8500-gpadc", | 613 | .name = "ab8500-gpadc", |
600 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), | 614 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), |
601 | .resources = ab8500_gpadc_resources, | 615 | .resources = ab8500_gpadc_resources, |
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c index 6820327adf4a..821e6b86afd2 100644 --- a/drivers/mfd/ab8500-i2c.c +++ b/drivers/mfd/ab8500-i2c.c | |||
@@ -97,7 +97,7 @@ static void __exit ab8500_i2c_exit(void) | |||
97 | { | 97 | { |
98 | platform_driver_unregister(&ab8500_i2c_driver); | 98 | platform_driver_unregister(&ab8500_i2c_driver); |
99 | } | 99 | } |
100 | subsys_initcall(ab8500_i2c_init); | 100 | arch_initcall(ab8500_i2c_init); |
101 | module_exit(ab8500_i2c_exit); | 101 | module_exit(ab8500_i2c_exit); |
102 | 102 | ||
103 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); | 103 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); |
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index 28852dfa310d..20e4e9395b61 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c | |||
@@ -373,7 +373,7 @@ static int gru_chiplet_setup_tlb_irq(int chiplet, char *irq_name, | |||
373 | 373 | ||
374 | if (gru_irq_count[chiplet] == 0) { | 374 | if (gru_irq_count[chiplet] == 0) { |
375 | gru_chip[chiplet].name = irq_name; | 375 | gru_chip[chiplet].name = irq_name; |
376 | ret = set_irq_chip(irq, &gru_chip[chiplet]); | 376 | ret = irq_set_chip(irq, &gru_chip[chiplet]); |
377 | if (ret) { | 377 | if (ret) { |
378 | printk(KERN_ERR "%s: set_irq_chip failed, errno=%d\n", | 378 | printk(KERN_ERR "%s: set_irq_chip failed, errno=%d\n", |
379 | GRU_DRIVER_ID_STR, -ret); | 379 | GRU_DRIVER_ID_STR, -ret); |
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 5ec8eddfcf6e..f5cedeccad42 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c | |||
@@ -1875,7 +1875,7 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write, | |||
1875 | unsigned int tot_sz, int max_scatter) | 1875 | unsigned int tot_sz, int max_scatter) |
1876 | { | 1876 | { |
1877 | unsigned int dev_addr, i, cnt, sz, ssz; | 1877 | unsigned int dev_addr, i, cnt, sz, ssz; |
1878 | struct timespec ts1, ts2, ts; | 1878 | struct timespec ts1, ts2; |
1879 | int ret; | 1879 | int ret; |
1880 | 1880 | ||
1881 | sz = test->area.max_tfr; | 1881 | sz = test->area.max_tfr; |
@@ -1912,7 +1912,6 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write, | |||
1912 | } | 1912 | } |
1913 | getnstimeofday(&ts2); | 1913 | getnstimeofday(&ts2); |
1914 | 1914 | ||
1915 | ts = timespec_sub(ts2, ts1); | ||
1916 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | 1915 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); |
1917 | 1916 | ||
1918 | return 0; | 1917 | return 0; |
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 797cdb5887fd..76af349c14b4 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * your option) any later version. | 9 | * your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/slab.h> | ||
12 | #include <linux/types.h> | 13 | #include <linux/types.h> |
13 | #include <linux/scatterlist.h> | 14 | #include <linux/scatterlist.h> |
14 | 15 | ||
@@ -252,6 +253,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | |||
252 | struct mmc_command cmd; | 253 | struct mmc_command cmd; |
253 | struct mmc_data data; | 254 | struct mmc_data data; |
254 | struct scatterlist sg; | 255 | struct scatterlist sg; |
256 | void *data_buf; | ||
255 | 257 | ||
256 | BUG_ON(!card); | 258 | BUG_ON(!card); |
257 | BUG_ON(!card->host); | 259 | BUG_ON(!card->host); |
@@ -263,6 +265,13 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | |||
263 | if (err) | 265 | if (err) |
264 | return err; | 266 | return err; |
265 | 267 | ||
268 | /* dma onto stack is unsafe/nonportable, but callers to this | ||
269 | * routine normally provide temporary on-stack buffers ... | ||
270 | */ | ||
271 | data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL); | ||
272 | if (data_buf == NULL) | ||
273 | return -ENOMEM; | ||
274 | |||
266 | memset(&mrq, 0, sizeof(struct mmc_request)); | 275 | memset(&mrq, 0, sizeof(struct mmc_request)); |
267 | memset(&cmd, 0, sizeof(struct mmc_command)); | 276 | memset(&cmd, 0, sizeof(struct mmc_command)); |
268 | memset(&data, 0, sizeof(struct mmc_data)); | 277 | memset(&data, 0, sizeof(struct mmc_data)); |
@@ -280,12 +289,15 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | |||
280 | data.sg = &sg; | 289 | data.sg = &sg; |
281 | data.sg_len = 1; | 290 | data.sg_len = 1; |
282 | 291 | ||
283 | sg_init_one(&sg, scr, 8); | 292 | sg_init_one(&sg, data_buf, 8); |
284 | 293 | ||
285 | mmc_set_data_timeout(&data, card); | 294 | mmc_set_data_timeout(&data, card); |
286 | 295 | ||
287 | mmc_wait_for_req(card->host, &mrq); | 296 | mmc_wait_for_req(card->host, &mrq); |
288 | 297 | ||
298 | memcpy(scr, data_buf, sizeof(card->raw_scr)); | ||
299 | kfree(data_buf); | ||
300 | |||
289 | if (cmd.error) | 301 | if (cmd.error) |
290 | return cmd.error; | 302 | return cmd.error; |
291 | if (data.error) | 303 | if (data.error) |
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 1a21c6427a19..94df40531c38 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
@@ -439,13 +439,25 @@ config MMC_SDRICOH_CS | |||
439 | To compile this driver as a module, choose M here: the | 439 | To compile this driver as a module, choose M here: the |
440 | module will be called sdricoh_cs. | 440 | module will be called sdricoh_cs. |
441 | 441 | ||
442 | config MMC_TMIO_CORE | ||
443 | tristate | ||
444 | |||
442 | config MMC_TMIO | 445 | config MMC_TMIO |
443 | tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" | 446 | tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" |
444 | depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI | 447 | depends on MFD_TMIO || MFD_ASIC3 |
448 | select MMC_TMIO_CORE | ||
445 | help | 449 | help |
446 | This provides support for the SD/MMC cell found in TC6393XB, | 450 | This provides support for the SD/MMC cell found in TC6393XB, |
447 | T7L66XB and also HTC ASIC3 | 451 | T7L66XB and also HTC ASIC3 |
448 | 452 | ||
453 | config MMC_SDHI | ||
454 | tristate "SH-Mobile SDHI SD/SDIO controller support" | ||
455 | depends on SUPERH || ARCH_SHMOBILE | ||
456 | select MMC_TMIO_CORE | ||
457 | help | ||
458 | This provides support for the SDHI SD/SDIO controller found in | ||
459 | SuperH and ARM SH-Mobile SoCs | ||
460 | |||
449 | config MMC_CB710 | 461 | config MMC_CB710 |
450 | tristate "ENE CB710 MMC/SD Interface support" | 462 | tristate "ENE CB710 MMC/SD Interface support" |
451 | depends on PCI | 463 | depends on PCI |
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 30aa6867745f..4f1df0aae574 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
@@ -29,7 +29,13 @@ endif | |||
29 | obj-$(CONFIG_MMC_S3C) += s3cmci.o | 29 | obj-$(CONFIG_MMC_S3C) += s3cmci.o |
30 | obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o | 30 | obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o |
31 | obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o | 31 | obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o |
32 | obj-$(CONFIG_MMC_CB710) += cb710-mmc.o | 32 | obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o |
33 | tmio_mmc_core-y := tmio_mmc_pio.o | ||
34 | ifneq ($(CONFIG_MMC_SDHI),n) | ||
35 | tmio_mmc_core-y += tmio_mmc_dma.o | ||
36 | endif | ||
37 | obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o | ||
38 | obj-$(CONFIG_MMC_CB710) += cb710-mmc.o | ||
33 | obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o | 39 | obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o |
34 | obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o | 40 | obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o |
35 | obj-$(CONFIG_MMC_DW) += dw_mmc.o | 41 | obj-$(CONFIG_MMC_DW) += dw_mmc.o |
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 5a614069cb00..87e1f57ec9ba 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c | |||
@@ -316,7 +316,7 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host) | |||
316 | 316 | ||
317 | /* Stop the IDMAC running */ | 317 | /* Stop the IDMAC running */ |
318 | temp = mci_readl(host, BMOD); | 318 | temp = mci_readl(host, BMOD); |
319 | temp &= ~SDMMC_IDMAC_ENABLE; | 319 | temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); |
320 | mci_writel(host, BMOD, temp); | 320 | mci_writel(host, BMOD, temp); |
321 | } | 321 | } |
322 | 322 | ||
@@ -385,7 +385,7 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) | |||
385 | 385 | ||
386 | /* Enable the IDMAC */ | 386 | /* Enable the IDMAC */ |
387 | temp = mci_readl(host, BMOD); | 387 | temp = mci_readl(host, BMOD); |
388 | temp |= SDMMC_IDMAC_ENABLE; | 388 | temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; |
389 | mci_writel(host, BMOD, temp); | 389 | mci_writel(host, BMOD, temp); |
390 | 390 | ||
391 | /* Start it running */ | 391 | /* Start it running */ |
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5bbb87d10251..b4a7e4fba90f 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
@@ -68,6 +68,12 @@ static struct variant_data variant_arm = { | |||
68 | .datalength_bits = 16, | 68 | .datalength_bits = 16, |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static struct variant_data variant_arm_extended_fifo = { | ||
72 | .fifosize = 128 * 4, | ||
73 | .fifohalfsize = 64 * 4, | ||
74 | .datalength_bits = 16, | ||
75 | }; | ||
76 | |||
71 | static struct variant_data variant_u300 = { | 77 | static struct variant_data variant_u300 = { |
72 | .fifosize = 16 * 4, | 78 | .fifosize = 16 * 4, |
73 | .fifohalfsize = 8 * 4, | 79 | .fifohalfsize = 8 * 4, |
@@ -1277,10 +1283,15 @@ static int mmci_resume(struct amba_device *dev) | |||
1277 | static struct amba_id mmci_ids[] = { | 1283 | static struct amba_id mmci_ids[] = { |
1278 | { | 1284 | { |
1279 | .id = 0x00041180, | 1285 | .id = 0x00041180, |
1280 | .mask = 0x000fffff, | 1286 | .mask = 0xff0fffff, |
1281 | .data = &variant_arm, | 1287 | .data = &variant_arm, |
1282 | }, | 1288 | }, |
1283 | { | 1289 | { |
1290 | .id = 0x01041180, | ||
1291 | .mask = 0xff0fffff, | ||
1292 | .data = &variant_arm_extended_fifo, | ||
1293 | }, | ||
1294 | { | ||
1284 | .id = 0x00041181, | 1295 | .id = 0x00041181, |
1285 | .mask = 0x000fffff, | 1296 | .mask = 0x000fffff, |
1286 | .data = &variant_arm, | 1297 | .data = &variant_arm, |
diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index 5530def54e5b..e2aecb7f1d5c 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c | |||
@@ -15,9 +15,11 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/irq.h> | ||
18 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
19 | #include <linux/of.h> | 20 | #include <linux/of.h> |
20 | #include <linux/of_gpio.h> | 21 | #include <linux/of_gpio.h> |
22 | #include <linux/of_irq.h> | ||
21 | #include <linux/spi/spi.h> | 23 | #include <linux/spi/spi.h> |
22 | #include <linux/spi/mmc_spi.h> | 24 | #include <linux/spi/mmc_spi.h> |
23 | #include <linux/mmc/core.h> | 25 | #include <linux/mmc/core.h> |
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 3b5248567973..a19967d0bfc4 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -16,14 +16,40 @@ | |||
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/gpio.h> | 18 | #include <linux/gpio.h> |
19 | #include <linux/slab.h> | ||
19 | #include <linux/mmc/host.h> | 20 | #include <linux/mmc/host.h> |
20 | #include <linux/mmc/sdhci-pltfm.h> | 21 | #include <linux/mmc/sdhci-pltfm.h> |
22 | #include <linux/mmc/mmc.h> | ||
23 | #include <linux/mmc/sdio.h> | ||
21 | #include <mach/hardware.h> | 24 | #include <mach/hardware.h> |
22 | #include <mach/esdhc.h> | 25 | #include <mach/esdhc.h> |
23 | #include "sdhci.h" | 26 | #include "sdhci.h" |
24 | #include "sdhci-pltfm.h" | 27 | #include "sdhci-pltfm.h" |
25 | #include "sdhci-esdhc.h" | 28 | #include "sdhci-esdhc.h" |
26 | 29 | ||
30 | /* VENDOR SPEC register */ | ||
31 | #define SDHCI_VENDOR_SPEC 0xC0 | ||
32 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 | ||
33 | |||
34 | #define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0) | ||
35 | /* | ||
36 | * The CMDTYPE of the CMD register (offset 0xE) should be set to | ||
37 | * "11" when the STOP CMD12 is issued on imx53 to abort one | ||
38 | * open ended multi-blk IO. Otherwise the TC INT wouldn't | ||
39 | * be generated. | ||
40 | * In exact block transfer, the controller doesn't complete the | ||
41 | * operations automatically as required at the end of the | ||
42 | * transfer and remains on hold if the abort command is not sent. | ||
43 | * As a result, the TC flag is not asserted and SW received timeout | ||
44 | * exeception. Bit1 of Vendor Spec registor is used to fix it. | ||
45 | */ | ||
46 | #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) | ||
47 | |||
48 | struct pltfm_imx_data { | ||
49 | int flags; | ||
50 | u32 scratchpad; | ||
51 | }; | ||
52 | |||
27 | static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) | 53 | static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) |
28 | { | 54 | { |
29 | void __iomem *base = host->ioaddr + (reg & ~0x3); | 55 | void __iomem *base = host->ioaddr + (reg & ~0x3); |
@@ -34,10 +60,14 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i | |||
34 | 60 | ||
35 | static u32 esdhc_readl_le(struct sdhci_host *host, int reg) | 61 | static u32 esdhc_readl_le(struct sdhci_host *host, int reg) |
36 | { | 62 | { |
63 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | ||
64 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | ||
65 | |||
37 | /* fake CARD_PRESENT flag on mx25/35 */ | 66 | /* fake CARD_PRESENT flag on mx25/35 */ |
38 | u32 val = readl(host->ioaddr + reg); | 67 | u32 val = readl(host->ioaddr + reg); |
39 | 68 | ||
40 | if (unlikely(reg == SDHCI_PRESENT_STATE)) { | 69 | if (unlikely((reg == SDHCI_PRESENT_STATE) |
70 | && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) { | ||
41 | struct esdhc_platform_data *boarddata = | 71 | struct esdhc_platform_data *boarddata = |
42 | host->mmc->parent->platform_data; | 72 | host->mmc->parent->platform_data; |
43 | 73 | ||
@@ -55,13 +85,26 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) | |||
55 | 85 | ||
56 | static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) | 86 | static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) |
57 | { | 87 | { |
58 | if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) | 88 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
89 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | ||
90 | |||
91 | if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE) | ||
92 | && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) | ||
59 | /* | 93 | /* |
60 | * these interrupts won't work with a custom card_detect gpio | 94 | * these interrupts won't work with a custom card_detect gpio |
61 | * (only applied to mx25/35) | 95 | * (only applied to mx25/35) |
62 | */ | 96 | */ |
63 | val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); | 97 | val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); |
64 | 98 | ||
99 | if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) | ||
100 | && (reg == SDHCI_INT_STATUS) | ||
101 | && (val & SDHCI_INT_DATA_END))) { | ||
102 | u32 v; | ||
103 | v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); | ||
104 | v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; | ||
105 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | ||
106 | } | ||
107 | |||
65 | writel(val, host->ioaddr + reg); | 108 | writel(val, host->ioaddr + reg); |
66 | } | 109 | } |
67 | 110 | ||
@@ -76,6 +119,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) | |||
76 | static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | 119 | static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) |
77 | { | 120 | { |
78 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 121 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
122 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | ||
79 | 123 | ||
80 | switch (reg) { | 124 | switch (reg) { |
81 | case SDHCI_TRANSFER_MODE: | 125 | case SDHCI_TRANSFER_MODE: |
@@ -83,10 +127,22 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |||
83 | * Postpone this write, we must do it together with a | 127 | * Postpone this write, we must do it together with a |
84 | * command write that is down below. | 128 | * command write that is down below. |
85 | */ | 129 | */ |
86 | pltfm_host->scratchpad = val; | 130 | if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) |
131 | && (host->cmd->opcode == SD_IO_RW_EXTENDED) | ||
132 | && (host->cmd->data->blocks > 1) | ||
133 | && (host->cmd->data->flags & MMC_DATA_READ)) { | ||
134 | u32 v; | ||
135 | v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); | ||
136 | v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; | ||
137 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | ||
138 | } | ||
139 | imx_data->scratchpad = val; | ||
87 | return; | 140 | return; |
88 | case SDHCI_COMMAND: | 141 | case SDHCI_COMMAND: |
89 | writel(val << 16 | pltfm_host->scratchpad, | 142 | if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) |
143 | && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) | ||
144 | val |= SDHCI_CMD_ABORTCMD; | ||
145 | writel(val << 16 | imx_data->scratchpad, | ||
90 | host->ioaddr + SDHCI_TRANSFER_MODE); | 146 | host->ioaddr + SDHCI_TRANSFER_MODE); |
91 | return; | 147 | return; |
92 | case SDHCI_BLOCK_SIZE: | 148 | case SDHCI_BLOCK_SIZE: |
@@ -146,7 +202,9 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) | |||
146 | } | 202 | } |
147 | 203 | ||
148 | static struct sdhci_ops sdhci_esdhc_ops = { | 204 | static struct sdhci_ops sdhci_esdhc_ops = { |
205 | .read_l = esdhc_readl_le, | ||
149 | .read_w = esdhc_readw_le, | 206 | .read_w = esdhc_readw_le, |
207 | .write_l = esdhc_writel_le, | ||
150 | .write_w = esdhc_writew_le, | 208 | .write_w = esdhc_writew_le, |
151 | .write_b = esdhc_writeb_le, | 209 | .write_b = esdhc_writeb_le, |
152 | .set_clock = esdhc_set_clock, | 210 | .set_clock = esdhc_set_clock, |
@@ -168,6 +226,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
168 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | 226 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; |
169 | struct clk *clk; | 227 | struct clk *clk; |
170 | int err; | 228 | int err; |
229 | struct pltfm_imx_data *imx_data; | ||
171 | 230 | ||
172 | clk = clk_get(mmc_dev(host->mmc), NULL); | 231 | clk = clk_get(mmc_dev(host->mmc), NULL); |
173 | if (IS_ERR(clk)) { | 232 | if (IS_ERR(clk)) { |
@@ -177,7 +236,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
177 | clk_enable(clk); | 236 | clk_enable(clk); |
178 | pltfm_host->clk = clk; | 237 | pltfm_host->clk = clk; |
179 | 238 | ||
180 | if (cpu_is_mx35() || cpu_is_mx51()) | 239 | imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); |
240 | if (!imx_data) { | ||
241 | clk_disable(pltfm_host->clk); | ||
242 | clk_put(pltfm_host->clk); | ||
243 | return -ENOMEM; | ||
244 | } | ||
245 | pltfm_host->priv = imx_data; | ||
246 | |||
247 | if (!cpu_is_mx25()) | ||
181 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; | 248 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; |
182 | 249 | ||
183 | if (cpu_is_mx25() || cpu_is_mx35()) { | 250 | if (cpu_is_mx25() || cpu_is_mx35()) { |
@@ -187,6 +254,9 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
187 | sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; | 254 | sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; |
188 | } | 255 | } |
189 | 256 | ||
257 | if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())) | ||
258 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; | ||
259 | |||
190 | if (boarddata) { | 260 | if (boarddata) { |
191 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); | 261 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); |
192 | if (err) { | 262 | if (err) { |
@@ -214,8 +284,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
214 | goto no_card_detect_irq; | 284 | goto no_card_detect_irq; |
215 | } | 285 | } |
216 | 286 | ||
217 | sdhci_esdhc_ops.write_l = esdhc_writel_le; | 287 | imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP; |
218 | sdhci_esdhc_ops.read_l = esdhc_readl_le; | ||
219 | /* Now we have a working card_detect again */ | 288 | /* Now we have a working card_detect again */ |
220 | host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; | 289 | host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; |
221 | } | 290 | } |
@@ -227,6 +296,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
227 | no_card_detect_pin: | 296 | no_card_detect_pin: |
228 | boarddata->cd_gpio = err; | 297 | boarddata->cd_gpio = err; |
229 | not_supported: | 298 | not_supported: |
299 | kfree(imx_data); | ||
230 | return 0; | 300 | return 0; |
231 | } | 301 | } |
232 | 302 | ||
@@ -234,6 +304,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) | |||
234 | { | 304 | { |
235 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 305 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
236 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | 306 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; |
307 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | ||
237 | 308 | ||
238 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) | 309 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) |
239 | gpio_free(boarddata->wp_gpio); | 310 | gpio_free(boarddata->wp_gpio); |
@@ -247,6 +318,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) | |||
247 | 318 | ||
248 | clk_disable(pltfm_host->clk); | 319 | clk_disable(pltfm_host->clk); |
249 | clk_put(pltfm_host->clk); | 320 | clk_put(pltfm_host->clk); |
321 | kfree(imx_data); | ||
250 | } | 322 | } |
251 | 323 | ||
252 | struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | 324 | struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { |
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index c55aae828aac..c3b08f111942 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h | |||
@@ -23,8 +23,7 @@ | |||
23 | SDHCI_QUIRK_NONSTANDARD_CLOCK | \ | 23 | SDHCI_QUIRK_NONSTANDARD_CLOCK | \ |
24 | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ | 24 | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ |
25 | SDHCI_QUIRK_PIO_NEEDS_DELAY | \ | 25 | SDHCI_QUIRK_PIO_NEEDS_DELAY | \ |
26 | SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | \ | 26 | SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) |
27 | SDHCI_QUIRK_NO_CARD_NO_RESET) | ||
28 | 27 | ||
29 | #define ESDHC_SYSTEM_CONTROL 0x2c | 28 | #define ESDHC_SYSTEM_CONTROL 0x2c |
30 | #define ESDHC_CLOCK_MASK 0x0000fff0 | 29 | #define ESDHC_CLOCK_MASK 0x0000fff0 |
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 08161f690ae8..ba40d6d035c7 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c | |||
@@ -74,7 +74,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) | |||
74 | 74 | ||
75 | struct sdhci_of_data sdhci_esdhc = { | 75 | struct sdhci_of_data sdhci_esdhc = { |
76 | /* card detection could be handled via GPIO */ | 76 | /* card detection could be handled via GPIO */ |
77 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION, | 77 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION |
78 | | SDHCI_QUIRK_NO_CARD_NO_RESET, | ||
78 | .ops = { | 79 | .ops = { |
79 | .read_l = sdhci_be32bs_readl, | 80 | .read_l = sdhci_be32bs_readl, |
80 | .read_w = esdhc_readw, | 81 | .read_w = esdhc_readw, |
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 2f8d46854acd..a136be706347 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
@@ -1016,16 +1016,14 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, | |||
1016 | struct sdhci_pci_chip *chip; | 1016 | struct sdhci_pci_chip *chip; |
1017 | struct sdhci_pci_slot *slot; | 1017 | struct sdhci_pci_slot *slot; |
1018 | 1018 | ||
1019 | u8 slots, rev, first_bar; | 1019 | u8 slots, first_bar; |
1020 | int ret, i; | 1020 | int ret, i; |
1021 | 1021 | ||
1022 | BUG_ON(pdev == NULL); | 1022 | BUG_ON(pdev == NULL); |
1023 | BUG_ON(ent == NULL); | 1023 | BUG_ON(ent == NULL); |
1024 | 1024 | ||
1025 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); | ||
1026 | |||
1027 | dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", | 1025 | dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", |
1028 | (int)pdev->vendor, (int)pdev->device, (int)rev); | 1026 | (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); |
1029 | 1027 | ||
1030 | ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); | 1028 | ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); |
1031 | if (ret) | 1029 | if (ret) |
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index ea2e44d9be5e..2b37016ad0ac 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | struct sdhci_pltfm_host { | 18 | struct sdhci_pltfm_host { |
19 | struct clk *clk; | 19 | struct clk *clk; |
20 | u32 scratchpad; /* to handle quirks across io-accessor calls */ | 20 | void *priv; /* to handle quirks across io-accessor calls */ |
21 | }; | 21 | }; |
22 | 22 | ||
23 | extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; | 23 | extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; |
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index d70c54c7b70a..60a4c97d3d18 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c | |||
@@ -50,7 +50,7 @@ static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) | |||
50 | /* val == 1 -> card removed, val == 0 -> card inserted */ | 50 | /* val == 1 -> card removed, val == 0 -> card inserted */ |
51 | /* if card removed - set irq for low level, else vice versa */ | 51 | /* if card removed - set irq for low level, else vice versa */ |
52 | gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; | 52 | gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; |
53 | set_irq_type(irq, gpio_irq_type); | 53 | irq_set_irq_type(irq, gpio_irq_type); |
54 | 54 | ||
55 | if (sdhci->data->card_power_gpio >= 0) { | 55 | if (sdhci->data->card_power_gpio >= 0) { |
56 | if (!sdhci->data->power_always_enb) { | 56 | if (!sdhci->data->power_always_enb) { |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 6e0969e40650..25e8bde600d1 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
@@ -45,6 +45,7 @@ | |||
45 | #define SDHCI_CMD_CRC 0x08 | 45 | #define SDHCI_CMD_CRC 0x08 |
46 | #define SDHCI_CMD_INDEX 0x10 | 46 | #define SDHCI_CMD_INDEX 0x10 |
47 | #define SDHCI_CMD_DATA 0x20 | 47 | #define SDHCI_CMD_DATA 0x20 |
48 | #define SDHCI_CMD_ABORTCMD 0xC0 | ||
48 | 49 | ||
49 | #define SDHCI_CMD_RESP_NONE 0x00 | 50 | #define SDHCI_CMD_RESP_NONE 0x00 |
50 | #define SDHCI_CMD_RESP_LONG 0x01 | 51 | #define SDHCI_CMD_RESP_LONG 0x01 |
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 53a63024bf11..cc701236d16f 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c | |||
@@ -23,51 +23,30 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/mmc/host.h> | 25 | #include <linux/mmc/host.h> |
26 | #include <linux/mfd/core.h> | 26 | #include <linux/mmc/sh_mobile_sdhi.h> |
27 | #include <linux/mfd/tmio.h> | 27 | #include <linux/mfd/tmio.h> |
28 | #include <linux/mfd/sh_mobile_sdhi.h> | ||
29 | #include <linux/sh_dma.h> | 28 | #include <linux/sh_dma.h> |
30 | 29 | ||
30 | #include "tmio_mmc.h" | ||
31 | |||
31 | struct sh_mobile_sdhi { | 32 | struct sh_mobile_sdhi { |
32 | struct clk *clk; | 33 | struct clk *clk; |
33 | struct tmio_mmc_data mmc_data; | 34 | struct tmio_mmc_data mmc_data; |
34 | struct mfd_cell cell_mmc; | ||
35 | struct sh_dmae_slave param_tx; | 35 | struct sh_dmae_slave param_tx; |
36 | struct sh_dmae_slave param_rx; | 36 | struct sh_dmae_slave param_rx; |
37 | struct tmio_mmc_dma dma_priv; | 37 | struct tmio_mmc_dma dma_priv; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static struct resource sh_mobile_sdhi_resources[] = { | 40 | static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state) |
41 | { | ||
42 | .start = 0x000, | ||
43 | .end = 0x1ff, | ||
44 | .flags = IORESOURCE_MEM, | ||
45 | }, | ||
46 | { | ||
47 | .start = 0, | ||
48 | .end = 0, | ||
49 | .flags = IORESOURCE_IRQ, | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | static struct mfd_cell sh_mobile_sdhi_cell = { | ||
54 | .name = "tmio-mmc", | ||
55 | .num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources), | ||
56 | .resources = sh_mobile_sdhi_resources, | ||
57 | }; | ||
58 | |||
59 | static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state) | ||
60 | { | 41 | { |
61 | struct platform_device *pdev = to_platform_device(tmio->dev.parent); | ||
62 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | 42 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; |
63 | 43 | ||
64 | if (p && p->set_pwr) | 44 | if (p && p->set_pwr) |
65 | p->set_pwr(pdev, state); | 45 | p->set_pwr(pdev, state); |
66 | } | 46 | } |
67 | 47 | ||
68 | static int sh_mobile_sdhi_get_cd(struct platform_device *tmio) | 48 | static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) |
69 | { | 49 | { |
70 | struct platform_device *pdev = to_platform_device(tmio->dev.parent); | ||
71 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | 50 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; |
72 | 51 | ||
73 | if (p && p->get_cd) | 52 | if (p && p->get_cd) |
@@ -81,20 +60,9 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
81 | struct sh_mobile_sdhi *priv; | 60 | struct sh_mobile_sdhi *priv; |
82 | struct tmio_mmc_data *mmc_data; | 61 | struct tmio_mmc_data *mmc_data; |
83 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | 62 | struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; |
84 | struct resource *mem; | 63 | struct tmio_mmc_host *host; |
85 | char clk_name[8]; | 64 | char clk_name[8]; |
86 | int ret, irq; | 65 | int ret; |
87 | |||
88 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
89 | if (!mem) | ||
90 | dev_err(&pdev->dev, "missing MEM resource\n"); | ||
91 | |||
92 | irq = platform_get_irq(pdev, 0); | ||
93 | if (irq < 0) | ||
94 | dev_err(&pdev->dev, "missing IRQ resource\n"); | ||
95 | |||
96 | if (!mem || (irq < 0)) | ||
97 | return -EINVAL; | ||
98 | 66 | ||
99 | priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); | 67 | priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); |
100 | if (priv == NULL) { | 68 | if (priv == NULL) { |
@@ -109,8 +77,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
109 | if (IS_ERR(priv->clk)) { | 77 | if (IS_ERR(priv->clk)) { |
110 | dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); | 78 | dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); |
111 | ret = PTR_ERR(priv->clk); | 79 | ret = PTR_ERR(priv->clk); |
112 | kfree(priv); | 80 | goto eclkget; |
113 | return ret; | ||
114 | } | 81 | } |
115 | 82 | ||
116 | clk_enable(priv->clk); | 83 | clk_enable(priv->clk); |
@@ -123,6 +90,15 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
123 | mmc_data->flags = p->tmio_flags; | 90 | mmc_data->flags = p->tmio_flags; |
124 | mmc_data->ocr_mask = p->tmio_ocr_mask; | 91 | mmc_data->ocr_mask = p->tmio_ocr_mask; |
125 | mmc_data->capabilities |= p->tmio_caps; | 92 | mmc_data->capabilities |= p->tmio_caps; |
93 | |||
94 | if (p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { | ||
95 | priv->param_tx.slave_id = p->dma_slave_tx; | ||
96 | priv->param_rx.slave_id = p->dma_slave_rx; | ||
97 | priv->dma_priv.chan_priv_tx = &priv->param_tx; | ||
98 | priv->dma_priv.chan_priv_rx = &priv->param_rx; | ||
99 | priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ | ||
100 | mmc_data->dma = &priv->dma_priv; | ||
101 | } | ||
126 | } | 102 | } |
127 | 103 | ||
128 | /* | 104 | /* |
@@ -136,36 +112,30 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
136 | */ | 112 | */ |
137 | mmc_data->flags |= TMIO_MMC_SDIO_IRQ; | 113 | mmc_data->flags |= TMIO_MMC_SDIO_IRQ; |
138 | 114 | ||
139 | if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { | 115 | ret = tmio_mmc_host_probe(&host, pdev, mmc_data); |
140 | priv->param_tx.slave_id = p->dma_slave_tx; | 116 | if (ret < 0) |
141 | priv->param_rx.slave_id = p->dma_slave_rx; | 117 | goto eprobe; |
142 | priv->dma_priv.chan_priv_tx = &priv->param_tx; | ||
143 | priv->dma_priv.chan_priv_rx = &priv->param_rx; | ||
144 | priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ | ||
145 | mmc_data->dma = &priv->dma_priv; | ||
146 | } | ||
147 | 118 | ||
148 | memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); | 119 | pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), |
149 | priv->cell_mmc.mfd_data = mmc_data; | 120 | (unsigned long)host->ctl, host->irq); |
150 | 121 | ||
151 | platform_set_drvdata(pdev, priv); | 122 | return ret; |
152 | |||
153 | ret = mfd_add_devices(&pdev->dev, pdev->id, | ||
154 | &priv->cell_mmc, 1, mem, irq); | ||
155 | if (ret) { | ||
156 | clk_disable(priv->clk); | ||
157 | clk_put(priv->clk); | ||
158 | kfree(priv); | ||
159 | } | ||
160 | 123 | ||
124 | eprobe: | ||
125 | clk_disable(priv->clk); | ||
126 | clk_put(priv->clk); | ||
127 | eclkget: | ||
128 | kfree(priv); | ||
161 | return ret; | 129 | return ret; |
162 | } | 130 | } |
163 | 131 | ||
164 | static int sh_mobile_sdhi_remove(struct platform_device *pdev) | 132 | static int sh_mobile_sdhi_remove(struct platform_device *pdev) |
165 | { | 133 | { |
166 | struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev); | 134 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
135 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
136 | struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); | ||
167 | 137 | ||
168 | mfd_remove_devices(&pdev->dev); | 138 | tmio_mmc_host_remove(host); |
169 | clk_disable(priv->clk); | 139 | clk_disable(priv->clk); |
170 | clk_put(priv->clk); | 140 | clk_put(priv->clk); |
171 | kfree(priv); | 141 | kfree(priv); |
@@ -198,3 +168,4 @@ module_exit(sh_mobile_sdhi_exit); | |||
198 | MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); | 168 | MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); |
199 | MODULE_AUTHOR("Magnus Damm"); | 169 | MODULE_AUTHOR("Magnus Damm"); |
200 | MODULE_LICENSE("GPL v2"); | 170 | MODULE_LICENSE("GPL v2"); |
171 | MODULE_ALIAS("platform:sh_mobile_sdhi"); | ||
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index ab1adeabdd22..79c568461d59 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/mmc/tmio_mmc.c | 2 | * linux/drivers/mmc/host/tmio_mmc.c |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Ian Molton | 4 | * Copyright (C) 2007 Ian Molton |
5 | * Copyright (C) 2007 Ian Molton | 5 | * Copyright (C) 2004 Ian Molton |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -11,1182 +11,17 @@ | |||
11 | * Driver for the MMC / SD / SDIO cell found in: | 11 | * Driver for the MMC / SD / SDIO cell found in: |
12 | * | 12 | * |
13 | * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 | 13 | * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 |
14 | * | ||
15 | * This driver draws mainly on scattered spec sheets, Reverse engineering | ||
16 | * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit | ||
17 | * support). (Further 4 bit support from a later datasheet). | ||
18 | * | ||
19 | * TODO: | ||
20 | * Investigate using a workqueue for PIO transfers | ||
21 | * Eliminate FIXMEs | ||
22 | * SDIO support | ||
23 | * Better Power management | ||
24 | * Handle MMC errors better | ||
25 | * double buffer support | ||
26 | * | ||
27 | */ | 14 | */ |
28 | 15 | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/device.h> | 16 | #include <linux/device.h> |
31 | #include <linux/dmaengine.h> | ||
32 | #include <linux/highmem.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/io.h> | ||
35 | #include <linux/irq.h> | ||
36 | #include <linux/mfd/core.h> | 17 | #include <linux/mfd/core.h> |
37 | #include <linux/mfd/tmio.h> | 18 | #include <linux/mfd/tmio.h> |
38 | #include <linux/mmc/host.h> | 19 | #include <linux/mmc/host.h> |
39 | #include <linux/module.h> | 20 | #include <linux/module.h> |
40 | #include <linux/pagemap.h> | 21 | #include <linux/pagemap.h> |
41 | #include <linux/scatterlist.h> | 22 | #include <linux/scatterlist.h> |
42 | #include <linux/workqueue.h> | ||
43 | #include <linux/spinlock.h> | ||
44 | |||
45 | #define CTL_SD_CMD 0x00 | ||
46 | #define CTL_ARG_REG 0x04 | ||
47 | #define CTL_STOP_INTERNAL_ACTION 0x08 | ||
48 | #define CTL_XFER_BLK_COUNT 0xa | ||
49 | #define CTL_RESPONSE 0x0c | ||
50 | #define CTL_STATUS 0x1c | ||
51 | #define CTL_IRQ_MASK 0x20 | ||
52 | #define CTL_SD_CARD_CLK_CTL 0x24 | ||
53 | #define CTL_SD_XFER_LEN 0x26 | ||
54 | #define CTL_SD_MEM_CARD_OPT 0x28 | ||
55 | #define CTL_SD_ERROR_DETAIL_STATUS 0x2c | ||
56 | #define CTL_SD_DATA_PORT 0x30 | ||
57 | #define CTL_TRANSACTION_CTL 0x34 | ||
58 | #define CTL_SDIO_STATUS 0x36 | ||
59 | #define CTL_SDIO_IRQ_MASK 0x38 | ||
60 | #define CTL_RESET_SD 0xe0 | ||
61 | #define CTL_SDIO_REGS 0x100 | ||
62 | #define CTL_CLK_AND_WAIT_CTL 0x138 | ||
63 | #define CTL_RESET_SDIO 0x1e0 | ||
64 | |||
65 | /* Definitions for values the CTRL_STATUS register can take. */ | ||
66 | #define TMIO_STAT_CMDRESPEND 0x00000001 | ||
67 | #define TMIO_STAT_DATAEND 0x00000004 | ||
68 | #define TMIO_STAT_CARD_REMOVE 0x00000008 | ||
69 | #define TMIO_STAT_CARD_INSERT 0x00000010 | ||
70 | #define TMIO_STAT_SIGSTATE 0x00000020 | ||
71 | #define TMIO_STAT_WRPROTECT 0x00000080 | ||
72 | #define TMIO_STAT_CARD_REMOVE_A 0x00000100 | ||
73 | #define TMIO_STAT_CARD_INSERT_A 0x00000200 | ||
74 | #define TMIO_STAT_SIGSTATE_A 0x00000400 | ||
75 | #define TMIO_STAT_CMD_IDX_ERR 0x00010000 | ||
76 | #define TMIO_STAT_CRCFAIL 0x00020000 | ||
77 | #define TMIO_STAT_STOPBIT_ERR 0x00040000 | ||
78 | #define TMIO_STAT_DATATIMEOUT 0x00080000 | ||
79 | #define TMIO_STAT_RXOVERFLOW 0x00100000 | ||
80 | #define TMIO_STAT_TXUNDERRUN 0x00200000 | ||
81 | #define TMIO_STAT_CMDTIMEOUT 0x00400000 | ||
82 | #define TMIO_STAT_RXRDY 0x01000000 | ||
83 | #define TMIO_STAT_TXRQ 0x02000000 | ||
84 | #define TMIO_STAT_ILL_FUNC 0x20000000 | ||
85 | #define TMIO_STAT_CMD_BUSY 0x40000000 | ||
86 | #define TMIO_STAT_ILL_ACCESS 0x80000000 | ||
87 | |||
88 | /* Definitions for values the CTRL_SDIO_STATUS register can take. */ | ||
89 | #define TMIO_SDIO_STAT_IOIRQ 0x0001 | ||
90 | #define TMIO_SDIO_STAT_EXPUB52 0x4000 | ||
91 | #define TMIO_SDIO_STAT_EXWT 0x8000 | ||
92 | #define TMIO_SDIO_MASK_ALL 0xc007 | ||
93 | |||
94 | /* Define some IRQ masks */ | ||
95 | /* This is the mask used at reset by the chip */ | ||
96 | #define TMIO_MASK_ALL 0x837f031d | ||
97 | #define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) | ||
98 | #define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) | ||
99 | #define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ | ||
100 | TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) | ||
101 | #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) | ||
102 | |||
103 | #define enable_mmc_irqs(host, i) \ | ||
104 | do { \ | ||
105 | u32 mask;\ | ||
106 | mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ | ||
107 | mask &= ~((i) & TMIO_MASK_IRQ); \ | ||
108 | sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ | ||
109 | } while (0) | ||
110 | |||
111 | #define disable_mmc_irqs(host, i) \ | ||
112 | do { \ | ||
113 | u32 mask;\ | ||
114 | mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ | ||
115 | mask |= ((i) & TMIO_MASK_IRQ); \ | ||
116 | sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ | ||
117 | } while (0) | ||
118 | |||
119 | #define ack_mmc_irqs(host, i) \ | ||
120 | do { \ | ||
121 | sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ | ||
122 | } while (0) | ||
123 | |||
124 | /* This is arbitrary, just noone needed any higher alignment yet */ | ||
125 | #define MAX_ALIGN 4 | ||
126 | |||
127 | struct tmio_mmc_host { | ||
128 | void __iomem *ctl; | ||
129 | unsigned long bus_shift; | ||
130 | struct mmc_command *cmd; | ||
131 | struct mmc_request *mrq; | ||
132 | struct mmc_data *data; | ||
133 | struct mmc_host *mmc; | ||
134 | int irq; | ||
135 | unsigned int sdio_irq_enabled; | ||
136 | |||
137 | /* Callbacks for clock / power control */ | ||
138 | void (*set_pwr)(struct platform_device *host, int state); | ||
139 | void (*set_clk_div)(struct platform_device *host, int state); | ||
140 | |||
141 | /* pio related stuff */ | ||
142 | struct scatterlist *sg_ptr; | ||
143 | struct scatterlist *sg_orig; | ||
144 | unsigned int sg_len; | ||
145 | unsigned int sg_off; | ||
146 | |||
147 | struct platform_device *pdev; | ||
148 | |||
149 | /* DMA support */ | ||
150 | struct dma_chan *chan_rx; | ||
151 | struct dma_chan *chan_tx; | ||
152 | struct tasklet_struct dma_complete; | ||
153 | struct tasklet_struct dma_issue; | ||
154 | #ifdef CONFIG_TMIO_MMC_DMA | ||
155 | u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN))); | ||
156 | struct scatterlist bounce_sg; | ||
157 | #endif | ||
158 | |||
159 | /* Track lost interrupts */ | ||
160 | struct delayed_work delayed_reset_work; | ||
161 | spinlock_t lock; | ||
162 | unsigned long last_req_ts; | ||
163 | }; | ||
164 | |||
165 | static void tmio_check_bounce_buffer(struct tmio_mmc_host *host); | ||
166 | |||
167 | static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) | ||
168 | { | ||
169 | return readw(host->ctl + (addr << host->bus_shift)); | ||
170 | } | ||
171 | |||
172 | static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, | ||
173 | u16 *buf, int count) | ||
174 | { | ||
175 | readsw(host->ctl + (addr << host->bus_shift), buf, count); | ||
176 | } | ||
177 | |||
178 | static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) | ||
179 | { | ||
180 | return readw(host->ctl + (addr << host->bus_shift)) | | ||
181 | readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; | ||
182 | } | ||
183 | |||
184 | static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) | ||
185 | { | ||
186 | writew(val, host->ctl + (addr << host->bus_shift)); | ||
187 | } | ||
188 | |||
189 | static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, | ||
190 | u16 *buf, int count) | ||
191 | { | ||
192 | writesw(host->ctl + (addr << host->bus_shift), buf, count); | ||
193 | } | ||
194 | |||
195 | static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) | ||
196 | { | ||
197 | writew(val, host->ctl + (addr << host->bus_shift)); | ||
198 | writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); | ||
199 | } | ||
200 | |||
201 | static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) | ||
202 | { | ||
203 | host->sg_len = data->sg_len; | ||
204 | host->sg_ptr = data->sg; | ||
205 | host->sg_orig = data->sg; | ||
206 | host->sg_off = 0; | ||
207 | } | ||
208 | |||
209 | static int tmio_mmc_next_sg(struct tmio_mmc_host *host) | ||
210 | { | ||
211 | host->sg_ptr = sg_next(host->sg_ptr); | ||
212 | host->sg_off = 0; | ||
213 | return --host->sg_len; | ||
214 | } | ||
215 | |||
216 | static char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) | ||
217 | { | ||
218 | local_irq_save(*flags); | ||
219 | return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; | ||
220 | } | ||
221 | |||
222 | static void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) | ||
223 | { | ||
224 | kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); | ||
225 | local_irq_restore(*flags); | ||
226 | } | ||
227 | |||
228 | #ifdef CONFIG_MMC_DEBUG | ||
229 | |||
230 | #define STATUS_TO_TEXT(a, status, i) \ | ||
231 | do { \ | ||
232 | if (status & TMIO_STAT_##a) { \ | ||
233 | if (i++) \ | ||
234 | printk(" | "); \ | ||
235 | printk(#a); \ | ||
236 | } \ | ||
237 | } while (0) | ||
238 | |||
239 | void pr_debug_status(u32 status) | ||
240 | { | ||
241 | int i = 0; | ||
242 | printk(KERN_DEBUG "status: %08x = ", status); | ||
243 | STATUS_TO_TEXT(CARD_REMOVE, status, i); | ||
244 | STATUS_TO_TEXT(CARD_INSERT, status, i); | ||
245 | STATUS_TO_TEXT(SIGSTATE, status, i); | ||
246 | STATUS_TO_TEXT(WRPROTECT, status, i); | ||
247 | STATUS_TO_TEXT(CARD_REMOVE_A, status, i); | ||
248 | STATUS_TO_TEXT(CARD_INSERT_A, status, i); | ||
249 | STATUS_TO_TEXT(SIGSTATE_A, status, i); | ||
250 | STATUS_TO_TEXT(CMD_IDX_ERR, status, i); | ||
251 | STATUS_TO_TEXT(STOPBIT_ERR, status, i); | ||
252 | STATUS_TO_TEXT(ILL_FUNC, status, i); | ||
253 | STATUS_TO_TEXT(CMD_BUSY, status, i); | ||
254 | STATUS_TO_TEXT(CMDRESPEND, status, i); | ||
255 | STATUS_TO_TEXT(DATAEND, status, i); | ||
256 | STATUS_TO_TEXT(CRCFAIL, status, i); | ||
257 | STATUS_TO_TEXT(DATATIMEOUT, status, i); | ||
258 | STATUS_TO_TEXT(CMDTIMEOUT, status, i); | ||
259 | STATUS_TO_TEXT(RXOVERFLOW, status, i); | ||
260 | STATUS_TO_TEXT(TXUNDERRUN, status, i); | ||
261 | STATUS_TO_TEXT(RXRDY, status, i); | ||
262 | STATUS_TO_TEXT(TXRQ, status, i); | ||
263 | STATUS_TO_TEXT(ILL_ACCESS, status, i); | ||
264 | printk("\n"); | ||
265 | } | ||
266 | |||
267 | #else | ||
268 | #define pr_debug_status(s) do { } while (0) | ||
269 | #endif | ||
270 | |||
271 | static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
272 | { | ||
273 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
274 | |||
275 | if (enable) { | ||
276 | host->sdio_irq_enabled = 1; | ||
277 | sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); | ||
278 | sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, | ||
279 | (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); | ||
280 | } else { | ||
281 | sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); | ||
282 | sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); | ||
283 | host->sdio_irq_enabled = 0; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) | ||
288 | { | ||
289 | u32 clk = 0, clock; | ||
290 | |||
291 | if (new_clock) { | ||
292 | for (clock = host->mmc->f_min, clk = 0x80000080; | ||
293 | new_clock >= (clock<<1); clk >>= 1) | ||
294 | clock <<= 1; | ||
295 | clk |= 0x100; | ||
296 | } | ||
297 | |||
298 | if (host->set_clk_div) | ||
299 | host->set_clk_div(host->pdev, (clk>>22) & 1); | ||
300 | |||
301 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); | ||
302 | } | ||
303 | |||
304 | static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) | ||
305 | { | ||
306 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
307 | |||
308 | /* | ||
309 | * Testing on sh-mobile showed that SDIO IRQs are unmasked when | ||
310 | * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the | ||
311 | * device IRQ here and restore the SDIO IRQ mask before | ||
312 | * re-enabling the device IRQ. | ||
313 | */ | ||
314 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||
315 | disable_irq(host->irq); | ||
316 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); | ||
317 | msleep(10); | ||
318 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||
319 | tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); | ||
320 | enable_irq(host->irq); | ||
321 | } | ||
322 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & | ||
323 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | ||
324 | msleep(10); | ||
325 | } | ||
326 | |||
327 | static void tmio_mmc_clk_start(struct tmio_mmc_host *host) | ||
328 | { | ||
329 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
330 | |||
331 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | | ||
332 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | ||
333 | msleep(10); | ||
334 | /* see comment in tmio_mmc_clk_stop above */ | ||
335 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||
336 | disable_irq(host->irq); | ||
337 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); | ||
338 | msleep(10); | ||
339 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||
340 | tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); | ||
341 | enable_irq(host->irq); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | static void reset(struct tmio_mmc_host *host) | ||
346 | { | ||
347 | /* FIXME - should we set stop clock reg here */ | ||
348 | sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); | ||
349 | sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); | ||
350 | msleep(10); | ||
351 | sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); | ||
352 | sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); | ||
353 | msleep(10); | ||
354 | } | ||
355 | |||
356 | static void tmio_mmc_reset_work(struct work_struct *work) | ||
357 | { | ||
358 | struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, | ||
359 | delayed_reset_work.work); | ||
360 | struct mmc_request *mrq; | ||
361 | unsigned long flags; | ||
362 | |||
363 | spin_lock_irqsave(&host->lock, flags); | ||
364 | mrq = host->mrq; | ||
365 | |||
366 | /* request already finished */ | ||
367 | if (!mrq | ||
368 | || time_is_after_jiffies(host->last_req_ts + | ||
369 | msecs_to_jiffies(2000))) { | ||
370 | spin_unlock_irqrestore(&host->lock, flags); | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | dev_warn(&host->pdev->dev, | ||
375 | "timeout waiting for hardware interrupt (CMD%u)\n", | ||
376 | mrq->cmd->opcode); | ||
377 | |||
378 | if (host->data) | ||
379 | host->data->error = -ETIMEDOUT; | ||
380 | else if (host->cmd) | ||
381 | host->cmd->error = -ETIMEDOUT; | ||
382 | else | ||
383 | mrq->cmd->error = -ETIMEDOUT; | ||
384 | |||
385 | host->cmd = NULL; | ||
386 | host->data = NULL; | ||
387 | host->mrq = NULL; | ||
388 | |||
389 | spin_unlock_irqrestore(&host->lock, flags); | ||
390 | |||
391 | reset(host); | ||
392 | |||
393 | mmc_request_done(host->mmc, mrq); | ||
394 | } | ||
395 | |||
396 | static void | ||
397 | tmio_mmc_finish_request(struct tmio_mmc_host *host) | ||
398 | { | ||
399 | struct mmc_request *mrq = host->mrq; | ||
400 | |||
401 | if (!mrq) | ||
402 | return; | ||
403 | |||
404 | host->mrq = NULL; | ||
405 | host->cmd = NULL; | ||
406 | host->data = NULL; | ||
407 | |||
408 | cancel_delayed_work(&host->delayed_reset_work); | ||
409 | |||
410 | mmc_request_done(host->mmc, mrq); | ||
411 | } | ||
412 | |||
413 | /* These are the bitmasks the tmio chip requires to implement the MMC response | ||
414 | * types. Note that R1 and R6 are the same in this scheme. */ | ||
415 | #define APP_CMD 0x0040 | ||
416 | #define RESP_NONE 0x0300 | ||
417 | #define RESP_R1 0x0400 | ||
418 | #define RESP_R1B 0x0500 | ||
419 | #define RESP_R2 0x0600 | ||
420 | #define RESP_R3 0x0700 | ||
421 | #define DATA_PRESENT 0x0800 | ||
422 | #define TRANSFER_READ 0x1000 | ||
423 | #define TRANSFER_MULTI 0x2000 | ||
424 | #define SECURITY_CMD 0x4000 | ||
425 | |||
426 | static int | ||
427 | tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) | ||
428 | { | ||
429 | struct mmc_data *data = host->data; | ||
430 | int c = cmd->opcode; | ||
431 | |||
432 | /* Command 12 is handled by hardware */ | ||
433 | if (cmd->opcode == 12 && !cmd->arg) { | ||
434 | sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | switch (mmc_resp_type(cmd)) { | ||
439 | case MMC_RSP_NONE: c |= RESP_NONE; break; | ||
440 | case MMC_RSP_R1: c |= RESP_R1; break; | ||
441 | case MMC_RSP_R1B: c |= RESP_R1B; break; | ||
442 | case MMC_RSP_R2: c |= RESP_R2; break; | ||
443 | case MMC_RSP_R3: c |= RESP_R3; break; | ||
444 | default: | ||
445 | pr_debug("Unknown response type %d\n", mmc_resp_type(cmd)); | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | |||
449 | host->cmd = cmd; | ||
450 | |||
451 | /* FIXME - this seems to be ok commented out but the spec suggest this bit | ||
452 | * should be set when issuing app commands. | ||
453 | * if(cmd->flags & MMC_FLAG_ACMD) | ||
454 | * c |= APP_CMD; | ||
455 | */ | ||
456 | if (data) { | ||
457 | c |= DATA_PRESENT; | ||
458 | if (data->blocks > 1) { | ||
459 | sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100); | ||
460 | c |= TRANSFER_MULTI; | ||
461 | } | ||
462 | if (data->flags & MMC_DATA_READ) | ||
463 | c |= TRANSFER_READ; | ||
464 | } | ||
465 | |||
466 | enable_mmc_irqs(host, TMIO_MASK_CMD); | ||
467 | |||
468 | /* Fire off the command */ | ||
469 | sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); | ||
470 | sd_ctrl_write16(host, CTL_SD_CMD, c); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * This chip always returns (at least?) as much data as you ask for. | ||
477 | * I'm unsure what happens if you ask for less than a block. This should be | ||
478 | * looked into to ensure that a funny length read doesnt hose the controller. | ||
479 | */ | ||
480 | static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) | ||
481 | { | ||
482 | struct mmc_data *data = host->data; | ||
483 | void *sg_virt; | ||
484 | unsigned short *buf; | ||
485 | unsigned int count; | ||
486 | unsigned long flags; | ||
487 | |||
488 | if (!data) { | ||
489 | pr_debug("Spurious PIO IRQ\n"); | ||
490 | return; | ||
491 | } | ||
492 | |||
493 | sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); | ||
494 | buf = (unsigned short *)(sg_virt + host->sg_off); | ||
495 | |||
496 | count = host->sg_ptr->length - host->sg_off; | ||
497 | if (count > data->blksz) | ||
498 | count = data->blksz; | ||
499 | |||
500 | pr_debug("count: %08x offset: %08x flags %08x\n", | ||
501 | count, host->sg_off, data->flags); | ||
502 | |||
503 | /* Transfer the data */ | ||
504 | if (data->flags & MMC_DATA_READ) | ||
505 | sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); | ||
506 | else | ||
507 | sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); | ||
508 | |||
509 | host->sg_off += count; | ||
510 | |||
511 | tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt); | ||
512 | |||
513 | if (host->sg_off == host->sg_ptr->length) | ||
514 | tmio_mmc_next_sg(host); | ||
515 | |||
516 | return; | ||
517 | } | ||
518 | |||
519 | /* needs to be called with host->lock held */ | ||
520 | static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) | ||
521 | { | ||
522 | struct mmc_data *data = host->data; | ||
523 | struct mmc_command *stop; | ||
524 | |||
525 | host->data = NULL; | ||
526 | |||
527 | if (!data) { | ||
528 | dev_warn(&host->pdev->dev, "Spurious data end IRQ\n"); | ||
529 | return; | ||
530 | } | ||
531 | stop = data->stop; | ||
532 | |||
533 | /* FIXME - return correct transfer count on errors */ | ||
534 | if (!data->error) | ||
535 | data->bytes_xfered = data->blocks * data->blksz; | ||
536 | else | ||
537 | data->bytes_xfered = 0; | ||
538 | |||
539 | pr_debug("Completed data request\n"); | ||
540 | |||
541 | /* | ||
542 | * FIXME: other drivers allow an optional stop command of any given type | ||
543 | * which we dont do, as the chip can auto generate them. | ||
544 | * Perhaps we can be smarter about when to use auto CMD12 and | ||
545 | * only issue the auto request when we know this is the desired | ||
546 | * stop command, allowing fallback to the stop command the | ||
547 | * upper layers expect. For now, we do what works. | ||
548 | */ | ||
549 | |||
550 | if (data->flags & MMC_DATA_READ) { | ||
551 | if (!host->chan_rx) | ||
552 | disable_mmc_irqs(host, TMIO_MASK_READOP); | ||
553 | else | ||
554 | tmio_check_bounce_buffer(host); | ||
555 | dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", | ||
556 | host->mrq); | ||
557 | } else { | ||
558 | if (!host->chan_tx) | ||
559 | disable_mmc_irqs(host, TMIO_MASK_WRITEOP); | ||
560 | dev_dbg(&host->pdev->dev, "Complete Tx request %p\n", | ||
561 | host->mrq); | ||
562 | } | ||
563 | |||
564 | if (stop) { | ||
565 | if (stop->opcode == 12 && !stop->arg) | ||
566 | sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); | ||
567 | else | ||
568 | BUG(); | ||
569 | } | ||
570 | |||
571 | tmio_mmc_finish_request(host); | ||
572 | } | ||
573 | |||
574 | static void tmio_mmc_data_irq(struct tmio_mmc_host *host) | ||
575 | { | ||
576 | struct mmc_data *data; | ||
577 | spin_lock(&host->lock); | ||
578 | data = host->data; | ||
579 | |||
580 | if (!data) | ||
581 | goto out; | ||
582 | |||
583 | if (host->chan_tx && (data->flags & MMC_DATA_WRITE)) { | ||
584 | /* | ||
585 | * Has all data been written out yet? Testing on SuperH showed, | ||
586 | * that in most cases the first interrupt comes already with the | ||
587 | * BUSY status bit clear, but on some operations, like mount or | ||
588 | * in the beginning of a write / sync / umount, there is one | ||
589 | * DATAEND interrupt with the BUSY bit set, in this cases | ||
590 | * waiting for one more interrupt fixes the problem. | ||
591 | */ | ||
592 | if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) { | ||
593 | disable_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
594 | tasklet_schedule(&host->dma_complete); | ||
595 | } | ||
596 | } else if (host->chan_rx && (data->flags & MMC_DATA_READ)) { | ||
597 | disable_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
598 | tasklet_schedule(&host->dma_complete); | ||
599 | } else { | ||
600 | tmio_mmc_do_data_irq(host); | ||
601 | } | ||
602 | out: | ||
603 | spin_unlock(&host->lock); | ||
604 | } | ||
605 | |||
606 | static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, | ||
607 | unsigned int stat) | ||
608 | { | ||
609 | struct mmc_command *cmd = host->cmd; | ||
610 | int i, addr; | ||
611 | |||
612 | spin_lock(&host->lock); | ||
613 | |||
614 | if (!host->cmd) { | ||
615 | pr_debug("Spurious CMD irq\n"); | ||
616 | goto out; | ||
617 | } | ||
618 | |||
619 | host->cmd = NULL; | ||
620 | |||
621 | /* This controller is sicker than the PXA one. Not only do we need to | ||
622 | * drop the top 8 bits of the first response word, we also need to | ||
623 | * modify the order of the response for short response command types. | ||
624 | */ | ||
625 | |||
626 | for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4) | ||
627 | cmd->resp[i] = sd_ctrl_read32(host, addr); | ||
628 | |||
629 | if (cmd->flags & MMC_RSP_136) { | ||
630 | cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); | ||
631 | cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24); | ||
632 | cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24); | ||
633 | cmd->resp[3] <<= 8; | ||
634 | } else if (cmd->flags & MMC_RSP_R3) { | ||
635 | cmd->resp[0] = cmd->resp[3]; | ||
636 | } | ||
637 | |||
638 | if (stat & TMIO_STAT_CMDTIMEOUT) | ||
639 | cmd->error = -ETIMEDOUT; | ||
640 | else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) | ||
641 | cmd->error = -EILSEQ; | ||
642 | |||
643 | /* If there is data to handle we enable data IRQs here, and | ||
644 | * we will ultimatley finish the request in the data_end handler. | ||
645 | * If theres no data or we encountered an error, finish now. | ||
646 | */ | ||
647 | if (host->data && !cmd->error) { | ||
648 | if (host->data->flags & MMC_DATA_READ) { | ||
649 | if (!host->chan_rx) | ||
650 | enable_mmc_irqs(host, TMIO_MASK_READOP); | ||
651 | } else { | ||
652 | if (!host->chan_tx) | ||
653 | enable_mmc_irqs(host, TMIO_MASK_WRITEOP); | ||
654 | else | ||
655 | tasklet_schedule(&host->dma_issue); | ||
656 | } | ||
657 | } else { | ||
658 | tmio_mmc_finish_request(host); | ||
659 | } | ||
660 | |||
661 | out: | ||
662 | spin_unlock(&host->lock); | ||
663 | |||
664 | return; | ||
665 | } | ||
666 | |||
667 | static irqreturn_t tmio_mmc_irq(int irq, void *devid) | ||
668 | { | ||
669 | struct tmio_mmc_host *host = devid; | ||
670 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
671 | unsigned int ireg, irq_mask, status; | ||
672 | unsigned int sdio_ireg, sdio_irq_mask, sdio_status; | ||
673 | |||
674 | pr_debug("MMC IRQ begin\n"); | ||
675 | |||
676 | status = sd_ctrl_read32(host, CTL_STATUS); | ||
677 | irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); | ||
678 | ireg = status & TMIO_MASK_IRQ & ~irq_mask; | ||
679 | |||
680 | sdio_ireg = 0; | ||
681 | if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||
682 | sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); | ||
683 | sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); | ||
684 | sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; | ||
685 | |||
686 | sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); | ||
687 | |||
688 | if (sdio_ireg && !host->sdio_irq_enabled) { | ||
689 | pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", | ||
690 | sdio_status, sdio_irq_mask, sdio_ireg); | ||
691 | tmio_mmc_enable_sdio_irq(host->mmc, 0); | ||
692 | goto out; | ||
693 | } | ||
694 | 23 | ||
695 | if (host->mmc->caps & MMC_CAP_SDIO_IRQ && | 24 | #include "tmio_mmc.h" |
696 | sdio_ireg & TMIO_SDIO_STAT_IOIRQ) | ||
697 | mmc_signal_sdio_irq(host->mmc); | ||
698 | |||
699 | if (sdio_ireg) | ||
700 | goto out; | ||
701 | } | ||
702 | |||
703 | pr_debug_status(status); | ||
704 | pr_debug_status(ireg); | ||
705 | |||
706 | if (!ireg) { | ||
707 | disable_mmc_irqs(host, status & ~irq_mask); | ||
708 | |||
709 | pr_warning("tmio_mmc: Spurious irq, disabling! " | ||
710 | "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); | ||
711 | pr_debug_status(status); | ||
712 | |||
713 | goto out; | ||
714 | } | ||
715 | |||
716 | while (ireg) { | ||
717 | /* Card insert / remove attempts */ | ||
718 | if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { | ||
719 | ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | | ||
720 | TMIO_STAT_CARD_REMOVE); | ||
721 | mmc_detect_change(host->mmc, msecs_to_jiffies(100)); | ||
722 | } | ||
723 | |||
724 | /* CRC and other errors */ | ||
725 | /* if (ireg & TMIO_STAT_ERR_IRQ) | ||
726 | * handled |= tmio_error_irq(host, irq, stat); | ||
727 | */ | ||
728 | |||
729 | /* Command completion */ | ||
730 | if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { | ||
731 | ack_mmc_irqs(host, | ||
732 | TMIO_STAT_CMDRESPEND | | ||
733 | TMIO_STAT_CMDTIMEOUT); | ||
734 | tmio_mmc_cmd_irq(host, status); | ||
735 | } | ||
736 | |||
737 | /* Data transfer */ | ||
738 | if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { | ||
739 | ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); | ||
740 | tmio_mmc_pio_irq(host); | ||
741 | } | ||
742 | |||
743 | /* Data transfer completion */ | ||
744 | if (ireg & TMIO_STAT_DATAEND) { | ||
745 | ack_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
746 | tmio_mmc_data_irq(host); | ||
747 | } | ||
748 | |||
749 | /* Check status - keep going until we've handled it all */ | ||
750 | status = sd_ctrl_read32(host, CTL_STATUS); | ||
751 | irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); | ||
752 | ireg = status & TMIO_MASK_IRQ & ~irq_mask; | ||
753 | |||
754 | pr_debug("Status at end of loop: %08x\n", status); | ||
755 | pr_debug_status(status); | ||
756 | } | ||
757 | pr_debug("MMC IRQ end\n"); | ||
758 | |||
759 | out: | ||
760 | return IRQ_HANDLED; | ||
761 | } | ||
762 | |||
763 | #ifdef CONFIG_TMIO_MMC_DMA | ||
764 | static void tmio_check_bounce_buffer(struct tmio_mmc_host *host) | ||
765 | { | ||
766 | if (host->sg_ptr == &host->bounce_sg) { | ||
767 | unsigned long flags; | ||
768 | void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); | ||
769 | memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); | ||
770 | tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); | ||
771 | } | ||
772 | } | ||
773 | |||
774 | static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) | ||
775 | { | ||
776 | #if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE) | ||
777 | /* Switch DMA mode on or off - SuperH specific? */ | ||
778 | sd_ctrl_write16(host, 0xd8, enable ? 2 : 0); | ||
779 | #endif | ||
780 | } | ||
781 | |||
782 | static void tmio_dma_complete(void *arg) | ||
783 | { | ||
784 | struct tmio_mmc_host *host = arg; | ||
785 | |||
786 | dev_dbg(&host->pdev->dev, "Command completed\n"); | ||
787 | |||
788 | if (!host->data) | ||
789 | dev_warn(&host->pdev->dev, "NULL data in DMA completion!\n"); | ||
790 | else | ||
791 | enable_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
792 | } | ||
793 | |||
794 | static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) | ||
795 | { | ||
796 | struct scatterlist *sg = host->sg_ptr, *sg_tmp; | ||
797 | struct dma_async_tx_descriptor *desc = NULL; | ||
798 | struct dma_chan *chan = host->chan_rx; | ||
799 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
800 | dma_cookie_t cookie; | ||
801 | int ret, i; | ||
802 | bool aligned = true, multiple = true; | ||
803 | unsigned int align = (1 << pdata->dma->alignment_shift) - 1; | ||
804 | |||
805 | for_each_sg(sg, sg_tmp, host->sg_len, i) { | ||
806 | if (sg_tmp->offset & align) | ||
807 | aligned = false; | ||
808 | if (sg_tmp->length & align) { | ||
809 | multiple = false; | ||
810 | break; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || | ||
815 | align >= MAX_ALIGN)) || !multiple) { | ||
816 | ret = -EINVAL; | ||
817 | goto pio; | ||
818 | } | ||
819 | |||
820 | /* The only sg element can be unaligned, use our bounce buffer then */ | ||
821 | if (!aligned) { | ||
822 | sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); | ||
823 | host->sg_ptr = &host->bounce_sg; | ||
824 | sg = host->sg_ptr; | ||
825 | } | ||
826 | |||
827 | ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); | ||
828 | if (ret > 0) | ||
829 | desc = chan->device->device_prep_slave_sg(chan, sg, ret, | ||
830 | DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
831 | |||
832 | if (desc) { | ||
833 | desc->callback = tmio_dma_complete; | ||
834 | desc->callback_param = host; | ||
835 | cookie = dmaengine_submit(desc); | ||
836 | dma_async_issue_pending(chan); | ||
837 | } | ||
838 | dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", | ||
839 | __func__, host->sg_len, ret, cookie, host->mrq); | ||
840 | |||
841 | pio: | ||
842 | if (!desc) { | ||
843 | /* DMA failed, fall back to PIO */ | ||
844 | if (ret >= 0) | ||
845 | ret = -EIO; | ||
846 | host->chan_rx = NULL; | ||
847 | dma_release_channel(chan); | ||
848 | /* Free the Tx channel too */ | ||
849 | chan = host->chan_tx; | ||
850 | if (chan) { | ||
851 | host->chan_tx = NULL; | ||
852 | dma_release_channel(chan); | ||
853 | } | ||
854 | dev_warn(&host->pdev->dev, | ||
855 | "DMA failed: %d, falling back to PIO\n", ret); | ||
856 | tmio_mmc_enable_dma(host, false); | ||
857 | } | ||
858 | |||
859 | dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, | ||
860 | desc, cookie, host->sg_len); | ||
861 | } | ||
862 | |||
863 | static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) | ||
864 | { | ||
865 | struct scatterlist *sg = host->sg_ptr, *sg_tmp; | ||
866 | struct dma_async_tx_descriptor *desc = NULL; | ||
867 | struct dma_chan *chan = host->chan_tx; | ||
868 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
869 | dma_cookie_t cookie; | ||
870 | int ret, i; | ||
871 | bool aligned = true, multiple = true; | ||
872 | unsigned int align = (1 << pdata->dma->alignment_shift) - 1; | ||
873 | |||
874 | for_each_sg(sg, sg_tmp, host->sg_len, i) { | ||
875 | if (sg_tmp->offset & align) | ||
876 | aligned = false; | ||
877 | if (sg_tmp->length & align) { | ||
878 | multiple = false; | ||
879 | break; | ||
880 | } | ||
881 | } | ||
882 | |||
883 | if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || | ||
884 | align >= MAX_ALIGN)) || !multiple) { | ||
885 | ret = -EINVAL; | ||
886 | goto pio; | ||
887 | } | ||
888 | |||
889 | /* The only sg element can be unaligned, use our bounce buffer then */ | ||
890 | if (!aligned) { | ||
891 | unsigned long flags; | ||
892 | void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); | ||
893 | sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); | ||
894 | memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); | ||
895 | tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); | ||
896 | host->sg_ptr = &host->bounce_sg; | ||
897 | sg = host->sg_ptr; | ||
898 | } | ||
899 | |||
900 | ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); | ||
901 | if (ret > 0) | ||
902 | desc = chan->device->device_prep_slave_sg(chan, sg, ret, | ||
903 | DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
904 | |||
905 | if (desc) { | ||
906 | desc->callback = tmio_dma_complete; | ||
907 | desc->callback_param = host; | ||
908 | cookie = dmaengine_submit(desc); | ||
909 | } | ||
910 | dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", | ||
911 | __func__, host->sg_len, ret, cookie, host->mrq); | ||
912 | |||
913 | pio: | ||
914 | if (!desc) { | ||
915 | /* DMA failed, fall back to PIO */ | ||
916 | if (ret >= 0) | ||
917 | ret = -EIO; | ||
918 | host->chan_tx = NULL; | ||
919 | dma_release_channel(chan); | ||
920 | /* Free the Rx channel too */ | ||
921 | chan = host->chan_rx; | ||
922 | if (chan) { | ||
923 | host->chan_rx = NULL; | ||
924 | dma_release_channel(chan); | ||
925 | } | ||
926 | dev_warn(&host->pdev->dev, | ||
927 | "DMA failed: %d, falling back to PIO\n", ret); | ||
928 | tmio_mmc_enable_dma(host, false); | ||
929 | } | ||
930 | |||
931 | dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__, | ||
932 | desc, cookie); | ||
933 | } | ||
934 | |||
935 | static void tmio_mmc_start_dma(struct tmio_mmc_host *host, | ||
936 | struct mmc_data *data) | ||
937 | { | ||
938 | if (data->flags & MMC_DATA_READ) { | ||
939 | if (host->chan_rx) | ||
940 | tmio_mmc_start_dma_rx(host); | ||
941 | } else { | ||
942 | if (host->chan_tx) | ||
943 | tmio_mmc_start_dma_tx(host); | ||
944 | } | ||
945 | } | ||
946 | |||
947 | static void tmio_issue_tasklet_fn(unsigned long priv) | ||
948 | { | ||
949 | struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; | ||
950 | struct dma_chan *chan = host->chan_tx; | ||
951 | |||
952 | dma_async_issue_pending(chan); | ||
953 | } | ||
954 | |||
955 | static void tmio_tasklet_fn(unsigned long arg) | ||
956 | { | ||
957 | struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; | ||
958 | unsigned long flags; | ||
959 | |||
960 | spin_lock_irqsave(&host->lock, flags); | ||
961 | |||
962 | if (!host->data) | ||
963 | goto out; | ||
964 | |||
965 | if (host->data->flags & MMC_DATA_READ) | ||
966 | dma_unmap_sg(host->chan_rx->device->dev, | ||
967 | host->sg_ptr, host->sg_len, | ||
968 | DMA_FROM_DEVICE); | ||
969 | else | ||
970 | dma_unmap_sg(host->chan_tx->device->dev, | ||
971 | host->sg_ptr, host->sg_len, | ||
972 | DMA_TO_DEVICE); | ||
973 | |||
974 | tmio_mmc_do_data_irq(host); | ||
975 | out: | ||
976 | spin_unlock_irqrestore(&host->lock, flags); | ||
977 | } | ||
978 | |||
979 | /* It might be necessary to make filter MFD specific */ | ||
980 | static bool tmio_mmc_filter(struct dma_chan *chan, void *arg) | ||
981 | { | ||
982 | dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); | ||
983 | chan->private = arg; | ||
984 | return true; | ||
985 | } | ||
986 | |||
987 | static void tmio_mmc_request_dma(struct tmio_mmc_host *host, | ||
988 | struct tmio_mmc_data *pdata) | ||
989 | { | ||
990 | /* We can only either use DMA for both Tx and Rx or not use it at all */ | ||
991 | if (pdata->dma) { | ||
992 | dma_cap_mask_t mask; | ||
993 | |||
994 | dma_cap_zero(mask); | ||
995 | dma_cap_set(DMA_SLAVE, mask); | ||
996 | |||
997 | host->chan_tx = dma_request_channel(mask, tmio_mmc_filter, | ||
998 | pdata->dma->chan_priv_tx); | ||
999 | dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, | ||
1000 | host->chan_tx); | ||
1001 | |||
1002 | if (!host->chan_tx) | ||
1003 | return; | ||
1004 | |||
1005 | host->chan_rx = dma_request_channel(mask, tmio_mmc_filter, | ||
1006 | pdata->dma->chan_priv_rx); | ||
1007 | dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, | ||
1008 | host->chan_rx); | ||
1009 | |||
1010 | if (!host->chan_rx) { | ||
1011 | dma_release_channel(host->chan_tx); | ||
1012 | host->chan_tx = NULL; | ||
1013 | return; | ||
1014 | } | ||
1015 | |||
1016 | tasklet_init(&host->dma_complete, tmio_tasklet_fn, (unsigned long)host); | ||
1017 | tasklet_init(&host->dma_issue, tmio_issue_tasklet_fn, (unsigned long)host); | ||
1018 | |||
1019 | tmio_mmc_enable_dma(host, true); | ||
1020 | } | ||
1021 | } | ||
1022 | |||
1023 | static void tmio_mmc_release_dma(struct tmio_mmc_host *host) | ||
1024 | { | ||
1025 | if (host->chan_tx) { | ||
1026 | struct dma_chan *chan = host->chan_tx; | ||
1027 | host->chan_tx = NULL; | ||
1028 | dma_release_channel(chan); | ||
1029 | } | ||
1030 | if (host->chan_rx) { | ||
1031 | struct dma_chan *chan = host->chan_rx; | ||
1032 | host->chan_rx = NULL; | ||
1033 | dma_release_channel(chan); | ||
1034 | } | ||
1035 | } | ||
1036 | #else | ||
1037 | static void tmio_check_bounce_buffer(struct tmio_mmc_host *host) | ||
1038 | { | ||
1039 | } | ||
1040 | |||
1041 | static void tmio_mmc_start_dma(struct tmio_mmc_host *host, | ||
1042 | struct mmc_data *data) | ||
1043 | { | ||
1044 | } | ||
1045 | |||
1046 | static void tmio_mmc_request_dma(struct tmio_mmc_host *host, | ||
1047 | struct tmio_mmc_data *pdata) | ||
1048 | { | ||
1049 | host->chan_tx = NULL; | ||
1050 | host->chan_rx = NULL; | ||
1051 | } | ||
1052 | |||
1053 | static void tmio_mmc_release_dma(struct tmio_mmc_host *host) | ||
1054 | { | ||
1055 | } | ||
1056 | #endif | ||
1057 | |||
1058 | static int tmio_mmc_start_data(struct tmio_mmc_host *host, | ||
1059 | struct mmc_data *data) | ||
1060 | { | ||
1061 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
1062 | |||
1063 | pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", | ||
1064 | data->blksz, data->blocks); | ||
1065 | |||
1066 | /* Some hardware cannot perform 2 byte requests in 4 bit mode */ | ||
1067 | if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { | ||
1068 | int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES; | ||
1069 | |||
1070 | if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) { | ||
1071 | pr_err("%s: %d byte block unsupported in 4 bit mode\n", | ||
1072 | mmc_hostname(host->mmc), data->blksz); | ||
1073 | return -EINVAL; | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | tmio_mmc_init_sg(host, data); | ||
1078 | host->data = data; | ||
1079 | |||
1080 | /* Set transfer length / blocksize */ | ||
1081 | sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); | ||
1082 | sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); | ||
1083 | |||
1084 | tmio_mmc_start_dma(host, data); | ||
1085 | |||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | /* Process requests from the MMC layer */ | ||
1090 | static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | ||
1091 | { | ||
1092 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
1093 | int ret; | ||
1094 | |||
1095 | if (host->mrq) | ||
1096 | pr_debug("request not null\n"); | ||
1097 | |||
1098 | host->last_req_ts = jiffies; | ||
1099 | wmb(); | ||
1100 | host->mrq = mrq; | ||
1101 | |||
1102 | if (mrq->data) { | ||
1103 | ret = tmio_mmc_start_data(host, mrq->data); | ||
1104 | if (ret) | ||
1105 | goto fail; | ||
1106 | } | ||
1107 | |||
1108 | ret = tmio_mmc_start_command(host, mrq->cmd); | ||
1109 | if (!ret) { | ||
1110 | schedule_delayed_work(&host->delayed_reset_work, | ||
1111 | msecs_to_jiffies(2000)); | ||
1112 | return; | ||
1113 | } | ||
1114 | |||
1115 | fail: | ||
1116 | host->mrq = NULL; | ||
1117 | mrq->cmd->error = ret; | ||
1118 | mmc_request_done(mmc, mrq); | ||
1119 | } | ||
1120 | |||
1121 | /* Set MMC clock / power. | ||
1122 | * Note: This controller uses a simple divider scheme therefore it cannot | ||
1123 | * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as | ||
1124 | * MMC wont run that fast, it has to be clocked at 12MHz which is the next | ||
1125 | * slowest setting. | ||
1126 | */ | ||
1127 | static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||
1128 | { | ||
1129 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
1130 | |||
1131 | if (ios->clock) | ||
1132 | tmio_mmc_set_clock(host, ios->clock); | ||
1133 | |||
1134 | /* Power sequence - OFF -> ON -> UP */ | ||
1135 | switch (ios->power_mode) { | ||
1136 | case MMC_POWER_OFF: /* power down SD bus */ | ||
1137 | if (host->set_pwr) | ||
1138 | host->set_pwr(host->pdev, 0); | ||
1139 | tmio_mmc_clk_stop(host); | ||
1140 | break; | ||
1141 | case MMC_POWER_ON: /* power up SD bus */ | ||
1142 | if (host->set_pwr) | ||
1143 | host->set_pwr(host->pdev, 1); | ||
1144 | break; | ||
1145 | case MMC_POWER_UP: /* start bus clock */ | ||
1146 | tmio_mmc_clk_start(host); | ||
1147 | break; | ||
1148 | } | ||
1149 | |||
1150 | switch (ios->bus_width) { | ||
1151 | case MMC_BUS_WIDTH_1: | ||
1152 | sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); | ||
1153 | break; | ||
1154 | case MMC_BUS_WIDTH_4: | ||
1155 | sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); | ||
1156 | break; | ||
1157 | } | ||
1158 | |||
1159 | /* Let things settle. delay taken from winCE driver */ | ||
1160 | udelay(140); | ||
1161 | } | ||
1162 | |||
1163 | static int tmio_mmc_get_ro(struct mmc_host *mmc) | ||
1164 | { | ||
1165 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
1166 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
1167 | |||
1168 | return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || | ||
1169 | (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1; | ||
1170 | } | ||
1171 | |||
1172 | static int tmio_mmc_get_cd(struct mmc_host *mmc) | ||
1173 | { | ||
1174 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
1175 | struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); | ||
1176 | |||
1177 | if (!pdata->get_cd) | ||
1178 | return -ENOSYS; | ||
1179 | else | ||
1180 | return pdata->get_cd(host->pdev); | ||
1181 | } | ||
1182 | |||
1183 | static const struct mmc_host_ops tmio_mmc_ops = { | ||
1184 | .request = tmio_mmc_request, | ||
1185 | .set_ios = tmio_mmc_set_ios, | ||
1186 | .get_ro = tmio_mmc_get_ro, | ||
1187 | .get_cd = tmio_mmc_get_cd, | ||
1188 | .enable_sdio_irq = tmio_mmc_enable_sdio_irq, | ||
1189 | }; | ||
1190 | 25 | ||
1191 | #ifdef CONFIG_PM | 26 | #ifdef CONFIG_PM |
1192 | static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) | 27 | static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) |
@@ -1227,138 +62,54 @@ out: | |||
1227 | #define tmio_mmc_resume NULL | 62 | #define tmio_mmc_resume NULL |
1228 | #endif | 63 | #endif |
1229 | 64 | ||
1230 | static int __devinit tmio_mmc_probe(struct platform_device *dev) | 65 | static int __devinit tmio_mmc_probe(struct platform_device *pdev) |
1231 | { | 66 | { |
1232 | const struct mfd_cell *cell = mfd_get_cell(dev); | 67 | const struct mfd_cell *cell = mfd_get_cell(pdev); |
1233 | struct tmio_mmc_data *pdata; | 68 | struct tmio_mmc_data *pdata; |
1234 | struct resource *res_ctl; | ||
1235 | struct tmio_mmc_host *host; | 69 | struct tmio_mmc_host *host; |
1236 | struct mmc_host *mmc; | ||
1237 | int ret = -EINVAL; | 70 | int ret = -EINVAL; |
1238 | u32 irq_mask = TMIO_MASK_CMD; | ||
1239 | 71 | ||
1240 | if (dev->num_resources != 2) | 72 | if (pdev->num_resources != 2) |
1241 | goto out; | 73 | goto out; |
1242 | 74 | ||
1243 | res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0); | 75 | pdata = mfd_get_data(pdev); |
1244 | if (!res_ctl) | ||
1245 | goto out; | ||
1246 | |||
1247 | pdata = mfd_get_data(dev); | ||
1248 | if (!pdata || !pdata->hclk) | 76 | if (!pdata || !pdata->hclk) |
1249 | goto out; | 77 | goto out; |
1250 | 78 | ||
1251 | ret = -ENOMEM; | ||
1252 | |||
1253 | mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev); | ||
1254 | if (!mmc) | ||
1255 | goto out; | ||
1256 | |||
1257 | host = mmc_priv(mmc); | ||
1258 | host->mmc = mmc; | ||
1259 | host->pdev = dev; | ||
1260 | platform_set_drvdata(dev, mmc); | ||
1261 | |||
1262 | host->set_pwr = pdata->set_pwr; | ||
1263 | host->set_clk_div = pdata->set_clk_div; | ||
1264 | |||
1265 | /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ | ||
1266 | host->bus_shift = resource_size(res_ctl) >> 10; | ||
1267 | |||
1268 | host->ctl = ioremap(res_ctl->start, resource_size(res_ctl)); | ||
1269 | if (!host->ctl) | ||
1270 | goto host_free; | ||
1271 | |||
1272 | mmc->ops = &tmio_mmc_ops; | ||
1273 | mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; | ||
1274 | mmc->f_max = pdata->hclk; | ||
1275 | mmc->f_min = mmc->f_max / 512; | ||
1276 | mmc->max_segs = 32; | ||
1277 | mmc->max_blk_size = 512; | ||
1278 | mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * | ||
1279 | mmc->max_segs; | ||
1280 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; | ||
1281 | mmc->max_seg_size = mmc->max_req_size; | ||
1282 | if (pdata->ocr_mask) | ||
1283 | mmc->ocr_avail = pdata->ocr_mask; | ||
1284 | else | ||
1285 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | ||
1286 | |||
1287 | /* Tell the MFD core we are ready to be enabled */ | 79 | /* Tell the MFD core we are ready to be enabled */ |
1288 | if (cell->enable) { | 80 | if (cell->enable) { |
1289 | ret = cell->enable(dev); | 81 | ret = cell->enable(pdev); |
1290 | if (ret) | 82 | if (ret) |
1291 | goto unmap_ctl; | 83 | goto out; |
1292 | } | 84 | } |
1293 | 85 | ||
1294 | tmio_mmc_clk_stop(host); | 86 | ret = tmio_mmc_host_probe(&host, pdev, pdata); |
1295 | reset(host); | ||
1296 | |||
1297 | ret = platform_get_irq(dev, 0); | ||
1298 | if (ret >= 0) | ||
1299 | host->irq = ret; | ||
1300 | else | ||
1301 | goto cell_disable; | ||
1302 | |||
1303 | disable_mmc_irqs(host, TMIO_MASK_ALL); | ||
1304 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||
1305 | tmio_mmc_enable_sdio_irq(mmc, 0); | ||
1306 | |||
1307 | ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | | ||
1308 | IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); | ||
1309 | if (ret) | 87 | if (ret) |
1310 | goto cell_disable; | 88 | goto cell_disable; |
1311 | 89 | ||
1312 | spin_lock_init(&host->lock); | ||
1313 | |||
1314 | /* Init delayed work for request timeouts */ | ||
1315 | INIT_DELAYED_WORK(&host->delayed_reset_work, tmio_mmc_reset_work); | ||
1316 | |||
1317 | /* See if we also get DMA */ | ||
1318 | tmio_mmc_request_dma(host, pdata); | ||
1319 | |||
1320 | mmc_add_host(mmc); | ||
1321 | |||
1322 | pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), | 90 | pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), |
1323 | (unsigned long)host->ctl, host->irq); | 91 | (unsigned long)host->ctl, host->irq); |
1324 | 92 | ||
1325 | /* Unmask the IRQs we want to know about */ | ||
1326 | if (!host->chan_rx) | ||
1327 | irq_mask |= TMIO_MASK_READOP; | ||
1328 | if (!host->chan_tx) | ||
1329 | irq_mask |= TMIO_MASK_WRITEOP; | ||
1330 | enable_mmc_irqs(host, irq_mask); | ||
1331 | |||
1332 | return 0; | 93 | return 0; |
1333 | 94 | ||
1334 | cell_disable: | 95 | cell_disable: |
1335 | if (cell->disable) | 96 | if (cell->disable) |
1336 | cell->disable(dev); | 97 | cell->disable(pdev); |
1337 | unmap_ctl: | ||
1338 | iounmap(host->ctl); | ||
1339 | host_free: | ||
1340 | mmc_free_host(mmc); | ||
1341 | out: | 98 | out: |
1342 | return ret; | 99 | return ret; |
1343 | } | 100 | } |
1344 | 101 | ||
1345 | static int __devexit tmio_mmc_remove(struct platform_device *dev) | 102 | static int __devexit tmio_mmc_remove(struct platform_device *pdev) |
1346 | { | 103 | { |
1347 | const struct mfd_cell *cell = mfd_get_cell(dev); | 104 | const struct mfd_cell *cell = mfd_get_cell(pdev); |
1348 | struct mmc_host *mmc = platform_get_drvdata(dev); | 105 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
1349 | 106 | ||
1350 | platform_set_drvdata(dev, NULL); | 107 | platform_set_drvdata(pdev, NULL); |
1351 | 108 | ||
1352 | if (mmc) { | 109 | if (mmc) { |
1353 | struct tmio_mmc_host *host = mmc_priv(mmc); | 110 | tmio_mmc_host_remove(mmc_priv(mmc)); |
1354 | mmc_remove_host(mmc); | ||
1355 | cancel_delayed_work_sync(&host->delayed_reset_work); | ||
1356 | tmio_mmc_release_dma(host); | ||
1357 | free_irq(host->irq, host); | ||
1358 | if (cell->disable) | 111 | if (cell->disable) |
1359 | cell->disable(dev); | 112 | cell->disable(pdev); |
1360 | iounmap(host->ctl); | ||
1361 | mmc_free_host(mmc); | ||
1362 | } | 113 | } |
1363 | 114 | ||
1364 | return 0; | 115 | return 0; |
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h new file mode 100644 index 000000000000..099ed49a259b --- /dev/null +++ b/drivers/mmc/host/tmio_mmc.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/host/tmio_mmc.h | ||
3 | * | ||
4 | * Copyright (C) 2007 Ian Molton | ||
5 | * Copyright (C) 2004 Ian Molton | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Driver for the MMC / SD / SDIO cell found in: | ||
12 | * | ||
13 | * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 | ||
14 | */ | ||
15 | |||
16 | #ifndef TMIO_MMC_H | ||
17 | #define TMIO_MMC_H | ||
18 | |||
19 | #include <linux/highmem.h> | ||
20 | #include <linux/mmc/tmio.h> | ||
21 | #include <linux/pagemap.h> | ||
22 | |||
23 | /* Definitions for values the CTRL_SDIO_STATUS register can take. */ | ||
24 | #define TMIO_SDIO_STAT_IOIRQ 0x0001 | ||
25 | #define TMIO_SDIO_STAT_EXPUB52 0x4000 | ||
26 | #define TMIO_SDIO_STAT_EXWT 0x8000 | ||
27 | #define TMIO_SDIO_MASK_ALL 0xc007 | ||
28 | |||
29 | /* Define some IRQ masks */ | ||
30 | /* This is the mask used at reset by the chip */ | ||
31 | #define TMIO_MASK_ALL 0x837f031d | ||
32 | #define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) | ||
33 | #define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) | ||
34 | #define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ | ||
35 | TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) | ||
36 | #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) | ||
37 | |||
38 | struct tmio_mmc_data; | ||
39 | |||
40 | struct tmio_mmc_host { | ||
41 | void __iomem *ctl; | ||
42 | unsigned long bus_shift; | ||
43 | struct mmc_command *cmd; | ||
44 | struct mmc_request *mrq; | ||
45 | struct mmc_data *data; | ||
46 | struct mmc_host *mmc; | ||
47 | int irq; | ||
48 | unsigned int sdio_irq_enabled; | ||
49 | |||
50 | /* Callbacks for clock / power control */ | ||
51 | void (*set_pwr)(struct platform_device *host, int state); | ||
52 | void (*set_clk_div)(struct platform_device *host, int state); | ||
53 | |||
54 | /* pio related stuff */ | ||
55 | struct scatterlist *sg_ptr; | ||
56 | struct scatterlist *sg_orig; | ||
57 | unsigned int sg_len; | ||
58 | unsigned int sg_off; | ||
59 | |||
60 | struct platform_device *pdev; | ||
61 | struct tmio_mmc_data *pdata; | ||
62 | |||
63 | /* DMA support */ | ||
64 | bool force_pio; | ||
65 | struct dma_chan *chan_rx; | ||
66 | struct dma_chan *chan_tx; | ||
67 | struct tasklet_struct dma_complete; | ||
68 | struct tasklet_struct dma_issue; | ||
69 | struct scatterlist bounce_sg; | ||
70 | u8 *bounce_buf; | ||
71 | |||
72 | /* Track lost interrupts */ | ||
73 | struct delayed_work delayed_reset_work; | ||
74 | spinlock_t lock; | ||
75 | unsigned long last_req_ts; | ||
76 | }; | ||
77 | |||
78 | int tmio_mmc_host_probe(struct tmio_mmc_host **host, | ||
79 | struct platform_device *pdev, | ||
80 | struct tmio_mmc_data *pdata); | ||
81 | void tmio_mmc_host_remove(struct tmio_mmc_host *host); | ||
82 | void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); | ||
83 | |||
84 | void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); | ||
85 | void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); | ||
86 | |||
87 | static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, | ||
88 | unsigned long *flags) | ||
89 | { | ||
90 | local_irq_save(*flags); | ||
91 | return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; | ||
92 | } | ||
93 | |||
94 | static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, | ||
95 | unsigned long *flags, void *virt) | ||
96 | { | ||
97 | kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); | ||
98 | local_irq_restore(*flags); | ||
99 | } | ||
100 | |||
101 | #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) | ||
102 | void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); | ||
103 | void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); | ||
104 | void tmio_mmc_release_dma(struct tmio_mmc_host *host); | ||
105 | #else | ||
106 | static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, | ||
107 | struct mmc_data *data) | ||
108 | { | ||
109 | } | ||
110 | |||
111 | static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, | ||
112 | struct tmio_mmc_data *pdata) | ||
113 | { | ||
114 | host->chan_tx = NULL; | ||
115 | host->chan_rx = NULL; | ||
116 | } | ||
117 | |||
118 | static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) | ||
119 | { | ||
120 | } | ||
121 | #endif | ||
122 | |||
123 | #endif | ||
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c new file mode 100644 index 000000000000..d3de74ab633e --- /dev/null +++ b/drivers/mmc/host/tmio_mmc_dma.c | |||
@@ -0,0 +1,317 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/tmio_mmc_dma.c | ||
3 | * | ||
4 | * Copyright (C) 2010-2011 Guennadi Liakhovetski | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * DMA function for TMIO MMC implementations | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/dmaengine.h> | ||
15 | #include <linux/mfd/tmio.h> | ||
16 | #include <linux/mmc/host.h> | ||
17 | #include <linux/mmc/tmio.h> | ||
18 | #include <linux/pagemap.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | |||
21 | #include "tmio_mmc.h" | ||
22 | |||
23 | #define TMIO_MMC_MIN_DMA_LEN 8 | ||
24 | |||
25 | static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) | ||
26 | { | ||
27 | #if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE) | ||
28 | /* Switch DMA mode on or off - SuperH specific? */ | ||
29 | writew(enable ? 2 : 0, host->ctl + (0xd8 << host->bus_shift)); | ||
30 | #endif | ||
31 | } | ||
32 | |||
33 | static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) | ||
34 | { | ||
35 | struct scatterlist *sg = host->sg_ptr, *sg_tmp; | ||
36 | struct dma_async_tx_descriptor *desc = NULL; | ||
37 | struct dma_chan *chan = host->chan_rx; | ||
38 | struct tmio_mmc_data *pdata = host->pdata; | ||
39 | dma_cookie_t cookie; | ||
40 | int ret, i; | ||
41 | bool aligned = true, multiple = true; | ||
42 | unsigned int align = (1 << pdata->dma->alignment_shift) - 1; | ||
43 | |||
44 | for_each_sg(sg, sg_tmp, host->sg_len, i) { | ||
45 | if (sg_tmp->offset & align) | ||
46 | aligned = false; | ||
47 | if (sg_tmp->length & align) { | ||
48 | multiple = false; | ||
49 | break; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || | ||
54 | (align & PAGE_MASK))) || !multiple) { | ||
55 | ret = -EINVAL; | ||
56 | goto pio; | ||
57 | } | ||
58 | |||
59 | if (sg->length < TMIO_MMC_MIN_DMA_LEN) { | ||
60 | host->force_pio = true; | ||
61 | return; | ||
62 | } | ||
63 | |||
64 | tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY); | ||
65 | |||
66 | /* The only sg element can be unaligned, use our bounce buffer then */ | ||
67 | if (!aligned) { | ||
68 | sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); | ||
69 | host->sg_ptr = &host->bounce_sg; | ||
70 | sg = host->sg_ptr; | ||
71 | } | ||
72 | |||
73 | ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); | ||
74 | if (ret > 0) | ||
75 | desc = chan->device->device_prep_slave_sg(chan, sg, ret, | ||
76 | DMA_FROM_DEVICE, DMA_CTRL_ACK); | ||
77 | |||
78 | if (desc) { | ||
79 | cookie = dmaengine_submit(desc); | ||
80 | if (cookie < 0) { | ||
81 | desc = NULL; | ||
82 | ret = cookie; | ||
83 | } | ||
84 | } | ||
85 | dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", | ||
86 | __func__, host->sg_len, ret, cookie, host->mrq); | ||
87 | |||
88 | pio: | ||
89 | if (!desc) { | ||
90 | /* DMA failed, fall back to PIO */ | ||
91 | if (ret >= 0) | ||
92 | ret = -EIO; | ||
93 | host->chan_rx = NULL; | ||
94 | dma_release_channel(chan); | ||
95 | /* Free the Tx channel too */ | ||
96 | chan = host->chan_tx; | ||
97 | if (chan) { | ||
98 | host->chan_tx = NULL; | ||
99 | dma_release_channel(chan); | ||
100 | } | ||
101 | dev_warn(&host->pdev->dev, | ||
102 | "DMA failed: %d, falling back to PIO\n", ret); | ||
103 | tmio_mmc_enable_dma(host, false); | ||
104 | } | ||
105 | |||
106 | dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, | ||
107 | desc, cookie, host->sg_len); | ||
108 | } | ||
109 | |||
110 | static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) | ||
111 | { | ||
112 | struct scatterlist *sg = host->sg_ptr, *sg_tmp; | ||
113 | struct dma_async_tx_descriptor *desc = NULL; | ||
114 | struct dma_chan *chan = host->chan_tx; | ||
115 | struct tmio_mmc_data *pdata = host->pdata; | ||
116 | dma_cookie_t cookie; | ||
117 | int ret, i; | ||
118 | bool aligned = true, multiple = true; | ||
119 | unsigned int align = (1 << pdata->dma->alignment_shift) - 1; | ||
120 | |||
121 | for_each_sg(sg, sg_tmp, host->sg_len, i) { | ||
122 | if (sg_tmp->offset & align) | ||
123 | aligned = false; | ||
124 | if (sg_tmp->length & align) { | ||
125 | multiple = false; | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || | ||
131 | (align & PAGE_MASK))) || !multiple) { | ||
132 | ret = -EINVAL; | ||
133 | goto pio; | ||
134 | } | ||
135 | |||
136 | if (sg->length < TMIO_MMC_MIN_DMA_LEN) { | ||
137 | host->force_pio = true; | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ); | ||
142 | |||
143 | /* The only sg element can be unaligned, use our bounce buffer then */ | ||
144 | if (!aligned) { | ||
145 | unsigned long flags; | ||
146 | void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); | ||
147 | sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); | ||
148 | memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); | ||
149 | tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); | ||
150 | host->sg_ptr = &host->bounce_sg; | ||
151 | sg = host->sg_ptr; | ||
152 | } | ||
153 | |||
154 | ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); | ||
155 | if (ret > 0) | ||
156 | desc = chan->device->device_prep_slave_sg(chan, sg, ret, | ||
157 | DMA_TO_DEVICE, DMA_CTRL_ACK); | ||
158 | |||
159 | if (desc) { | ||
160 | cookie = dmaengine_submit(desc); | ||
161 | if (cookie < 0) { | ||
162 | desc = NULL; | ||
163 | ret = cookie; | ||
164 | } | ||
165 | } | ||
166 | dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", | ||
167 | __func__, host->sg_len, ret, cookie, host->mrq); | ||
168 | |||
169 | pio: | ||
170 | if (!desc) { | ||
171 | /* DMA failed, fall back to PIO */ | ||
172 | if (ret >= 0) | ||
173 | ret = -EIO; | ||
174 | host->chan_tx = NULL; | ||
175 | dma_release_channel(chan); | ||
176 | /* Free the Rx channel too */ | ||
177 | chan = host->chan_rx; | ||
178 | if (chan) { | ||
179 | host->chan_rx = NULL; | ||
180 | dma_release_channel(chan); | ||
181 | } | ||
182 | dev_warn(&host->pdev->dev, | ||
183 | "DMA failed: %d, falling back to PIO\n", ret); | ||
184 | tmio_mmc_enable_dma(host, false); | ||
185 | } | ||
186 | |||
187 | dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__, | ||
188 | desc, cookie); | ||
189 | } | ||
190 | |||
191 | void tmio_mmc_start_dma(struct tmio_mmc_host *host, | ||
192 | struct mmc_data *data) | ||
193 | { | ||
194 | if (data->flags & MMC_DATA_READ) { | ||
195 | if (host->chan_rx) | ||
196 | tmio_mmc_start_dma_rx(host); | ||
197 | } else { | ||
198 | if (host->chan_tx) | ||
199 | tmio_mmc_start_dma_tx(host); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static void tmio_mmc_issue_tasklet_fn(unsigned long priv) | ||
204 | { | ||
205 | struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; | ||
206 | struct dma_chan *chan = NULL; | ||
207 | |||
208 | spin_lock_irq(&host->lock); | ||
209 | |||
210 | if (host && host->data) { | ||
211 | if (host->data->flags & MMC_DATA_READ) | ||
212 | chan = host->chan_rx; | ||
213 | else | ||
214 | chan = host->chan_tx; | ||
215 | } | ||
216 | |||
217 | spin_unlock_irq(&host->lock); | ||
218 | |||
219 | tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
220 | |||
221 | if (chan) | ||
222 | dma_async_issue_pending(chan); | ||
223 | } | ||
224 | |||
225 | static void tmio_mmc_tasklet_fn(unsigned long arg) | ||
226 | { | ||
227 | struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; | ||
228 | |||
229 | spin_lock_irq(&host->lock); | ||
230 | |||
231 | if (!host->data) | ||
232 | goto out; | ||
233 | |||
234 | if (host->data->flags & MMC_DATA_READ) | ||
235 | dma_unmap_sg(host->chan_rx->device->dev, | ||
236 | host->sg_ptr, host->sg_len, | ||
237 | DMA_FROM_DEVICE); | ||
238 | else | ||
239 | dma_unmap_sg(host->chan_tx->device->dev, | ||
240 | host->sg_ptr, host->sg_len, | ||
241 | DMA_TO_DEVICE); | ||
242 | |||
243 | tmio_mmc_do_data_irq(host); | ||
244 | out: | ||
245 | spin_unlock_irq(&host->lock); | ||
246 | } | ||
247 | |||
248 | /* It might be necessary to make filter MFD specific */ | ||
249 | static bool tmio_mmc_filter(struct dma_chan *chan, void *arg) | ||
250 | { | ||
251 | dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); | ||
252 | chan->private = arg; | ||
253 | return true; | ||
254 | } | ||
255 | |||
256 | void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) | ||
257 | { | ||
258 | /* We can only either use DMA for both Tx and Rx or not use it at all */ | ||
259 | if (pdata->dma) { | ||
260 | dma_cap_mask_t mask; | ||
261 | |||
262 | dma_cap_zero(mask); | ||
263 | dma_cap_set(DMA_SLAVE, mask); | ||
264 | |||
265 | host->chan_tx = dma_request_channel(mask, tmio_mmc_filter, | ||
266 | pdata->dma->chan_priv_tx); | ||
267 | dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, | ||
268 | host->chan_tx); | ||
269 | |||
270 | if (!host->chan_tx) | ||
271 | return; | ||
272 | |||
273 | host->chan_rx = dma_request_channel(mask, tmio_mmc_filter, | ||
274 | pdata->dma->chan_priv_rx); | ||
275 | dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, | ||
276 | host->chan_rx); | ||
277 | |||
278 | if (!host->chan_rx) | ||
279 | goto ereqrx; | ||
280 | |||
281 | host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA); | ||
282 | if (!host->bounce_buf) | ||
283 | goto ebouncebuf; | ||
284 | |||
285 | tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host); | ||
286 | tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host); | ||
287 | |||
288 | tmio_mmc_enable_dma(host, true); | ||
289 | |||
290 | return; | ||
291 | ebouncebuf: | ||
292 | dma_release_channel(host->chan_rx); | ||
293 | host->chan_rx = NULL; | ||
294 | ereqrx: | ||
295 | dma_release_channel(host->chan_tx); | ||
296 | host->chan_tx = NULL; | ||
297 | return; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | void tmio_mmc_release_dma(struct tmio_mmc_host *host) | ||
302 | { | ||
303 | if (host->chan_tx) { | ||
304 | struct dma_chan *chan = host->chan_tx; | ||
305 | host->chan_tx = NULL; | ||
306 | dma_release_channel(chan); | ||
307 | } | ||
308 | if (host->chan_rx) { | ||
309 | struct dma_chan *chan = host->chan_rx; | ||
310 | host->chan_rx = NULL; | ||
311 | dma_release_channel(chan); | ||
312 | } | ||
313 | if (host->bounce_buf) { | ||
314 | free_pages((unsigned long)host->bounce_buf, 0); | ||
315 | host->bounce_buf = NULL; | ||
316 | } | ||
317 | } | ||
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c new file mode 100644 index 000000000000..6ae8d2f00ec7 --- /dev/null +++ b/drivers/mmc/host/tmio_mmc_pio.c | |||
@@ -0,0 +1,897 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/host/tmio_mmc_pio.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Guennadi Liakhovetski | ||
5 | * Copyright (C) 2007 Ian Molton | ||
6 | * Copyright (C) 2004 Ian Molton | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * Driver for the MMC / SD / SDIO IP found in: | ||
13 | * | ||
14 | * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs | ||
15 | * | ||
16 | * This driver draws mainly on scattered spec sheets, Reverse engineering | ||
17 | * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit | ||
18 | * support). (Further 4 bit support from a later datasheet). | ||
19 | * | ||
20 | * TODO: | ||
21 | * Investigate using a workqueue for PIO transfers | ||
22 | * Eliminate FIXMEs | ||
23 | * SDIO support | ||
24 | * Better Power management | ||
25 | * Handle MMC errors better | ||
26 | * double buffer support | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include <linux/delay.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/highmem.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/io.h> | ||
35 | #include <linux/irq.h> | ||
36 | #include <linux/mfd/tmio.h> | ||
37 | #include <linux/mmc/host.h> | ||
38 | #include <linux/mmc/tmio.h> | ||
39 | #include <linux/module.h> | ||
40 | #include <linux/pagemap.h> | ||
41 | #include <linux/platform_device.h> | ||
42 | #include <linux/scatterlist.h> | ||
43 | #include <linux/workqueue.h> | ||
44 | #include <linux/spinlock.h> | ||
45 | |||
46 | #include "tmio_mmc.h" | ||
47 | |||
48 | static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) | ||
49 | { | ||
50 | return readw(host->ctl + (addr << host->bus_shift)); | ||
51 | } | ||
52 | |||
53 | static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, | ||
54 | u16 *buf, int count) | ||
55 | { | ||
56 | readsw(host->ctl + (addr << host->bus_shift), buf, count); | ||
57 | } | ||
58 | |||
59 | static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) | ||
60 | { | ||
61 | return readw(host->ctl + (addr << host->bus_shift)) | | ||
62 | readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; | ||
63 | } | ||
64 | |||
65 | static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) | ||
66 | { | ||
67 | writew(val, host->ctl + (addr << host->bus_shift)); | ||
68 | } | ||
69 | |||
70 | static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, | ||
71 | u16 *buf, int count) | ||
72 | { | ||
73 | writesw(host->ctl + (addr << host->bus_shift), buf, count); | ||
74 | } | ||
75 | |||
76 | static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) | ||
77 | { | ||
78 | writew(val, host->ctl + (addr << host->bus_shift)); | ||
79 | writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); | ||
80 | } | ||
81 | |||
82 | void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) | ||
83 | { | ||
84 | u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) & ~(i & TMIO_MASK_IRQ); | ||
85 | sd_ctrl_write32(host, CTL_IRQ_MASK, mask); | ||
86 | } | ||
87 | |||
88 | void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) | ||
89 | { | ||
90 | u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) | (i & TMIO_MASK_IRQ); | ||
91 | sd_ctrl_write32(host, CTL_IRQ_MASK, mask); | ||
92 | } | ||
93 | |||
94 | static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) | ||
95 | { | ||
96 | sd_ctrl_write32(host, CTL_STATUS, ~i); | ||
97 | } | ||
98 | |||
99 | static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) | ||
100 | { | ||
101 | host->sg_len = data->sg_len; | ||
102 | host->sg_ptr = data->sg; | ||
103 | host->sg_orig = data->sg; | ||
104 | host->sg_off = 0; | ||
105 | } | ||
106 | |||
107 | static int tmio_mmc_next_sg(struct tmio_mmc_host *host) | ||
108 | { | ||
109 | host->sg_ptr = sg_next(host->sg_ptr); | ||
110 | host->sg_off = 0; | ||
111 | return --host->sg_len; | ||
112 | } | ||
113 | |||
114 | #ifdef CONFIG_MMC_DEBUG | ||
115 | |||
116 | #define STATUS_TO_TEXT(a, status, i) \ | ||
117 | do { \ | ||
118 | if (status & TMIO_STAT_##a) { \ | ||
119 | if (i++) \ | ||
120 | printk(" | "); \ | ||
121 | printk(#a); \ | ||
122 | } \ | ||
123 | } while (0) | ||
124 | |||
125 | static void pr_debug_status(u32 status) | ||
126 | { | ||
127 | int i = 0; | ||
128 | printk(KERN_DEBUG "status: %08x = ", status); | ||
129 | STATUS_TO_TEXT(CARD_REMOVE, status, i); | ||
130 | STATUS_TO_TEXT(CARD_INSERT, status, i); | ||
131 | STATUS_TO_TEXT(SIGSTATE, status, i); | ||
132 | STATUS_TO_TEXT(WRPROTECT, status, i); | ||
133 | STATUS_TO_TEXT(CARD_REMOVE_A, status, i); | ||
134 | STATUS_TO_TEXT(CARD_INSERT_A, status, i); | ||
135 | STATUS_TO_TEXT(SIGSTATE_A, status, i); | ||
136 | STATUS_TO_TEXT(CMD_IDX_ERR, status, i); | ||
137 | STATUS_TO_TEXT(STOPBIT_ERR, status, i); | ||
138 | STATUS_TO_TEXT(ILL_FUNC, status, i); | ||
139 | STATUS_TO_TEXT(CMD_BUSY, status, i); | ||
140 | STATUS_TO_TEXT(CMDRESPEND, status, i); | ||
141 | STATUS_TO_TEXT(DATAEND, status, i); | ||
142 | STATUS_TO_TEXT(CRCFAIL, status, i); | ||
143 | STATUS_TO_TEXT(DATATIMEOUT, status, i); | ||
144 | STATUS_TO_TEXT(CMDTIMEOUT, status, i); | ||
145 | STATUS_TO_TEXT(RXOVERFLOW, status, i); | ||
146 | STATUS_TO_TEXT(TXUNDERRUN, status, i); | ||
147 | STATUS_TO_TEXT(RXRDY, status, i); | ||
148 | STATUS_TO_TEXT(TXRQ, status, i); | ||
149 | STATUS_TO_TEXT(ILL_ACCESS, status, i); | ||
150 | printk("\n"); | ||
151 | } | ||
152 | |||
153 | #else | ||
154 | #define pr_debug_status(s) do { } while (0) | ||
155 | #endif | ||
156 | |||
157 | static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
158 | { | ||
159 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
160 | |||
161 | if (enable) { | ||
162 | host->sdio_irq_enabled = 1; | ||
163 | sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); | ||
164 | sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, | ||
165 | (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); | ||
166 | } else { | ||
167 | sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); | ||
168 | sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); | ||
169 | host->sdio_irq_enabled = 0; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) | ||
174 | { | ||
175 | u32 clk = 0, clock; | ||
176 | |||
177 | if (new_clock) { | ||
178 | for (clock = host->mmc->f_min, clk = 0x80000080; | ||
179 | new_clock >= (clock<<1); clk >>= 1) | ||
180 | clock <<= 1; | ||
181 | clk |= 0x100; | ||
182 | } | ||
183 | |||
184 | if (host->set_clk_div) | ||
185 | host->set_clk_div(host->pdev, (clk>>22) & 1); | ||
186 | |||
187 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); | ||
188 | } | ||
189 | |||
190 | static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) | ||
191 | { | ||
192 | struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); | ||
193 | |||
194 | /* implicit BUG_ON(!res) */ | ||
195 | if (resource_size(res) > 0x100) { | ||
196 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); | ||
197 | msleep(10); | ||
198 | } | ||
199 | |||
200 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & | ||
201 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | ||
202 | msleep(10); | ||
203 | } | ||
204 | |||
205 | static void tmio_mmc_clk_start(struct tmio_mmc_host *host) | ||
206 | { | ||
207 | struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); | ||
208 | |||
209 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | | ||
210 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); | ||
211 | msleep(10); | ||
212 | |||
213 | /* implicit BUG_ON(!res) */ | ||
214 | if (resource_size(res) > 0x100) { | ||
215 | sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); | ||
216 | msleep(10); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static void tmio_mmc_reset(struct tmio_mmc_host *host) | ||
221 | { | ||
222 | struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); | ||
223 | |||
224 | /* FIXME - should we set stop clock reg here */ | ||
225 | sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); | ||
226 | /* implicit BUG_ON(!res) */ | ||
227 | if (resource_size(res) > 0x100) | ||
228 | sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); | ||
229 | msleep(10); | ||
230 | sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); | ||
231 | if (resource_size(res) > 0x100) | ||
232 | sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); | ||
233 | msleep(10); | ||
234 | } | ||
235 | |||
236 | static void tmio_mmc_reset_work(struct work_struct *work) | ||
237 | { | ||
238 | struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, | ||
239 | delayed_reset_work.work); | ||
240 | struct mmc_request *mrq; | ||
241 | unsigned long flags; | ||
242 | |||
243 | spin_lock_irqsave(&host->lock, flags); | ||
244 | mrq = host->mrq; | ||
245 | |||
246 | /* request already finished */ | ||
247 | if (!mrq | ||
248 | || time_is_after_jiffies(host->last_req_ts + | ||
249 | msecs_to_jiffies(2000))) { | ||
250 | spin_unlock_irqrestore(&host->lock, flags); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | dev_warn(&host->pdev->dev, | ||
255 | "timeout waiting for hardware interrupt (CMD%u)\n", | ||
256 | mrq->cmd->opcode); | ||
257 | |||
258 | if (host->data) | ||
259 | host->data->error = -ETIMEDOUT; | ||
260 | else if (host->cmd) | ||
261 | host->cmd->error = -ETIMEDOUT; | ||
262 | else | ||
263 | mrq->cmd->error = -ETIMEDOUT; | ||
264 | |||
265 | host->cmd = NULL; | ||
266 | host->data = NULL; | ||
267 | host->mrq = NULL; | ||
268 | host->force_pio = false; | ||
269 | |||
270 | spin_unlock_irqrestore(&host->lock, flags); | ||
271 | |||
272 | tmio_mmc_reset(host); | ||
273 | |||
274 | mmc_request_done(host->mmc, mrq); | ||
275 | } | ||
276 | |||
277 | static void tmio_mmc_finish_request(struct tmio_mmc_host *host) | ||
278 | { | ||
279 | struct mmc_request *mrq = host->mrq; | ||
280 | |||
281 | if (!mrq) | ||
282 | return; | ||
283 | |||
284 | host->mrq = NULL; | ||
285 | host->cmd = NULL; | ||
286 | host->data = NULL; | ||
287 | host->force_pio = false; | ||
288 | |||
289 | cancel_delayed_work(&host->delayed_reset_work); | ||
290 | |||
291 | mmc_request_done(host->mmc, mrq); | ||
292 | } | ||
293 | |||
294 | /* These are the bitmasks the tmio chip requires to implement the MMC response | ||
295 | * types. Note that R1 and R6 are the same in this scheme. */ | ||
296 | #define APP_CMD 0x0040 | ||
297 | #define RESP_NONE 0x0300 | ||
298 | #define RESP_R1 0x0400 | ||
299 | #define RESP_R1B 0x0500 | ||
300 | #define RESP_R2 0x0600 | ||
301 | #define RESP_R3 0x0700 | ||
302 | #define DATA_PRESENT 0x0800 | ||
303 | #define TRANSFER_READ 0x1000 | ||
304 | #define TRANSFER_MULTI 0x2000 | ||
305 | #define SECURITY_CMD 0x4000 | ||
306 | |||
307 | static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) | ||
308 | { | ||
309 | struct mmc_data *data = host->data; | ||
310 | int c = cmd->opcode; | ||
311 | |||
312 | /* Command 12 is handled by hardware */ | ||
313 | if (cmd->opcode == 12 && !cmd->arg) { | ||
314 | sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | switch (mmc_resp_type(cmd)) { | ||
319 | case MMC_RSP_NONE: c |= RESP_NONE; break; | ||
320 | case MMC_RSP_R1: c |= RESP_R1; break; | ||
321 | case MMC_RSP_R1B: c |= RESP_R1B; break; | ||
322 | case MMC_RSP_R2: c |= RESP_R2; break; | ||
323 | case MMC_RSP_R3: c |= RESP_R3; break; | ||
324 | default: | ||
325 | pr_debug("Unknown response type %d\n", mmc_resp_type(cmd)); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | |||
329 | host->cmd = cmd; | ||
330 | |||
331 | /* FIXME - this seems to be ok commented out but the spec suggest this bit | ||
332 | * should be set when issuing app commands. | ||
333 | * if(cmd->flags & MMC_FLAG_ACMD) | ||
334 | * c |= APP_CMD; | ||
335 | */ | ||
336 | if (data) { | ||
337 | c |= DATA_PRESENT; | ||
338 | if (data->blocks > 1) { | ||
339 | sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100); | ||
340 | c |= TRANSFER_MULTI; | ||
341 | } | ||
342 | if (data->flags & MMC_DATA_READ) | ||
343 | c |= TRANSFER_READ; | ||
344 | } | ||
345 | |||
346 | tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_CMD); | ||
347 | |||
348 | /* Fire off the command */ | ||
349 | sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); | ||
350 | sd_ctrl_write16(host, CTL_SD_CMD, c); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * This chip always returns (at least?) as much data as you ask for. | ||
357 | * I'm unsure what happens if you ask for less than a block. This should be | ||
358 | * looked into to ensure that a funny length read doesnt hose the controller. | ||
359 | */ | ||
360 | static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) | ||
361 | { | ||
362 | struct mmc_data *data = host->data; | ||
363 | void *sg_virt; | ||
364 | unsigned short *buf; | ||
365 | unsigned int count; | ||
366 | unsigned long flags; | ||
367 | |||
368 | if ((host->chan_tx || host->chan_rx) && !host->force_pio) { | ||
369 | pr_err("PIO IRQ in DMA mode!\n"); | ||
370 | return; | ||
371 | } else if (!data) { | ||
372 | pr_debug("Spurious PIO IRQ\n"); | ||
373 | return; | ||
374 | } | ||
375 | |||
376 | sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); | ||
377 | buf = (unsigned short *)(sg_virt + host->sg_off); | ||
378 | |||
379 | count = host->sg_ptr->length - host->sg_off; | ||
380 | if (count > data->blksz) | ||
381 | count = data->blksz; | ||
382 | |||
383 | pr_debug("count: %08x offset: %08x flags %08x\n", | ||
384 | count, host->sg_off, data->flags); | ||
385 | |||
386 | /* Transfer the data */ | ||
387 | if (data->flags & MMC_DATA_READ) | ||
388 | sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); | ||
389 | else | ||
390 | sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); | ||
391 | |||
392 | host->sg_off += count; | ||
393 | |||
394 | tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt); | ||
395 | |||
396 | if (host->sg_off == host->sg_ptr->length) | ||
397 | tmio_mmc_next_sg(host); | ||
398 | |||
399 | return; | ||
400 | } | ||
401 | |||
402 | static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host) | ||
403 | { | ||
404 | if (host->sg_ptr == &host->bounce_sg) { | ||
405 | unsigned long flags; | ||
406 | void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); | ||
407 | memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); | ||
408 | tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | /* needs to be called with host->lock held */ | ||
413 | void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) | ||
414 | { | ||
415 | struct mmc_data *data = host->data; | ||
416 | struct mmc_command *stop; | ||
417 | |||
418 | host->data = NULL; | ||
419 | |||
420 | if (!data) { | ||
421 | dev_warn(&host->pdev->dev, "Spurious data end IRQ\n"); | ||
422 | return; | ||
423 | } | ||
424 | stop = data->stop; | ||
425 | |||
426 | /* FIXME - return correct transfer count on errors */ | ||
427 | if (!data->error) | ||
428 | data->bytes_xfered = data->blocks * data->blksz; | ||
429 | else | ||
430 | data->bytes_xfered = 0; | ||
431 | |||
432 | pr_debug("Completed data request\n"); | ||
433 | |||
434 | /* | ||
435 | * FIXME: other drivers allow an optional stop command of any given type | ||
436 | * which we dont do, as the chip can auto generate them. | ||
437 | * Perhaps we can be smarter about when to use auto CMD12 and | ||
438 | * only issue the auto request when we know this is the desired | ||
439 | * stop command, allowing fallback to the stop command the | ||
440 | * upper layers expect. For now, we do what works. | ||
441 | */ | ||
442 | |||
443 | if (data->flags & MMC_DATA_READ) { | ||
444 | if (host->chan_rx && !host->force_pio) | ||
445 | tmio_mmc_check_bounce_buffer(host); | ||
446 | dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", | ||
447 | host->mrq); | ||
448 | } else { | ||
449 | dev_dbg(&host->pdev->dev, "Complete Tx request %p\n", | ||
450 | host->mrq); | ||
451 | } | ||
452 | |||
453 | if (stop) { | ||
454 | if (stop->opcode == 12 && !stop->arg) | ||
455 | sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); | ||
456 | else | ||
457 | BUG(); | ||
458 | } | ||
459 | |||
460 | tmio_mmc_finish_request(host); | ||
461 | } | ||
462 | |||
463 | static void tmio_mmc_data_irq(struct tmio_mmc_host *host) | ||
464 | { | ||
465 | struct mmc_data *data; | ||
466 | spin_lock(&host->lock); | ||
467 | data = host->data; | ||
468 | |||
469 | if (!data) | ||
470 | goto out; | ||
471 | |||
472 | if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) { | ||
473 | /* | ||
474 | * Has all data been written out yet? Testing on SuperH showed, | ||
475 | * that in most cases the first interrupt comes already with the | ||
476 | * BUSY status bit clear, but on some operations, like mount or | ||
477 | * in the beginning of a write / sync / umount, there is one | ||
478 | * DATAEND interrupt with the BUSY bit set, in this cases | ||
479 | * waiting for one more interrupt fixes the problem. | ||
480 | */ | ||
481 | if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) { | ||
482 | tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
483 | tasklet_schedule(&host->dma_complete); | ||
484 | } | ||
485 | } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) { | ||
486 | tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
487 | tasklet_schedule(&host->dma_complete); | ||
488 | } else { | ||
489 | tmio_mmc_do_data_irq(host); | ||
490 | tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP); | ||
491 | } | ||
492 | out: | ||
493 | spin_unlock(&host->lock); | ||
494 | } | ||
495 | |||
496 | static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, | ||
497 | unsigned int stat) | ||
498 | { | ||
499 | struct mmc_command *cmd = host->cmd; | ||
500 | int i, addr; | ||
501 | |||
502 | spin_lock(&host->lock); | ||
503 | |||
504 | if (!host->cmd) { | ||
505 | pr_debug("Spurious CMD irq\n"); | ||
506 | goto out; | ||
507 | } | ||
508 | |||
509 | host->cmd = NULL; | ||
510 | |||
511 | /* This controller is sicker than the PXA one. Not only do we need to | ||
512 | * drop the top 8 bits of the first response word, we also need to | ||
513 | * modify the order of the response for short response command types. | ||
514 | */ | ||
515 | |||
516 | for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4) | ||
517 | cmd->resp[i] = sd_ctrl_read32(host, addr); | ||
518 | |||
519 | if (cmd->flags & MMC_RSP_136) { | ||
520 | cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); | ||
521 | cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24); | ||
522 | cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24); | ||
523 | cmd->resp[3] <<= 8; | ||
524 | } else if (cmd->flags & MMC_RSP_R3) { | ||
525 | cmd->resp[0] = cmd->resp[3]; | ||
526 | } | ||
527 | |||
528 | if (stat & TMIO_STAT_CMDTIMEOUT) | ||
529 | cmd->error = -ETIMEDOUT; | ||
530 | else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) | ||
531 | cmd->error = -EILSEQ; | ||
532 | |||
533 | /* If there is data to handle we enable data IRQs here, and | ||
534 | * we will ultimatley finish the request in the data_end handler. | ||
535 | * If theres no data or we encountered an error, finish now. | ||
536 | */ | ||
537 | if (host->data && !cmd->error) { | ||
538 | if (host->data->flags & MMC_DATA_READ) { | ||
539 | if (host->force_pio || !host->chan_rx) | ||
540 | tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP); | ||
541 | else | ||
542 | tasklet_schedule(&host->dma_issue); | ||
543 | } else { | ||
544 | if (host->force_pio || !host->chan_tx) | ||
545 | tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP); | ||
546 | else | ||
547 | tasklet_schedule(&host->dma_issue); | ||
548 | } | ||
549 | } else { | ||
550 | tmio_mmc_finish_request(host); | ||
551 | } | ||
552 | |||
553 | out: | ||
554 | spin_unlock(&host->lock); | ||
555 | } | ||
556 | |||
557 | static irqreturn_t tmio_mmc_irq(int irq, void *devid) | ||
558 | { | ||
559 | struct tmio_mmc_host *host = devid; | ||
560 | struct tmio_mmc_data *pdata = host->pdata; | ||
561 | unsigned int ireg, irq_mask, status; | ||
562 | unsigned int sdio_ireg, sdio_irq_mask, sdio_status; | ||
563 | |||
564 | pr_debug("MMC IRQ begin\n"); | ||
565 | |||
566 | status = sd_ctrl_read32(host, CTL_STATUS); | ||
567 | irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); | ||
568 | ireg = status & TMIO_MASK_IRQ & ~irq_mask; | ||
569 | |||
570 | sdio_ireg = 0; | ||
571 | if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||
572 | sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); | ||
573 | sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); | ||
574 | sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; | ||
575 | |||
576 | sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); | ||
577 | |||
578 | if (sdio_ireg && !host->sdio_irq_enabled) { | ||
579 | pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", | ||
580 | sdio_status, sdio_irq_mask, sdio_ireg); | ||
581 | tmio_mmc_enable_sdio_irq(host->mmc, 0); | ||
582 | goto out; | ||
583 | } | ||
584 | |||
585 | if (host->mmc->caps & MMC_CAP_SDIO_IRQ && | ||
586 | sdio_ireg & TMIO_SDIO_STAT_IOIRQ) | ||
587 | mmc_signal_sdio_irq(host->mmc); | ||
588 | |||
589 | if (sdio_ireg) | ||
590 | goto out; | ||
591 | } | ||
592 | |||
593 | pr_debug_status(status); | ||
594 | pr_debug_status(ireg); | ||
595 | |||
596 | if (!ireg) { | ||
597 | tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask); | ||
598 | |||
599 | pr_warning("tmio_mmc: Spurious irq, disabling! " | ||
600 | "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); | ||
601 | pr_debug_status(status); | ||
602 | |||
603 | goto out; | ||
604 | } | ||
605 | |||
606 | while (ireg) { | ||
607 | /* Card insert / remove attempts */ | ||
608 | if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { | ||
609 | tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | | ||
610 | TMIO_STAT_CARD_REMOVE); | ||
611 | mmc_detect_change(host->mmc, msecs_to_jiffies(100)); | ||
612 | } | ||
613 | |||
614 | /* CRC and other errors */ | ||
615 | /* if (ireg & TMIO_STAT_ERR_IRQ) | ||
616 | * handled |= tmio_error_irq(host, irq, stat); | ||
617 | */ | ||
618 | |||
619 | /* Command completion */ | ||
620 | if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { | ||
621 | tmio_mmc_ack_mmc_irqs(host, | ||
622 | TMIO_STAT_CMDRESPEND | | ||
623 | TMIO_STAT_CMDTIMEOUT); | ||
624 | tmio_mmc_cmd_irq(host, status); | ||
625 | } | ||
626 | |||
627 | /* Data transfer */ | ||
628 | if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { | ||
629 | tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); | ||
630 | tmio_mmc_pio_irq(host); | ||
631 | } | ||
632 | |||
633 | /* Data transfer completion */ | ||
634 | if (ireg & TMIO_STAT_DATAEND) { | ||
635 | tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND); | ||
636 | tmio_mmc_data_irq(host); | ||
637 | } | ||
638 | |||
639 | /* Check status - keep going until we've handled it all */ | ||
640 | status = sd_ctrl_read32(host, CTL_STATUS); | ||
641 | irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); | ||
642 | ireg = status & TMIO_MASK_IRQ & ~irq_mask; | ||
643 | |||
644 | pr_debug("Status at end of loop: %08x\n", status); | ||
645 | pr_debug_status(status); | ||
646 | } | ||
647 | pr_debug("MMC IRQ end\n"); | ||
648 | |||
649 | out: | ||
650 | return IRQ_HANDLED; | ||
651 | } | ||
652 | |||
653 | static int tmio_mmc_start_data(struct tmio_mmc_host *host, | ||
654 | struct mmc_data *data) | ||
655 | { | ||
656 | struct tmio_mmc_data *pdata = host->pdata; | ||
657 | |||
658 | pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", | ||
659 | data->blksz, data->blocks); | ||
660 | |||
661 | /* Some hardware cannot perform 2 byte requests in 4 bit mode */ | ||
662 | if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { | ||
663 | int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES; | ||
664 | |||
665 | if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) { | ||
666 | pr_err("%s: %d byte block unsupported in 4 bit mode\n", | ||
667 | mmc_hostname(host->mmc), data->blksz); | ||
668 | return -EINVAL; | ||
669 | } | ||
670 | } | ||
671 | |||
672 | tmio_mmc_init_sg(host, data); | ||
673 | host->data = data; | ||
674 | |||
675 | /* Set transfer length / blocksize */ | ||
676 | sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); | ||
677 | sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); | ||
678 | |||
679 | tmio_mmc_start_dma(host, data); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | /* Process requests from the MMC layer */ | ||
685 | static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | ||
686 | { | ||
687 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
688 | int ret; | ||
689 | |||
690 | if (host->mrq) | ||
691 | pr_debug("request not null\n"); | ||
692 | |||
693 | host->last_req_ts = jiffies; | ||
694 | wmb(); | ||
695 | host->mrq = mrq; | ||
696 | |||
697 | if (mrq->data) { | ||
698 | ret = tmio_mmc_start_data(host, mrq->data); | ||
699 | if (ret) | ||
700 | goto fail; | ||
701 | } | ||
702 | |||
703 | ret = tmio_mmc_start_command(host, mrq->cmd); | ||
704 | if (!ret) { | ||
705 | schedule_delayed_work(&host->delayed_reset_work, | ||
706 | msecs_to_jiffies(2000)); | ||
707 | return; | ||
708 | } | ||
709 | |||
710 | fail: | ||
711 | host->mrq = NULL; | ||
712 | host->force_pio = false; | ||
713 | mrq->cmd->error = ret; | ||
714 | mmc_request_done(mmc, mrq); | ||
715 | } | ||
716 | |||
717 | /* Set MMC clock / power. | ||
718 | * Note: This controller uses a simple divider scheme therefore it cannot | ||
719 | * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as | ||
720 | * MMC wont run that fast, it has to be clocked at 12MHz which is the next | ||
721 | * slowest setting. | ||
722 | */ | ||
723 | static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||
724 | { | ||
725 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
726 | |||
727 | if (ios->clock) | ||
728 | tmio_mmc_set_clock(host, ios->clock); | ||
729 | |||
730 | /* Power sequence - OFF -> UP -> ON */ | ||
731 | if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { | ||
732 | /* power down SD bus */ | ||
733 | if (ios->power_mode == MMC_POWER_OFF && host->set_pwr) | ||
734 | host->set_pwr(host->pdev, 0); | ||
735 | tmio_mmc_clk_stop(host); | ||
736 | } else if (ios->power_mode == MMC_POWER_UP) { | ||
737 | /* power up SD bus */ | ||
738 | if (host->set_pwr) | ||
739 | host->set_pwr(host->pdev, 1); | ||
740 | } else { | ||
741 | /* start bus clock */ | ||
742 | tmio_mmc_clk_start(host); | ||
743 | } | ||
744 | |||
745 | switch (ios->bus_width) { | ||
746 | case MMC_BUS_WIDTH_1: | ||
747 | sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); | ||
748 | break; | ||
749 | case MMC_BUS_WIDTH_4: | ||
750 | sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); | ||
751 | break; | ||
752 | } | ||
753 | |||
754 | /* Let things settle. delay taken from winCE driver */ | ||
755 | udelay(140); | ||
756 | } | ||
757 | |||
758 | static int tmio_mmc_get_ro(struct mmc_host *mmc) | ||
759 | { | ||
760 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
761 | struct tmio_mmc_data *pdata = host->pdata; | ||
762 | |||
763 | return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || | ||
764 | !(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); | ||
765 | } | ||
766 | |||
767 | static int tmio_mmc_get_cd(struct mmc_host *mmc) | ||
768 | { | ||
769 | struct tmio_mmc_host *host = mmc_priv(mmc); | ||
770 | struct tmio_mmc_data *pdata = host->pdata; | ||
771 | |||
772 | if (!pdata->get_cd) | ||
773 | return -ENOSYS; | ||
774 | else | ||
775 | return pdata->get_cd(host->pdev); | ||
776 | } | ||
777 | |||
778 | static const struct mmc_host_ops tmio_mmc_ops = { | ||
779 | .request = tmio_mmc_request, | ||
780 | .set_ios = tmio_mmc_set_ios, | ||
781 | .get_ro = tmio_mmc_get_ro, | ||
782 | .get_cd = tmio_mmc_get_cd, | ||
783 | .enable_sdio_irq = tmio_mmc_enable_sdio_irq, | ||
784 | }; | ||
785 | |||
786 | int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, | ||
787 | struct platform_device *pdev, | ||
788 | struct tmio_mmc_data *pdata) | ||
789 | { | ||
790 | struct tmio_mmc_host *_host; | ||
791 | struct mmc_host *mmc; | ||
792 | struct resource *res_ctl; | ||
793 | int ret; | ||
794 | u32 irq_mask = TMIO_MASK_CMD; | ||
795 | |||
796 | res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
797 | if (!res_ctl) | ||
798 | return -EINVAL; | ||
799 | |||
800 | mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); | ||
801 | if (!mmc) | ||
802 | return -ENOMEM; | ||
803 | |||
804 | _host = mmc_priv(mmc); | ||
805 | _host->pdata = pdata; | ||
806 | _host->mmc = mmc; | ||
807 | _host->pdev = pdev; | ||
808 | platform_set_drvdata(pdev, mmc); | ||
809 | |||
810 | _host->set_pwr = pdata->set_pwr; | ||
811 | _host->set_clk_div = pdata->set_clk_div; | ||
812 | |||
813 | /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ | ||
814 | _host->bus_shift = resource_size(res_ctl) >> 10; | ||
815 | |||
816 | _host->ctl = ioremap(res_ctl->start, resource_size(res_ctl)); | ||
817 | if (!_host->ctl) { | ||
818 | ret = -ENOMEM; | ||
819 | goto host_free; | ||
820 | } | ||
821 | |||
822 | mmc->ops = &tmio_mmc_ops; | ||
823 | mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; | ||
824 | mmc->f_max = pdata->hclk; | ||
825 | mmc->f_min = mmc->f_max / 512; | ||
826 | mmc->max_segs = 32; | ||
827 | mmc->max_blk_size = 512; | ||
828 | mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * | ||
829 | mmc->max_segs; | ||
830 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; | ||
831 | mmc->max_seg_size = mmc->max_req_size; | ||
832 | if (pdata->ocr_mask) | ||
833 | mmc->ocr_avail = pdata->ocr_mask; | ||
834 | else | ||
835 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | ||
836 | |||
837 | tmio_mmc_clk_stop(_host); | ||
838 | tmio_mmc_reset(_host); | ||
839 | |||
840 | ret = platform_get_irq(pdev, 0); | ||
841 | if (ret < 0) | ||
842 | goto unmap_ctl; | ||
843 | |||
844 | _host->irq = ret; | ||
845 | |||
846 | tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); | ||
847 | if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||
848 | tmio_mmc_enable_sdio_irq(mmc, 0); | ||
849 | |||
850 | ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED | | ||
851 | IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host); | ||
852 | if (ret) | ||
853 | goto unmap_ctl; | ||
854 | |||
855 | spin_lock_init(&_host->lock); | ||
856 | |||
857 | /* Init delayed work for request timeouts */ | ||
858 | INIT_DELAYED_WORK(&_host->delayed_reset_work, tmio_mmc_reset_work); | ||
859 | |||
860 | /* See if we also get DMA */ | ||
861 | tmio_mmc_request_dma(_host, pdata); | ||
862 | |||
863 | mmc_add_host(mmc); | ||
864 | |||
865 | /* Unmask the IRQs we want to know about */ | ||
866 | if (!_host->chan_rx) | ||
867 | irq_mask |= TMIO_MASK_READOP; | ||
868 | if (!_host->chan_tx) | ||
869 | irq_mask |= TMIO_MASK_WRITEOP; | ||
870 | |||
871 | tmio_mmc_enable_mmc_irqs(_host, irq_mask); | ||
872 | |||
873 | *host = _host; | ||
874 | |||
875 | return 0; | ||
876 | |||
877 | unmap_ctl: | ||
878 | iounmap(_host->ctl); | ||
879 | host_free: | ||
880 | mmc_free_host(mmc); | ||
881 | |||
882 | return ret; | ||
883 | } | ||
884 | EXPORT_SYMBOL(tmio_mmc_host_probe); | ||
885 | |||
886 | void tmio_mmc_host_remove(struct tmio_mmc_host *host) | ||
887 | { | ||
888 | mmc_remove_host(host->mmc); | ||
889 | cancel_delayed_work_sync(&host->delayed_reset_work); | ||
890 | tmio_mmc_release_dma(host); | ||
891 | free_irq(host->irq, host); | ||
892 | iounmap(host->ctl); | ||
893 | mmc_free_host(host->mmc); | ||
894 | } | ||
895 | EXPORT_SYMBOL(tmio_mmc_host_remove); | ||
896 | |||
897 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 8c5b4881ccd6..4dfe2c02ea91 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c | |||
@@ -1087,14 +1087,13 @@ static int __devinit via_sd_probe(struct pci_dev *pcidev, | |||
1087 | struct mmc_host *mmc; | 1087 | struct mmc_host *mmc; |
1088 | struct via_crdr_mmc_host *sdhost; | 1088 | struct via_crdr_mmc_host *sdhost; |
1089 | u32 base, len; | 1089 | u32 base, len; |
1090 | u8 rev, gatt; | 1090 | u8 gatt; |
1091 | int ret; | 1091 | int ret; |
1092 | 1092 | ||
1093 | pci_read_config_byte(pcidev, PCI_CLASS_REVISION, &rev); | ||
1094 | pr_info(DRV_NAME | 1093 | pr_info(DRV_NAME |
1095 | ": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n", | 1094 | ": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n", |
1096 | pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, | 1095 | pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, |
1097 | (int)rev); | 1096 | (int)pcidev->revision); |
1098 | 1097 | ||
1099 | ret = pci_enable_device(pcidev); | 1098 | ret = pci_enable_device(pcidev); |
1100 | if (ret) | 1099 | if (ret) |
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 22abfb39d813..68d45ba2d9b9 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c | |||
@@ -1237,8 +1237,17 @@ static int bfin_mac_enable(struct phy_device *phydev) | |||
1237 | 1237 | ||
1238 | if (phydev->interface == PHY_INTERFACE_MODE_RMII) { | 1238 | if (phydev->interface == PHY_INTERFACE_MODE_RMII) { |
1239 | opmode |= RMII; /* For Now only 100MBit are supported */ | 1239 | opmode |= RMII; /* For Now only 100MBit are supported */ |
1240 | #if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) && CONFIG_BF_REV_0_2 | 1240 | #if defined(CONFIG_BF537) || defined(CONFIG_BF536) |
1241 | opmode |= TE; | 1241 | if (__SILICON_REVISION__ < 3) { |
1242 | /* | ||
1243 | * This isn't publicly documented (fun times!), but in | ||
1244 | * silicon <=0.2, the RX and TX pins are clocked together. | ||
1245 | * So in order to recv, we must enable the transmit side | ||
1246 | * as well. This will cause a spurious TX interrupt too, | ||
1247 | * but we can easily consume that. | ||
1248 | */ | ||
1249 | opmode |= TE; | ||
1250 | } | ||
1242 | #endif | 1251 | #endif |
1243 | } | 1252 | } |
1244 | 1253 | ||
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d1865cc97313..8e6d618b5305 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -8317,7 +8317,7 @@ static const struct net_device_ops bnx2_netdev_ops = { | |||
8317 | #endif | 8317 | #endif |
8318 | }; | 8318 | }; |
8319 | 8319 | ||
8320 | static void inline vlan_features_add(struct net_device *dev, u32 flags) | 8320 | static inline void vlan_features_add(struct net_device *dev, u32 flags) |
8321 | { | 8321 | { |
8322 | dev->vlan_features |= flags; | 8322 | dev->vlan_features |= flags; |
8323 | } | 8323 | } |
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 110eda01843c..31552959aed7 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c | |||
@@ -588,14 +588,9 @@ static void c_can_chip_config(struct net_device *dev) | |||
588 | { | 588 | { |
589 | struct c_can_priv *priv = netdev_priv(dev); | 589 | struct c_can_priv *priv = netdev_priv(dev); |
590 | 590 | ||
591 | if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) | 591 | /* enable automatic retransmission */ |
592 | /* disable automatic retransmission */ | 592 | priv->write_reg(priv, &priv->regs->control, |
593 | priv->write_reg(priv, &priv->regs->control, | 593 | CONTROL_ENABLE_AR); |
594 | CONTROL_DISABLE_AR); | ||
595 | else | ||
596 | /* enable automatic retransmission */ | ||
597 | priv->write_reg(priv, &priv->regs->control, | ||
598 | CONTROL_ENABLE_AR); | ||
599 | 594 | ||
600 | if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY & | 595 | if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY & |
601 | CAN_CTRLMODE_LOOPBACK)) { | 596 | CAN_CTRLMODE_LOOPBACK)) { |
@@ -704,7 +699,6 @@ static void c_can_do_tx(struct net_device *dev) | |||
704 | 699 | ||
705 | for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { | 700 | for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { |
706 | msg_obj_no = get_tx_echo_msg_obj(priv); | 701 | msg_obj_no = get_tx_echo_msg_obj(priv); |
707 | c_can_inval_msg_object(dev, 0, msg_obj_no); | ||
708 | val = c_can_read_reg32(priv, &priv->regs->txrqst1); | 702 | val = c_can_read_reg32(priv, &priv->regs->txrqst1); |
709 | if (!(val & (1 << msg_obj_no))) { | 703 | if (!(val & (1 << msg_obj_no))) { |
710 | can_get_echo_skb(dev, | 704 | can_get_echo_skb(dev, |
@@ -713,6 +707,7 @@ static void c_can_do_tx(struct net_device *dev) | |||
713 | &priv->regs->ifregs[0].msg_cntrl) | 707 | &priv->regs->ifregs[0].msg_cntrl) |
714 | & IF_MCONT_DLC_MASK; | 708 | & IF_MCONT_DLC_MASK; |
715 | stats->tx_packets++; | 709 | stats->tx_packets++; |
710 | c_can_inval_msg_object(dev, 0, msg_obj_no); | ||
716 | } | 711 | } |
717 | } | 712 | } |
718 | 713 | ||
@@ -1112,8 +1107,7 @@ struct net_device *alloc_c_can_dev(void) | |||
1112 | priv->can.bittiming_const = &c_can_bittiming_const; | 1107 | priv->can.bittiming_const = &c_can_bittiming_const; |
1113 | priv->can.do_set_mode = c_can_set_mode; | 1108 | priv->can.do_set_mode = c_can_set_mode; |
1114 | priv->can.do_get_berr_counter = c_can_get_berr_counter; | 1109 | priv->can.do_get_berr_counter = c_can_get_berr_counter; |
1115 | priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT | | 1110 | priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | |
1116 | CAN_CTRLMODE_LOOPBACK | | ||
1117 | CAN_CTRLMODE_LISTENONLY | | 1111 | CAN_CTRLMODE_LISTENONLY | |
1118 | CAN_CTRLMODE_BERR_REPORTING; | 1112 | CAN_CTRLMODE_BERR_REPORTING; |
1119 | 1113 | ||
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index e629b961ae2d..cc90824f2c9c 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c | |||
@@ -73,7 +73,8 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) | |||
73 | void __iomem *addr; | 73 | void __iomem *addr; |
74 | struct net_device *dev; | 74 | struct net_device *dev; |
75 | struct c_can_priv *priv; | 75 | struct c_can_priv *priv; |
76 | struct resource *mem, *irq; | 76 | struct resource *mem; |
77 | int irq; | ||
77 | #ifdef CONFIG_HAVE_CLK | 78 | #ifdef CONFIG_HAVE_CLK |
78 | struct clk *clk; | 79 | struct clk *clk; |
79 | 80 | ||
@@ -88,8 +89,8 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) | |||
88 | 89 | ||
89 | /* get the platform data */ | 90 | /* get the platform data */ |
90 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 91 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
91 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 92 | irq = platform_get_irq(pdev, 0); |
92 | if (!mem || (irq <= 0)) { | 93 | if (!mem || irq <= 0) { |
93 | ret = -ENODEV; | 94 | ret = -ENODEV; |
94 | goto exit_free_clk; | 95 | goto exit_free_clk; |
95 | } | 96 | } |
@@ -117,7 +118,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) | |||
117 | 118 | ||
118 | priv = netdev_priv(dev); | 119 | priv = netdev_priv(dev); |
119 | 120 | ||
120 | dev->irq = irq->start; | 121 | dev->irq = irq; |
121 | priv->regs = addr; | 122 | priv->regs = addr; |
122 | #ifdef CONFIG_HAVE_CLK | 123 | #ifdef CONFIG_HAVE_CLK |
123 | priv->can.clock.freq = clk_get_rate(clk); | 124 | priv->can.clock.freq = clk_get_rate(clk); |
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 4d538a4e9d55..910893143295 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c | |||
@@ -1983,14 +1983,20 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) | |||
1983 | { | 1983 | { |
1984 | struct port_info *pi = netdev_priv(dev); | 1984 | struct port_info *pi = netdev_priv(dev); |
1985 | struct adapter *adapter = pi->adapter; | 1985 | struct adapter *adapter = pi->adapter; |
1986 | struct qset_params *qsp = &adapter->params.sge.qset[0]; | 1986 | struct qset_params *qsp; |
1987 | struct sge_qset *qs = &adapter->sge.qs[0]; | 1987 | struct sge_qset *qs; |
1988 | int i; | ||
1988 | 1989 | ||
1989 | if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) | 1990 | if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) |
1990 | return -EINVAL; | 1991 | return -EINVAL; |
1991 | 1992 | ||
1992 | qsp->coalesce_usecs = c->rx_coalesce_usecs; | 1993 | for (i = 0; i < pi->nqsets; i++) { |
1993 | t3_update_qset_coalesce(qs, qsp); | 1994 | qsp = &adapter->params.sge.qset[i]; |
1995 | qs = &adapter->sge.qs[i]; | ||
1996 | qsp->coalesce_usecs = c->rx_coalesce_usecs; | ||
1997 | t3_update_qset_coalesce(qs, qsp); | ||
1998 | } | ||
1999 | |||
1994 | return 0; | 2000 | return 0; |
1995 | } | 2001 | } |
1996 | 2002 | ||
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 317708113601..b7af5bab9937 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c | |||
@@ -621,9 +621,9 @@ static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) | |||
621 | /* change in wol state, update IRQ state */ | 621 | /* change in wol state, update IRQ state */ |
622 | 622 | ||
623 | if (!dm->wake_state) | 623 | if (!dm->wake_state) |
624 | set_irq_wake(dm->irq_wake, 1); | 624 | irq_set_irq_wake(dm->irq_wake, 1); |
625 | else if (dm->wake_state & !opts) | 625 | else if (dm->wake_state & !opts) |
626 | set_irq_wake(dm->irq_wake, 0); | 626 | irq_set_irq_wake(dm->irq_wake, 0); |
627 | } | 627 | } |
628 | 628 | ||
629 | dm->wake_state = opts; | 629 | dm->wake_state = opts; |
@@ -1424,13 +1424,13 @@ dm9000_probe(struct platform_device *pdev) | |||
1424 | } else { | 1424 | } else { |
1425 | 1425 | ||
1426 | /* test to see if irq is really wakeup capable */ | 1426 | /* test to see if irq is really wakeup capable */ |
1427 | ret = set_irq_wake(db->irq_wake, 1); | 1427 | ret = irq_set_irq_wake(db->irq_wake, 1); |
1428 | if (ret) { | 1428 | if (ret) { |
1429 | dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", | 1429 | dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", |
1430 | db->irq_wake, ret); | 1430 | db->irq_wake, ret); |
1431 | ret = 0; | 1431 | ret = 0; |
1432 | } else { | 1432 | } else { |
1433 | set_irq_wake(db->irq_wake, 0); | 1433 | irq_set_irq_wake(db->irq_wake, 0); |
1434 | db->wake_supported = 1; | 1434 | db->wake_supported = 1; |
1435 | } | 1435 | } |
1436 | } | 1436 | } |
diff --git a/drivers/net/jme.c b/drivers/net/jme.c index f690474f4409..994c80939c7a 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c | |||
@@ -273,7 +273,7 @@ jme_clear_pm(struct jme_adapter *jme) | |||
273 | { | 273 | { |
274 | jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); | 274 | jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); |
275 | pci_set_power_state(jme->pdev, PCI_D0); | 275 | pci_set_power_state(jme->pdev, PCI_D0); |
276 | pci_enable_wake(jme->pdev, PCI_D0, false); | 276 | device_set_wakeup_enable(&jme->pdev->dev, false); |
277 | } | 277 | } |
278 | 278 | ||
279 | static int | 279 | static int |
@@ -2538,6 +2538,8 @@ jme_set_wol(struct net_device *netdev, | |||
2538 | 2538 | ||
2539 | jwrite32(jme, JME_PMCS, jme->reg_pmcs); | 2539 | jwrite32(jme, JME_PMCS, jme->reg_pmcs); |
2540 | 2540 | ||
2541 | device_set_wakeup_enable(&jme->pdev->dev, jme->reg_pmcs); | ||
2542 | |||
2541 | return 0; | 2543 | return 0; |
2542 | } | 2544 | } |
2543 | 2545 | ||
@@ -3172,9 +3174,9 @@ jme_shutdown(struct pci_dev *pdev) | |||
3172 | } | 3174 | } |
3173 | 3175 | ||
3174 | #ifdef CONFIG_PM | 3176 | #ifdef CONFIG_PM |
3175 | static int | 3177 | static int jme_suspend(struct device *dev) |
3176 | jme_suspend(struct pci_dev *pdev, pm_message_t state) | ||
3177 | { | 3178 | { |
3179 | struct pci_dev *pdev = to_pci_dev(dev); | ||
3178 | struct net_device *netdev = pci_get_drvdata(pdev); | 3180 | struct net_device *netdev = pci_get_drvdata(pdev); |
3179 | struct jme_adapter *jme = netdev_priv(netdev); | 3181 | struct jme_adapter *jme = netdev_priv(netdev); |
3180 | 3182 | ||
@@ -3206,22 +3208,18 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) | |||
3206 | tasklet_hi_enable(&jme->rxclean_task); | 3208 | tasklet_hi_enable(&jme->rxclean_task); |
3207 | tasklet_hi_enable(&jme->rxempty_task); | 3209 | tasklet_hi_enable(&jme->rxempty_task); |
3208 | 3210 | ||
3209 | pci_save_state(pdev); | ||
3210 | jme_powersave_phy(jme); | 3211 | jme_powersave_phy(jme); |
3211 | pci_enable_wake(jme->pdev, PCI_D3hot, true); | ||
3212 | pci_set_power_state(pdev, PCI_D3hot); | ||
3213 | 3212 | ||
3214 | return 0; | 3213 | return 0; |
3215 | } | 3214 | } |
3216 | 3215 | ||
3217 | static int | 3216 | static int jme_resume(struct device *dev) |
3218 | jme_resume(struct pci_dev *pdev) | ||
3219 | { | 3217 | { |
3218 | struct pci_dev *pdev = to_pci_dev(dev); | ||
3220 | struct net_device *netdev = pci_get_drvdata(pdev); | 3219 | struct net_device *netdev = pci_get_drvdata(pdev); |
3221 | struct jme_adapter *jme = netdev_priv(netdev); | 3220 | struct jme_adapter *jme = netdev_priv(netdev); |
3222 | 3221 | ||
3223 | jme_clear_pm(jme); | 3222 | jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); |
3224 | pci_restore_state(pdev); | ||
3225 | 3223 | ||
3226 | jme_phy_on(jme); | 3224 | jme_phy_on(jme); |
3227 | if (test_bit(JME_FLAG_SSET, &jme->flags)) | 3225 | if (test_bit(JME_FLAG_SSET, &jme->flags)) |
@@ -3238,6 +3236,13 @@ jme_resume(struct pci_dev *pdev) | |||
3238 | 3236 | ||
3239 | return 0; | 3237 | return 0; |
3240 | } | 3238 | } |
3239 | |||
3240 | static SIMPLE_DEV_PM_OPS(jme_pm_ops, jme_suspend, jme_resume); | ||
3241 | #define JME_PM_OPS (&jme_pm_ops) | ||
3242 | |||
3243 | #else | ||
3244 | |||
3245 | #define JME_PM_OPS NULL | ||
3241 | #endif | 3246 | #endif |
3242 | 3247 | ||
3243 | static DEFINE_PCI_DEVICE_TABLE(jme_pci_tbl) = { | 3248 | static DEFINE_PCI_DEVICE_TABLE(jme_pci_tbl) = { |
@@ -3251,11 +3256,8 @@ static struct pci_driver jme_driver = { | |||
3251 | .id_table = jme_pci_tbl, | 3256 | .id_table = jme_pci_tbl, |
3252 | .probe = jme_init_one, | 3257 | .probe = jme_init_one, |
3253 | .remove = __devexit_p(jme_remove_one), | 3258 | .remove = __devexit_p(jme_remove_one), |
3254 | #ifdef CONFIG_PM | ||
3255 | .suspend = jme_suspend, | ||
3256 | .resume = jme_resume, | ||
3257 | #endif /* CONFIG_PM */ | ||
3258 | .shutdown = jme_shutdown, | 3259 | .shutdown = jme_shutdown, |
3260 | .driver.pm = JME_PM_OPS, | ||
3259 | }; | 3261 | }; |
3260 | 3262 | ||
3261 | static int __init | 3263 | static int __init |
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 540a8dcbcc46..7f7d5708a658 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c | |||
@@ -4898,7 +4898,7 @@ static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) | |||
4898 | goto unlock; | 4898 | goto unlock; |
4899 | } | 4899 | } |
4900 | skb_copy_and_csum_dev(org_skb, skb->data); | 4900 | skb_copy_and_csum_dev(org_skb, skb->data); |
4901 | org_skb->ip_summed = 0; | 4901 | org_skb->ip_summed = CHECKSUM_NONE; |
4902 | skb->len = org_skb->len; | 4902 | skb->len = org_skb->len; |
4903 | copy_old_skb(org_skb, skb); | 4903 | copy_old_skb(org_skb, skb); |
4904 | } | 4904 | } |
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 5762ebde4455..4f158baa0246 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c | |||
@@ -742,6 +742,9 @@ int mlx4_en_start_port(struct net_device *dev) | |||
742 | 0, MLX4_PROT_ETH)) | 742 | 0, MLX4_PROT_ETH)) |
743 | mlx4_warn(mdev, "Failed Attaching Broadcast\n"); | 743 | mlx4_warn(mdev, "Failed Attaching Broadcast\n"); |
744 | 744 | ||
745 | /* Must redo promiscuous mode setup. */ | ||
746 | priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); | ||
747 | |||
745 | /* Schedule multicast task to populate multicast list */ | 748 | /* Schedule multicast task to populate multicast list */ |
746 | queue_work(mdev->workqueue, &priv->mcast_task); | 749 | queue_work(mdev->workqueue, &priv->mcast_task); |
747 | 750 | ||
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1f4e8680a96a..673dc600c891 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
@@ -1312,17 +1312,26 @@ myri10ge_unmap_rx_page(struct pci_dev *pdev, | |||
1312 | * page into an skb */ | 1312 | * page into an skb */ |
1313 | 1313 | ||
1314 | static inline int | 1314 | static inline int |
1315 | myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, | 1315 | myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum, |
1316 | int bytes, int len, __wsum csum) | 1316 | int lro_enabled) |
1317 | { | 1317 | { |
1318 | struct myri10ge_priv *mgp = ss->mgp; | 1318 | struct myri10ge_priv *mgp = ss->mgp; |
1319 | struct sk_buff *skb; | 1319 | struct sk_buff *skb; |
1320 | struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME]; | 1320 | struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME]; |
1321 | int i, idx, hlen, remainder; | 1321 | struct myri10ge_rx_buf *rx; |
1322 | int i, idx, hlen, remainder, bytes; | ||
1322 | struct pci_dev *pdev = mgp->pdev; | 1323 | struct pci_dev *pdev = mgp->pdev; |
1323 | struct net_device *dev = mgp->dev; | 1324 | struct net_device *dev = mgp->dev; |
1324 | u8 *va; | 1325 | u8 *va; |
1325 | 1326 | ||
1327 | if (len <= mgp->small_bytes) { | ||
1328 | rx = &ss->rx_small; | ||
1329 | bytes = mgp->small_bytes; | ||
1330 | } else { | ||
1331 | rx = &ss->rx_big; | ||
1332 | bytes = mgp->big_bytes; | ||
1333 | } | ||
1334 | |||
1326 | len += MXGEFW_PAD; | 1335 | len += MXGEFW_PAD; |
1327 | idx = rx->cnt & rx->mask; | 1336 | idx = rx->cnt & rx->mask; |
1328 | va = page_address(rx->info[idx].page) + rx->info[idx].page_offset; | 1337 | va = page_address(rx->info[idx].page) + rx->info[idx].page_offset; |
@@ -1341,7 +1350,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, | |||
1341 | remainder -= MYRI10GE_ALLOC_SIZE; | 1350 | remainder -= MYRI10GE_ALLOC_SIZE; |
1342 | } | 1351 | } |
1343 | 1352 | ||
1344 | if (dev->features & NETIF_F_LRO) { | 1353 | if (lro_enabled) { |
1345 | rx_frags[0].page_offset += MXGEFW_PAD; | 1354 | rx_frags[0].page_offset += MXGEFW_PAD; |
1346 | rx_frags[0].size -= MXGEFW_PAD; | 1355 | rx_frags[0].size -= MXGEFW_PAD; |
1347 | len -= MXGEFW_PAD; | 1356 | len -= MXGEFW_PAD; |
@@ -1463,7 +1472,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) | |||
1463 | { | 1472 | { |
1464 | struct myri10ge_rx_done *rx_done = &ss->rx_done; | 1473 | struct myri10ge_rx_done *rx_done = &ss->rx_done; |
1465 | struct myri10ge_priv *mgp = ss->mgp; | 1474 | struct myri10ge_priv *mgp = ss->mgp; |
1466 | struct net_device *netdev = mgp->dev; | 1475 | |
1467 | unsigned long rx_bytes = 0; | 1476 | unsigned long rx_bytes = 0; |
1468 | unsigned long rx_packets = 0; | 1477 | unsigned long rx_packets = 0; |
1469 | unsigned long rx_ok; | 1478 | unsigned long rx_ok; |
@@ -1474,18 +1483,18 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) | |||
1474 | u16 length; | 1483 | u16 length; |
1475 | __wsum checksum; | 1484 | __wsum checksum; |
1476 | 1485 | ||
1486 | /* | ||
1487 | * Prevent compiler from generating more than one ->features memory | ||
1488 | * access to avoid theoretical race condition with functions that | ||
1489 | * change NETIF_F_LRO flag at runtime. | ||
1490 | */ | ||
1491 | bool lro_enabled = ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO; | ||
1492 | |||
1477 | while (rx_done->entry[idx].length != 0 && work_done < budget) { | 1493 | while (rx_done->entry[idx].length != 0 && work_done < budget) { |
1478 | length = ntohs(rx_done->entry[idx].length); | 1494 | length = ntohs(rx_done->entry[idx].length); |
1479 | rx_done->entry[idx].length = 0; | 1495 | rx_done->entry[idx].length = 0; |
1480 | checksum = csum_unfold(rx_done->entry[idx].checksum); | 1496 | checksum = csum_unfold(rx_done->entry[idx].checksum); |
1481 | if (length <= mgp->small_bytes) | 1497 | rx_ok = myri10ge_rx_done(ss, length, checksum, lro_enabled); |
1482 | rx_ok = myri10ge_rx_done(ss, &ss->rx_small, | ||
1483 | mgp->small_bytes, | ||
1484 | length, checksum); | ||
1485 | else | ||
1486 | rx_ok = myri10ge_rx_done(ss, &ss->rx_big, | ||
1487 | mgp->big_bytes, | ||
1488 | length, checksum); | ||
1489 | rx_packets += rx_ok; | 1498 | rx_packets += rx_ok; |
1490 | rx_bytes += rx_ok * (unsigned long)length; | 1499 | rx_bytes += rx_ok * (unsigned long)length; |
1491 | cnt++; | 1500 | cnt++; |
@@ -1497,7 +1506,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) | |||
1497 | ss->stats.rx_packets += rx_packets; | 1506 | ss->stats.rx_packets += rx_packets; |
1498 | ss->stats.rx_bytes += rx_bytes; | 1507 | ss->stats.rx_bytes += rx_bytes; |
1499 | 1508 | ||
1500 | if (netdev->features & NETIF_F_LRO) | 1509 | if (lro_enabled) |
1501 | lro_flush_all(&rx_done->lro_mgr); | 1510 | lro_flush_all(&rx_done->lro_mgr); |
1502 | 1511 | ||
1503 | /* restock receive rings if needed */ | 1512 | /* restock receive rings if needed */ |
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 653d308e0f5d..3bdcc803ec68 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c | |||
@@ -871,7 +871,7 @@ static int netxen_nic_set_flags(struct net_device *netdev, u32 data) | |||
871 | struct netxen_adapter *adapter = netdev_priv(netdev); | 871 | struct netxen_adapter *adapter = netdev_priv(netdev); |
872 | int hw_lro; | 872 | int hw_lro; |
873 | 873 | ||
874 | if (data & ~ETH_FLAG_LRO) | 874 | if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) |
875 | return -EINVAL; | 875 | return -EINVAL; |
876 | 876 | ||
877 | if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) | 877 | if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) |
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 4c14510e2a87..45b2755d6cba 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c | |||
@@ -1003,7 +1003,7 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data) | |||
1003 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 1003 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
1004 | int hw_lro; | 1004 | int hw_lro; |
1005 | 1005 | ||
1006 | if (data & ~ETH_FLAG_LRO) | 1006 | if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) |
1007 | return -EINVAL; | 1007 | return -EINVAL; |
1008 | 1008 | ||
1009 | if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) | 1009 | if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) |
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2ad6364103ea..356e74d20b80 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -6726,7 +6726,7 @@ static int s2io_ethtool_set_flags(struct net_device *dev, u32 data) | |||
6726 | int rc = 0; | 6726 | int rc = 0; |
6727 | int changed = 0; | 6727 | int changed = 0; |
6728 | 6728 | ||
6729 | if (data & ~ETH_FLAG_LRO) | 6729 | if (ethtool_invalid_flags(dev, data, ETH_FLAG_LRO)) |
6730 | return -EINVAL; | 6730 | return -EINVAL; |
6731 | 6731 | ||
6732 | if (data & ETH_FLAG_LRO) { | 6732 | if (data & ETH_FLAG_LRO) { |
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ebec88882c3b..73c942d85f07 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -48,9 +48,9 @@ | |||
48 | #include <net/ip.h> | 48 | #include <net/ip.h> |
49 | 49 | ||
50 | #include <asm/system.h> | 50 | #include <asm/system.h> |
51 | #include <asm/io.h> | 51 | #include <linux/io.h> |
52 | #include <asm/byteorder.h> | 52 | #include <asm/byteorder.h> |
53 | #include <asm/uaccess.h> | 53 | #include <linux/uaccess.h> |
54 | 54 | ||
55 | #ifdef CONFIG_SPARC | 55 | #ifdef CONFIG_SPARC |
56 | #include <asm/idprom.h> | 56 | #include <asm/idprom.h> |
@@ -13118,7 +13118,7 @@ done: | |||
13118 | 13118 | ||
13119 | static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); | 13119 | static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); |
13120 | 13120 | ||
13121 | static void inline vlan_features_add(struct net_device *dev, unsigned long flags) | 13121 | static inline void vlan_features_add(struct net_device *dev, unsigned long flags) |
13122 | { | 13122 | { |
13123 | dev->vlan_features |= flags; | 13123 | dev->vlan_features |= flags; |
13124 | } | 13124 | } |
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 81254be85b92..51f2ef142a5b 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c | |||
@@ -304,8 +304,8 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data) | |||
304 | u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; | 304 | u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; |
305 | unsigned long flags; | 305 | unsigned long flags; |
306 | 306 | ||
307 | if (data & ~ETH_FLAG_LRO) | 307 | if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) |
308 | return -EOPNOTSUPP; | 308 | return -EINVAL; |
309 | 309 | ||
310 | if (lro_requested ^ lro_present) { | 310 | if (lro_requested ^ lro_present) { |
311 | /* toggle the LRO feature*/ | 311 | /* toggle the LRO feature*/ |
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index 1dd3a21b3a43..c5eb034107fd 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c | |||
@@ -1117,8 +1117,8 @@ static int vxge_set_flags(struct net_device *dev, u32 data) | |||
1117 | struct vxgedev *vdev = netdev_priv(dev); | 1117 | struct vxgedev *vdev = netdev_priv(dev); |
1118 | enum vxge_hw_status status; | 1118 | enum vxge_hw_status status; |
1119 | 1119 | ||
1120 | if (data & ~ETH_FLAG_RXHASH) | 1120 | if (ethtool_invalid_flags(dev, data, ETH_FLAG_RXHASH)) |
1121 | return -EOPNOTSUPP; | 1121 | return -EINVAL; |
1122 | 1122 | ||
1123 | if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) | 1123 | if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) |
1124 | return 0; | 1124 | return 0; |
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 18d24b7b1e34..7ecc0bda57b3 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c | |||
@@ -649,8 +649,7 @@ static int __devinit p54spi_probe(struct spi_device *spi) | |||
649 | goto err_free_common; | 649 | goto err_free_common; |
650 | } | 650 | } |
651 | 651 | ||
652 | set_irq_type(gpio_to_irq(p54spi_gpio_irq), | 652 | irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING); |
653 | IRQ_TYPE_EDGE_RISING); | ||
654 | 653 | ||
655 | disable_irq(gpio_to_irq(p54spi_gpio_irq)); | 654 | disable_irq(gpio_to_irq(p54spi_gpio_irq)); |
656 | 655 | ||
diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index d550b5e68d3c..f51a0241a440 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c | |||
@@ -265,7 +265,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, | |||
265 | goto disable; | 265 | goto disable; |
266 | } | 266 | } |
267 | 267 | ||
268 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | 268 | irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); |
269 | disable_irq(wl->irq); | 269 | disable_irq(wl->irq); |
270 | 270 | ||
271 | wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; | 271 | wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; |
diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c index ac872b38960f..af6448c4d3e2 100644 --- a/drivers/net/wireless/wl1251/spi.c +++ b/drivers/net/wireless/wl1251/spi.c | |||
@@ -286,7 +286,7 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) | |||
286 | goto out_free; | 286 | goto out_free; |
287 | } | 287 | } |
288 | 288 | ||
289 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | 289 | irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); |
290 | 290 | ||
291 | disable_irq(wl->irq); | 291 | disable_irq(wl->irq); |
292 | 292 | ||
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index deeec32a5803..103095bbe8c0 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c | |||
@@ -340,7 +340,7 @@ static int __init eisa_probe(struct parisc_device *dev) | |||
340 | /* Reserve IRQ2 */ | 340 | /* Reserve IRQ2 */ |
341 | setup_irq(2, &irq2_action); | 341 | setup_irq(2, &irq2_action); |
342 | for (i = 0; i < 16; i++) { | 342 | for (i = 0; i < 16; i++) { |
343 | set_irq_chip_and_handler(i, &eisa_interrupt_type, | 343 | irq_set_chip_and_handler(i, &eisa_interrupt_type, |
344 | handle_simple_irq); | 344 | handle_simple_irq); |
345 | } | 345 | } |
346 | 346 | ||
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index ef31080cf591..1bab5a2cd359 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c | |||
@@ -152,8 +152,8 @@ int gsc_assign_irq(struct irq_chip *type, void *data) | |||
152 | if (irq > GSC_IRQ_MAX) | 152 | if (irq > GSC_IRQ_MAX) |
153 | return NO_IRQ; | 153 | return NO_IRQ; |
154 | 154 | ||
155 | set_irq_chip_and_handler(irq, type, handle_simple_irq); | 155 | irq_set_chip_and_handler(irq, type, handle_simple_irq); |
156 | set_irq_chip_data(irq, data); | 156 | irq_set_chip_data(irq, data); |
157 | 157 | ||
158 | return irq++; | 158 | return irq++; |
159 | } | 159 | } |
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index a4d8ff66a639..e3b76d409dee 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c | |||
@@ -355,7 +355,8 @@ int superio_fixup_irq(struct pci_dev *pcidev) | |||
355 | #endif | 355 | #endif |
356 | 356 | ||
357 | for (i = 0; i < 16; i++) { | 357 | for (i = 0; i < 16; i++) { |
358 | set_irq_chip_and_handler(i, &superio_interrupt_type, handle_simple_irq); | 358 | irq_set_chip_and_handler(i, &superio_interrupt_type, |
359 | handle_simple_irq); | ||
359 | } | 360 | } |
360 | 361 | ||
361 | /* | 362 | /* |
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 09933eb9126b..12e02bf92c4a 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -1226,7 +1226,7 @@ const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) | |||
1226 | 1226 | ||
1227 | void dmar_msi_unmask(struct irq_data *data) | 1227 | void dmar_msi_unmask(struct irq_data *data) |
1228 | { | 1228 | { |
1229 | struct intel_iommu *iommu = irq_data_get_irq_data(data); | 1229 | struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); |
1230 | unsigned long flag; | 1230 | unsigned long flag; |
1231 | 1231 | ||
1232 | /* unmask it */ | 1232 | /* unmask it */ |
@@ -1240,7 +1240,7 @@ void dmar_msi_unmask(struct irq_data *data) | |||
1240 | void dmar_msi_mask(struct irq_data *data) | 1240 | void dmar_msi_mask(struct irq_data *data) |
1241 | { | 1241 | { |
1242 | unsigned long flag; | 1242 | unsigned long flag; |
1243 | struct intel_iommu *iommu = irq_data_get_irq_data(data); | 1243 | struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); |
1244 | 1244 | ||
1245 | /* mask it */ | 1245 | /* mask it */ |
1246 | spin_lock_irqsave(&iommu->register_lock, flag); | 1246 | spin_lock_irqsave(&iommu->register_lock, flag); |
@@ -1252,7 +1252,7 @@ void dmar_msi_mask(struct irq_data *data) | |||
1252 | 1252 | ||
1253 | void dmar_msi_write(int irq, struct msi_msg *msg) | 1253 | void dmar_msi_write(int irq, struct msi_msg *msg) |
1254 | { | 1254 | { |
1255 | struct intel_iommu *iommu = get_irq_data(irq); | 1255 | struct intel_iommu *iommu = irq_get_handler_data(irq); |
1256 | unsigned long flag; | 1256 | unsigned long flag; |
1257 | 1257 | ||
1258 | spin_lock_irqsave(&iommu->register_lock, flag); | 1258 | spin_lock_irqsave(&iommu->register_lock, flag); |
@@ -1264,7 +1264,7 @@ void dmar_msi_write(int irq, struct msi_msg *msg) | |||
1264 | 1264 | ||
1265 | void dmar_msi_read(int irq, struct msi_msg *msg) | 1265 | void dmar_msi_read(int irq, struct msi_msg *msg) |
1266 | { | 1266 | { |
1267 | struct intel_iommu *iommu = get_irq_data(irq); | 1267 | struct intel_iommu *iommu = irq_get_handler_data(irq); |
1268 | unsigned long flag; | 1268 | unsigned long flag; |
1269 | 1269 | ||
1270 | spin_lock_irqsave(&iommu->register_lock, flag); | 1270 | spin_lock_irqsave(&iommu->register_lock, flag); |
@@ -1382,12 +1382,12 @@ int dmar_set_interrupt(struct intel_iommu *iommu) | |||
1382 | return -EINVAL; | 1382 | return -EINVAL; |
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | set_irq_data(irq, iommu); | 1385 | irq_set_handler_data(irq, iommu); |
1386 | iommu->irq = irq; | 1386 | iommu->irq = irq; |
1387 | 1387 | ||
1388 | ret = arch_setup_dmar_msi(irq); | 1388 | ret = arch_setup_dmar_msi(irq); |
1389 | if (ret) { | 1389 | if (ret) { |
1390 | set_irq_data(irq, NULL); | 1390 | irq_set_handler_data(irq, NULL); |
1391 | iommu->irq = 0; | 1391 | iommu->irq = 0; |
1392 | destroy_irq(irq); | 1392 | destroy_irq(irq); |
1393 | return ret; | 1393 | return ret; |
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 834842aa5bbf..db057b6fe0c8 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c | |||
@@ -34,7 +34,7 @@ struct ht_irq_cfg { | |||
34 | 34 | ||
35 | void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) | 35 | void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) |
36 | { | 36 | { |
37 | struct ht_irq_cfg *cfg = get_irq_data(irq); | 37 | struct ht_irq_cfg *cfg = irq_get_handler_data(irq); |
38 | unsigned long flags; | 38 | unsigned long flags; |
39 | spin_lock_irqsave(&ht_irq_lock, flags); | 39 | spin_lock_irqsave(&ht_irq_lock, flags); |
40 | if (cfg->msg.address_lo != msg->address_lo) { | 40 | if (cfg->msg.address_lo != msg->address_lo) { |
@@ -53,13 +53,13 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) | |||
53 | 53 | ||
54 | void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) | 54 | void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) |
55 | { | 55 | { |
56 | struct ht_irq_cfg *cfg = get_irq_data(irq); | 56 | struct ht_irq_cfg *cfg = irq_get_handler_data(irq); |
57 | *msg = cfg->msg; | 57 | *msg = cfg->msg; |
58 | } | 58 | } |
59 | 59 | ||
60 | void mask_ht_irq(struct irq_data *data) | 60 | void mask_ht_irq(struct irq_data *data) |
61 | { | 61 | { |
62 | struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); | 62 | struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); |
63 | struct ht_irq_msg msg = cfg->msg; | 63 | struct ht_irq_msg msg = cfg->msg; |
64 | 64 | ||
65 | msg.address_lo |= 1; | 65 | msg.address_lo |= 1; |
@@ -68,7 +68,7 @@ void mask_ht_irq(struct irq_data *data) | |||
68 | 68 | ||
69 | void unmask_ht_irq(struct irq_data *data) | 69 | void unmask_ht_irq(struct irq_data *data) |
70 | { | 70 | { |
71 | struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); | 71 | struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); |
72 | struct ht_irq_msg msg = cfg->msg; | 72 | struct ht_irq_msg msg = cfg->msg; |
73 | 73 | ||
74 | msg.address_lo &= ~1; | 74 | msg.address_lo &= ~1; |
@@ -126,7 +126,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) | |||
126 | kfree(cfg); | 126 | kfree(cfg); |
127 | return -EBUSY; | 127 | return -EBUSY; |
128 | } | 128 | } |
129 | set_irq_data(irq, cfg); | 129 | irq_set_handler_data(irq, cfg); |
130 | 130 | ||
131 | if (arch_setup_ht_irq(irq, dev) < 0) { | 131 | if (arch_setup_ht_irq(irq, dev) < 0) { |
132 | ht_destroy_irq(irq); | 132 | ht_destroy_irq(irq); |
@@ -162,9 +162,9 @@ void ht_destroy_irq(unsigned int irq) | |||
162 | { | 162 | { |
163 | struct ht_irq_cfg *cfg; | 163 | struct ht_irq_cfg *cfg; |
164 | 164 | ||
165 | cfg = get_irq_data(irq); | 165 | cfg = irq_get_handler_data(irq); |
166 | set_irq_chip(irq, NULL); | 166 | irq_set_chip(irq, NULL); |
167 | set_irq_data(irq, NULL); | 167 | irq_set_handler_data(irq, NULL); |
168 | destroy_irq(irq); | 168 | destroy_irq(irq); |
169 | 169 | ||
170 | kfree(cfg); | 170 | kfree(cfg); |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index a4115f1afe1f..7da3bef60d87 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -1206,7 +1206,7 @@ void free_dmar_iommu(struct intel_iommu *iommu) | |||
1206 | iommu_disable_translation(iommu); | 1206 | iommu_disable_translation(iommu); |
1207 | 1207 | ||
1208 | if (iommu->irq) { | 1208 | if (iommu->irq) { |
1209 | set_irq_data(iommu->irq, NULL); | 1209 | irq_set_handler_data(iommu->irq, NULL); |
1210 | /* This will mask the irq */ | 1210 | /* This will mask the irq */ |
1211 | free_irq(iommu->irq, iommu); | 1211 | free_irq(iommu->irq, iommu); |
1212 | destroy_irq(iommu->irq); | 1212 | destroy_irq(iommu->irq); |
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index ec87cd66f3eb..a22557b20283 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
@@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(irq_2_ir_lock); | |||
50 | 50 | ||
51 | static struct irq_2_iommu *irq_2_iommu(unsigned int irq) | 51 | static struct irq_2_iommu *irq_2_iommu(unsigned int irq) |
52 | { | 52 | { |
53 | struct irq_cfg *cfg = get_irq_chip_data(irq); | 53 | struct irq_cfg *cfg = irq_get_chip_data(irq); |
54 | return cfg ? &cfg->irq_2_iommu : NULL; | 54 | return cfg ? &cfg->irq_2_iommu : NULL; |
55 | } | 55 | } |
56 | 56 | ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 44b0aeee83e5..2f10328bf661 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -236,7 +236,7 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
236 | 236 | ||
237 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) | 237 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) |
238 | { | 238 | { |
239 | struct msi_desc *entry = get_irq_msi(irq); | 239 | struct msi_desc *entry = irq_get_msi_desc(irq); |
240 | 240 | ||
241 | __read_msi_msg(entry, msg); | 241 | __read_msi_msg(entry, msg); |
242 | } | 242 | } |
@@ -253,7 +253,7 @@ void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
253 | 253 | ||
254 | void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) | 254 | void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) |
255 | { | 255 | { |
256 | struct msi_desc *entry = get_irq_msi(irq); | 256 | struct msi_desc *entry = irq_get_msi_desc(irq); |
257 | 257 | ||
258 | __get_cached_msi_msg(entry, msg); | 258 | __get_cached_msi_msg(entry, msg); |
259 | } | 259 | } |
@@ -297,7 +297,7 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
297 | 297 | ||
298 | void write_msi_msg(unsigned int irq, struct msi_msg *msg) | 298 | void write_msi_msg(unsigned int irq, struct msi_msg *msg) |
299 | { | 299 | { |
300 | struct msi_desc *entry = get_irq_msi(irq); | 300 | struct msi_desc *entry = irq_get_msi_desc(irq); |
301 | 301 | ||
302 | __write_msi_msg(entry, msg); | 302 | __write_msi_msg(entry, msg); |
303 | } | 303 | } |
@@ -354,7 +354,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) | |||
354 | if (!dev->msi_enabled) | 354 | if (!dev->msi_enabled) |
355 | return; | 355 | return; |
356 | 356 | ||
357 | entry = get_irq_msi(dev->irq); | 357 | entry = irq_get_msi_desc(dev->irq); |
358 | pos = entry->msi_attrib.pos; | 358 | pos = entry->msi_attrib.pos; |
359 | 359 | ||
360 | pci_intx_for_msi(dev, 0); | 360 | pci_intx_for_msi(dev, 0); |
@@ -519,7 +519,7 @@ static void msix_program_entries(struct pci_dev *dev, | |||
519 | PCI_MSIX_ENTRY_VECTOR_CTRL; | 519 | PCI_MSIX_ENTRY_VECTOR_CTRL; |
520 | 520 | ||
521 | entries[i].vector = entry->irq; | 521 | entries[i].vector = entry->irq; |
522 | set_irq_msi(entry->irq, entry); | 522 | irq_set_msi_desc(entry->irq, entry); |
523 | entry->masked = readl(entry->mask_base + offset); | 523 | entry->masked = readl(entry->mask_base + offset); |
524 | msix_mask_irq(entry, 1); | 524 | msix_mask_irq(entry, 1); |
525 | i++; | 525 | i++; |
diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c index eae9cbe37a3e..49221395101e 100644 --- a/drivers/pcmcia/bfin_cf_pcmcia.c +++ b/drivers/pcmcia/bfin_cf_pcmcia.c | |||
@@ -235,7 +235,7 @@ static int __devinit bfin_cf_probe(struct platform_device *pdev) | |||
235 | cf->irq = irq; | 235 | cf->irq = irq; |
236 | cf->socket.pci_irq = irq; | 236 | cf->socket.pci_irq = irq; |
237 | 237 | ||
238 | set_irq_type(irq, IRQF_TRIGGER_LOW); | 238 | irq_set_irq_type(irq, IRQF_TRIGGER_LOW); |
239 | 239 | ||
240 | io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 240 | io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
241 | attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 241 | attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 27575e6378a1..01757f18a208 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c | |||
@@ -181,7 +181,7 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) | |||
181 | /* all other (older) Db1x00 boards use a GPIO to show | 181 | /* all other (older) Db1x00 boards use a GPIO to show |
182 | * card detection status: use both-edge triggers. | 182 | * card detection status: use both-edge triggers. |
183 | */ | 183 | */ |
184 | set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH); | 184 | irq_set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH); |
185 | ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq, | 185 | ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq, |
186 | 0, "pcmcia_carddetect", sock); | 186 | 0, "pcmcia_carddetect", sock); |
187 | 187 | ||
diff --git a/drivers/pcmcia/sa1100_nanoengine.c b/drivers/pcmcia/sa1100_nanoengine.c index 3d2652e2f5ae..93b9c9ba57c3 100644 --- a/drivers/pcmcia/sa1100_nanoengine.c +++ b/drivers/pcmcia/sa1100_nanoengine.c | |||
@@ -86,7 +86,7 @@ static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | |||
86 | GPDR &= ~nano_skts[i].input_pins; | 86 | GPDR &= ~nano_skts[i].input_pins; |
87 | GPDR |= nano_skts[i].output_pins; | 87 | GPDR |= nano_skts[i].output_pins; |
88 | GPCR = nano_skts[i].clear_outputs; | 88 | GPCR = nano_skts[i].clear_outputs; |
89 | set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH); | 89 | irq_set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH); |
90 | skt->socket.pci_irq = nano_skts[i].pci_irq; | 90 | skt->socket.pci_irq = nano_skts[i].pci_irq; |
91 | 91 | ||
92 | return soc_pcmcia_request_irqs(skt, | 92 | return soc_pcmcia_request_irqs(skt, |
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 5a9a392eacdf..768f9572a8c8 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c | |||
@@ -155,11 +155,11 @@ static int soc_common_pcmcia_config_skt( | |||
155 | */ | 155 | */ |
156 | if (skt->irq_state != 1 && state->io_irq) { | 156 | if (skt->irq_state != 1 && state->io_irq) { |
157 | skt->irq_state = 1; | 157 | skt->irq_state = 1; |
158 | set_irq_type(skt->socket.pci_irq, | 158 | irq_set_irq_type(skt->socket.pci_irq, |
159 | IRQ_TYPE_EDGE_FALLING); | 159 | IRQ_TYPE_EDGE_FALLING); |
160 | } else if (skt->irq_state == 1 && state->io_irq == 0) { | 160 | } else if (skt->irq_state == 1 && state->io_irq == 0) { |
161 | skt->irq_state = 0; | 161 | skt->irq_state = 0; |
162 | set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); | 162 | irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); |
163 | } | 163 | } |
164 | 164 | ||
165 | skt->cs_state = *state; | 165 | skt->cs_state = *state; |
@@ -537,7 +537,7 @@ int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, | |||
537 | IRQF_DISABLED, irqs[i].str, skt); | 537 | IRQF_DISABLED, irqs[i].str, skt); |
538 | if (res) | 538 | if (res) |
539 | break; | 539 | break; |
540 | set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); | 540 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); |
541 | } | 541 | } |
542 | 542 | ||
543 | if (res) { | 543 | if (res) { |
@@ -570,7 +570,7 @@ void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, | |||
570 | 570 | ||
571 | for (i = 0; i < nr; i++) | 571 | for (i = 0; i < nr; i++) |
572 | if (irqs[i].sock == skt->nr) | 572 | if (irqs[i].sock == skt->nr) |
573 | set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); | 573 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); |
574 | } | 574 | } |
575 | EXPORT_SYMBOL(soc_pcmcia_disable_irqs); | 575 | EXPORT_SYMBOL(soc_pcmcia_disable_irqs); |
576 | 576 | ||
@@ -581,8 +581,8 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, | |||
581 | 581 | ||
582 | for (i = 0; i < nr; i++) | 582 | for (i = 0; i < nr; i++) |
583 | if (irqs[i].sock == skt->nr) { | 583 | if (irqs[i].sock == skt->nr) { |
584 | set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING); | 584 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING); |
585 | set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH); | 585 | irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH); |
586 | } | 586 | } |
587 | } | 587 | } |
588 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); | 588 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); |
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c index 3b67a1b6a197..379f4218857d 100644 --- a/drivers/pcmcia/xxs1500_ss.c +++ b/drivers/pcmcia/xxs1500_ss.c | |||
@@ -274,7 +274,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev) | |||
274 | * edge detector. | 274 | * edge detector. |
275 | */ | 275 | */ |
276 | irq = gpio_to_irq(GPIO_CDA); | 276 | irq = gpio_to_irq(GPIO_CDA); |
277 | set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); | 277 | irq_set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); |
278 | ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock); | 278 | ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock); |
279 | if (ret) { | 279 | if (ret) { |
280 | dev_err(&pdev->dev, "cannot setup cd irq\n"); | 280 | dev_err(&pdev->dev, "cannot setup cd irq\n"); |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 222dfb737b11..2ee442c2a5db 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -101,6 +101,19 @@ config DELL_WMI | |||
101 | To compile this driver as a module, choose M here: the module will | 101 | To compile this driver as a module, choose M here: the module will |
102 | be called dell-wmi. | 102 | be called dell-wmi. |
103 | 103 | ||
104 | config DELL_WMI_AIO | ||
105 | tristate "WMI Hotkeys for Dell All-In-One series" | ||
106 | depends on ACPI_WMI | ||
107 | depends on INPUT | ||
108 | select INPUT_SPARSEKMAP | ||
109 | ---help--- | ||
110 | Say Y here if you want to support WMI-based hotkeys on Dell | ||
111 | All-In-One machines. | ||
112 | |||
113 | To compile this driver as a module, choose M here: the module will | ||
114 | be called dell-wmi. | ||
115 | |||
116 | |||
104 | config FUJITSU_LAPTOP | 117 | config FUJITSU_LAPTOP |
105 | tristate "Fujitsu Laptop Extras" | 118 | tristate "Fujitsu Laptop Extras" |
106 | depends on ACPI | 119 | depends on ACPI |
@@ -438,23 +451,53 @@ config EEEPC_LAPTOP | |||
438 | Bluetooth, backlight and allows powering on/off some other | 451 | Bluetooth, backlight and allows powering on/off some other |
439 | devices. | 452 | devices. |
440 | 453 | ||
441 | If you have an Eee PC laptop, say Y or M here. | 454 | If you have an Eee PC laptop, say Y or M here. If this driver |
455 | doesn't work on your Eee PC, try eeepc-wmi instead. | ||
442 | 456 | ||
443 | config EEEPC_WMI | 457 | config ASUS_WMI |
444 | tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)" | 458 | tristate "ASUS WMI Driver (EXPERIMENTAL)" |
445 | depends on ACPI_WMI | 459 | depends on ACPI_WMI |
446 | depends on INPUT | 460 | depends on INPUT |
461 | depends on HWMON | ||
447 | depends on EXPERIMENTAL | 462 | depends on EXPERIMENTAL |
448 | depends on BACKLIGHT_CLASS_DEVICE | 463 | depends on BACKLIGHT_CLASS_DEVICE |
449 | depends on RFKILL || RFKILL = n | 464 | depends on RFKILL || RFKILL = n |
465 | depends on HOTPLUG_PCI | ||
450 | select INPUT_SPARSEKMAP | 466 | select INPUT_SPARSEKMAP |
451 | select LEDS_CLASS | 467 | select LEDS_CLASS |
452 | select NEW_LEDS | 468 | select NEW_LEDS |
453 | ---help--- | 469 | ---help--- |
454 | Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. | 470 | Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new |
471 | Asus Notebooks). | ||
455 | 472 | ||
456 | To compile this driver as a module, choose M here: the module will | 473 | To compile this driver as a module, choose M here: the module will |
457 | be called eeepc-wmi. | 474 | be called asus-wmi. |
475 | |||
476 | config ASUS_NB_WMI | ||
477 | tristate "Asus Notebook WMI Driver (EXPERIMENTAL)" | ||
478 | depends on ASUS_WMI | ||
479 | ---help--- | ||
480 | This is a driver for newer Asus notebooks. It adds extra features | ||
481 | like wireless radio and bluetooth control, leds, hotkeys, backlight... | ||
482 | |||
483 | For more informations, see | ||
484 | <file:Documentation/ABI/testing/sysfs-platform-asus-wmi> | ||
485 | |||
486 | If you have an ACPI-WMI compatible Asus Notebook, say Y or M | ||
487 | here. | ||
488 | |||
489 | config EEEPC_WMI | ||
490 | tristate "Eee PC WMI Driver (EXPERIMENTAL)" | ||
491 | depends on ASUS_WMI | ||
492 | ---help--- | ||
493 | This is a driver for newer Eee PC laptops. It adds extra features | ||
494 | like wireless radio and bluetooth control, leds, hotkeys, backlight... | ||
495 | |||
496 | For more informations, see | ||
497 | <file:Documentation/ABI/testing/sysfs-platform-asus-wmi> | ||
498 | |||
499 | If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M | ||
500 | here. | ||
458 | 501 | ||
459 | config ACPI_WMI | 502 | config ACPI_WMI |
460 | tristate "WMI" | 503 | tristate "WMI" |
@@ -616,6 +659,21 @@ config GPIO_INTEL_PMIC | |||
616 | Say Y here to support GPIO via the SCU IPC interface | 659 | Say Y here to support GPIO via the SCU IPC interface |
617 | on Intel MID platforms. | 660 | on Intel MID platforms. |
618 | 661 | ||
662 | config INTEL_MID_POWER_BUTTON | ||
663 | tristate "power button driver for Intel MID platforms" | ||
664 | depends on INTEL_SCU_IPC && INPUT | ||
665 | help | ||
666 | This driver handles the power button on the Intel MID platforms. | ||
667 | |||
668 | If unsure, say N. | ||
669 | |||
670 | config INTEL_MFLD_THERMAL | ||
671 | tristate "Thermal driver for Intel Medfield platform" | ||
672 | depends on INTEL_SCU_IPC && THERMAL | ||
673 | help | ||
674 | Say Y here to enable thermal driver support for the Intel Medfield | ||
675 | platform. | ||
676 | |||
619 | config RAR_REGISTER | 677 | config RAR_REGISTER |
620 | bool "Restricted Access Region Register Driver" | 678 | bool "Restricted Access Region Register Driver" |
621 | depends on PCI && X86_MRST | 679 | depends on PCI && X86_MRST |
@@ -672,4 +730,26 @@ config XO1_RFKILL | |||
672 | Support for enabling/disabling the WLAN interface on the OLPC XO-1 | 730 | Support for enabling/disabling the WLAN interface on the OLPC XO-1 |
673 | laptop. | 731 | laptop. |
674 | 732 | ||
733 | config XO15_EBOOK | ||
734 | tristate "OLPC XO-1.5 ebook switch" | ||
735 | depends on ACPI && INPUT | ||
736 | ---help--- | ||
737 | Support for the ebook switch on the OLPC XO-1.5 laptop. | ||
738 | |||
739 | This switch is triggered as the screen is rotated and folded down to | ||
740 | convert the device into ebook form. | ||
741 | |||
742 | config SAMSUNG_LAPTOP | ||
743 | tristate "Samsung Laptop driver" | ||
744 | depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 | ||
745 | ---help--- | ||
746 | This module implements a driver for a wide range of different | ||
747 | Samsung laptops. It offers control over the different | ||
748 | function keys, wireless LED, LCD backlight level, and | ||
749 | sometimes provides a "performance_control" sysfs file to allow | ||
750 | the performance level of the laptop to be changed. | ||
751 | |||
752 | To compile this driver as a module, choose M here: the module | ||
753 | will be called samsung-laptop. | ||
754 | |||
675 | endif # X86_PLATFORM_DEVICES | 755 | endif # X86_PLATFORM_DEVICES |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 299aefb3e74c..029e8861d086 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
@@ -3,6 +3,8 @@ | |||
3 | # x86 Platform-Specific Drivers | 3 | # x86 Platform-Specific Drivers |
4 | # | 4 | # |
5 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o | 5 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o |
6 | obj-$(CONFIG_ASUS_WMI) += asus-wmi.o | ||
7 | obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o | ||
6 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o | 8 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o |
7 | obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o | 9 | obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o |
8 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o | 10 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o |
@@ -10,6 +12,7 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o | |||
10 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o | 12 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o |
11 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o | 13 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o |
12 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o | 14 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o |
15 | obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o | ||
13 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o | 16 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o |
14 | obj-$(CONFIG_ACERHDF) += acerhdf.o | 17 | obj-$(CONFIG_ACERHDF) += acerhdf.o |
15 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o | 18 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o |
@@ -29,9 +32,13 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o | |||
29 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o | 32 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o |
30 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o | 33 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o |
31 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o | 34 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o |
32 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o | 35 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o |
36 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o | ||
33 | obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o | 37 | obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o |
34 | obj-$(CONFIG_INTEL_IPS) += intel_ips.o | 38 | obj-$(CONFIG_INTEL_IPS) += intel_ips.o |
35 | obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o | 39 | obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o |
36 | obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o | 40 | obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o |
41 | obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o | ||
37 | obj-$(CONFIG_IBM_RTL) += ibm_rtl.o | 42 | obj-$(CONFIG_IBM_RTL) += ibm_rtl.o |
43 | obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o | ||
44 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o | ||
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c9784705f6ac..5ea6c3477d17 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -22,6 +22,8 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
26 | |||
25 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
26 | #include <linux/module.h> | 28 | #include <linux/module.h> |
27 | #include <linux/init.h> | 29 | #include <linux/init.h> |
@@ -46,12 +48,6 @@ MODULE_AUTHOR("Carlos Corbacho"); | |||
46 | MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); | 48 | MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); |
47 | MODULE_LICENSE("GPL"); | 49 | MODULE_LICENSE("GPL"); |
48 | 50 | ||
49 | #define ACER_LOGPREFIX "acer-wmi: " | ||
50 | #define ACER_ERR KERN_ERR ACER_LOGPREFIX | ||
51 | #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX | ||
52 | #define ACER_INFO KERN_INFO ACER_LOGPREFIX | ||
53 | #define ACER_WARNING KERN_WARNING ACER_LOGPREFIX | ||
54 | |||
55 | /* | 51 | /* |
56 | * Magic Number | 52 | * Magic Number |
57 | * Meaning is unknown - this number is required for writing to ACPI for AMW0 | 53 | * Meaning is unknown - this number is required for writing to ACPI for AMW0 |
@@ -84,7 +80,7 @@ MODULE_LICENSE("GPL"); | |||
84 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" | 80 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" |
85 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" | 81 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" |
86 | #define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" | 82 | #define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" |
87 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" | 83 | #define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A" |
88 | #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" | 84 | #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" |
89 | 85 | ||
90 | /* | 86 | /* |
@@ -93,7 +89,7 @@ MODULE_LICENSE("GPL"); | |||
93 | #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" | 89 | #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" |
94 | 90 | ||
95 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); | 91 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); |
96 | MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); | 92 | MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); |
97 | MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); | 93 | MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); |
98 | 94 | ||
99 | enum acer_wmi_event_ids { | 95 | enum acer_wmi_event_ids { |
@@ -108,7 +104,7 @@ static const struct key_entry acer_wmi_keymap[] = { | |||
108 | {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ | 104 | {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ |
109 | {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ | 105 | {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ |
110 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ | 106 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ |
111 | {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ | 107 | {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */ |
112 | {KE_END, 0} | 108 | {KE_END, 0} |
113 | }; | 109 | }; |
114 | 110 | ||
@@ -221,6 +217,7 @@ struct acer_debug { | |||
221 | static struct rfkill *wireless_rfkill; | 217 | static struct rfkill *wireless_rfkill; |
222 | static struct rfkill *bluetooth_rfkill; | 218 | static struct rfkill *bluetooth_rfkill; |
223 | static struct rfkill *threeg_rfkill; | 219 | static struct rfkill *threeg_rfkill; |
220 | static bool rfkill_inited; | ||
224 | 221 | ||
225 | /* Each low-level interface must define at least some of the following */ | 222 | /* Each low-level interface must define at least some of the following */ |
226 | struct wmi_interface { | 223 | struct wmi_interface { |
@@ -845,7 +842,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy) | |||
845 | has_type_aa = true; | 842 | has_type_aa = true; |
846 | type_aa = (struct hotkey_function_type_aa *) header; | 843 | type_aa = (struct hotkey_function_type_aa *) header; |
847 | 844 | ||
848 | printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n", | 845 | pr_info("Function bitmap for Communication Button: 0x%x\n", |
849 | type_aa->commun_func_bitmap); | 846 | type_aa->commun_func_bitmap); |
850 | 847 | ||
851 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) | 848 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) |
@@ -991,6 +988,7 @@ static int __devinit acer_led_init(struct device *dev) | |||
991 | 988 | ||
992 | static void acer_led_exit(void) | 989 | static void acer_led_exit(void) |
993 | { | 990 | { |
991 | set_u32(LED_OFF, ACER_CAP_MAILLED); | ||
994 | led_classdev_unregister(&mail_led); | 992 | led_classdev_unregister(&mail_led); |
995 | } | 993 | } |
996 | 994 | ||
@@ -1036,7 +1034,7 @@ static int __devinit acer_backlight_init(struct device *dev) | |||
1036 | bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, | 1034 | bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, |
1037 | &props); | 1035 | &props); |
1038 | if (IS_ERR(bd)) { | 1036 | if (IS_ERR(bd)) { |
1039 | printk(ACER_ERR "Could not register Acer backlight device\n"); | 1037 | pr_err("Could not register Acer backlight device\n"); |
1040 | acer_backlight_device = NULL; | 1038 | acer_backlight_device = NULL; |
1041 | return PTR_ERR(bd); | 1039 | return PTR_ERR(bd); |
1042 | } | 1040 | } |
@@ -1083,8 +1081,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device) | |||
1083 | return AE_ERROR; | 1081 | return AE_ERROR; |
1084 | } | 1082 | } |
1085 | if (obj->buffer.length != 8) { | 1083 | if (obj->buffer.length != 8) { |
1086 | printk(ACER_WARNING "Unknown buffer length %d\n", | 1084 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); |
1087 | obj->buffer.length); | ||
1088 | kfree(obj); | 1085 | kfree(obj); |
1089 | return AE_ERROR; | 1086 | return AE_ERROR; |
1090 | } | 1087 | } |
@@ -1093,7 +1090,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device) | |||
1093 | kfree(obj); | 1090 | kfree(obj); |
1094 | 1091 | ||
1095 | if (return_value.error_code || return_value.ec_return_value) | 1092 | if (return_value.error_code || return_value.ec_return_value) |
1096 | printk(ACER_WARNING "Get Device Status failed: " | 1093 | pr_warning("Get Device Status failed: " |
1097 | "0x%x - 0x%x\n", return_value.error_code, | 1094 | "0x%x - 0x%x\n", return_value.error_code, |
1098 | return_value.ec_return_value); | 1095 | return_value.ec_return_value); |
1099 | else | 1096 | else |
@@ -1161,9 +1158,13 @@ static int acer_rfkill_set(void *data, bool blocked) | |||
1161 | { | 1158 | { |
1162 | acpi_status status; | 1159 | acpi_status status; |
1163 | u32 cap = (unsigned long)data; | 1160 | u32 cap = (unsigned long)data; |
1164 | status = set_u32(!blocked, cap); | 1161 | |
1165 | if (ACPI_FAILURE(status)) | 1162 | if (rfkill_inited) { |
1166 | return -ENODEV; | 1163 | status = set_u32(!blocked, cap); |
1164 | if (ACPI_FAILURE(status)) | ||
1165 | return -ENODEV; | ||
1166 | } | ||
1167 | |||
1167 | return 0; | 1168 | return 0; |
1168 | } | 1169 | } |
1169 | 1170 | ||
@@ -1187,14 +1188,16 @@ static struct rfkill *acer_rfkill_register(struct device *dev, | |||
1187 | return ERR_PTR(-ENOMEM); | 1188 | return ERR_PTR(-ENOMEM); |
1188 | 1189 | ||
1189 | status = get_device_status(&state, cap); | 1190 | status = get_device_status(&state, cap); |
1190 | if (ACPI_SUCCESS(status)) | ||
1191 | rfkill_init_sw_state(rfkill_dev, !state); | ||
1192 | 1191 | ||
1193 | err = rfkill_register(rfkill_dev); | 1192 | err = rfkill_register(rfkill_dev); |
1194 | if (err) { | 1193 | if (err) { |
1195 | rfkill_destroy(rfkill_dev); | 1194 | rfkill_destroy(rfkill_dev); |
1196 | return ERR_PTR(err); | 1195 | return ERR_PTR(err); |
1197 | } | 1196 | } |
1197 | |||
1198 | if (ACPI_SUCCESS(status)) | ||
1199 | rfkill_set_sw_state(rfkill_dev, !state); | ||
1200 | |||
1198 | return rfkill_dev; | 1201 | return rfkill_dev; |
1199 | } | 1202 | } |
1200 | 1203 | ||
@@ -1229,14 +1232,19 @@ static int acer_rfkill_init(struct device *dev) | |||
1229 | } | 1232 | } |
1230 | } | 1233 | } |
1231 | 1234 | ||
1232 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 1235 | rfkill_inited = true; |
1236 | |||
1237 | if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) | ||
1238 | schedule_delayed_work(&acer_rfkill_work, | ||
1239 | round_jiffies_relative(HZ)); | ||
1233 | 1240 | ||
1234 | return 0; | 1241 | return 0; |
1235 | } | 1242 | } |
1236 | 1243 | ||
1237 | static void acer_rfkill_exit(void) | 1244 | static void acer_rfkill_exit(void) |
1238 | { | 1245 | { |
1239 | cancel_delayed_work_sync(&acer_rfkill_work); | 1246 | if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) |
1247 | cancel_delayed_work_sync(&acer_rfkill_work); | ||
1240 | 1248 | ||
1241 | rfkill_unregister(wireless_rfkill); | 1249 | rfkill_unregister(wireless_rfkill); |
1242 | rfkill_destroy(wireless_rfkill); | 1250 | rfkill_destroy(wireless_rfkill); |
@@ -1309,7 +1317,7 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1309 | 1317 | ||
1310 | status = wmi_get_event_data(value, &response); | 1318 | status = wmi_get_event_data(value, &response); |
1311 | if (status != AE_OK) { | 1319 | if (status != AE_OK) { |
1312 | printk(ACER_WARNING "bad event status 0x%x\n", status); | 1320 | pr_warning("bad event status 0x%x\n", status); |
1313 | return; | 1321 | return; |
1314 | } | 1322 | } |
1315 | 1323 | ||
@@ -1318,14 +1326,12 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1318 | if (!obj) | 1326 | if (!obj) |
1319 | return; | 1327 | return; |
1320 | if (obj->type != ACPI_TYPE_BUFFER) { | 1328 | if (obj->type != ACPI_TYPE_BUFFER) { |
1321 | printk(ACER_WARNING "Unknown response received %d\n", | 1329 | pr_warning("Unknown response received %d\n", obj->type); |
1322 | obj->type); | ||
1323 | kfree(obj); | 1330 | kfree(obj); |
1324 | return; | 1331 | return; |
1325 | } | 1332 | } |
1326 | if (obj->buffer.length != 8) { | 1333 | if (obj->buffer.length != 8) { |
1327 | printk(ACER_WARNING "Unknown buffer length %d\n", | 1334 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); |
1328 | obj->buffer.length); | ||
1329 | kfree(obj); | 1335 | kfree(obj); |
1330 | return; | 1336 | return; |
1331 | } | 1337 | } |
@@ -1335,13 +1341,26 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1335 | 1341 | ||
1336 | switch (return_value.function) { | 1342 | switch (return_value.function) { |
1337 | case WMID_HOTKEY_EVENT: | 1343 | case WMID_HOTKEY_EVENT: |
1344 | if (return_value.device_state) { | ||
1345 | u16 device_state = return_value.device_state; | ||
1346 | pr_debug("deivces states: 0x%x\n", device_state); | ||
1347 | if (has_cap(ACER_CAP_WIRELESS)) | ||
1348 | rfkill_set_sw_state(wireless_rfkill, | ||
1349 | !(device_state & ACER_WMID3_GDS_WIRELESS)); | ||
1350 | if (has_cap(ACER_CAP_BLUETOOTH)) | ||
1351 | rfkill_set_sw_state(bluetooth_rfkill, | ||
1352 | !(device_state & ACER_WMID3_GDS_BLUETOOTH)); | ||
1353 | if (has_cap(ACER_CAP_THREEG)) | ||
1354 | rfkill_set_sw_state(threeg_rfkill, | ||
1355 | !(device_state & ACER_WMID3_GDS_THREEG)); | ||
1356 | } | ||
1338 | if (!sparse_keymap_report_event(acer_wmi_input_dev, | 1357 | if (!sparse_keymap_report_event(acer_wmi_input_dev, |
1339 | return_value.key_num, 1, true)) | 1358 | return_value.key_num, 1, true)) |
1340 | printk(ACER_WARNING "Unknown key number - 0x%x\n", | 1359 | pr_warning("Unknown key number - 0x%x\n", |
1341 | return_value.key_num); | 1360 | return_value.key_num); |
1342 | break; | 1361 | break; |
1343 | default: | 1362 | default: |
1344 | printk(ACER_WARNING "Unknown function number - %d - %d\n", | 1363 | pr_warning("Unknown function number - %d - %d\n", |
1345 | return_value.function, return_value.key_num); | 1364 | return_value.function, return_value.key_num); |
1346 | break; | 1365 | break; |
1347 | } | 1366 | } |
@@ -1370,8 +1389,7 @@ wmid3_set_lm_mode(struct lm_input_params *params, | |||
1370 | return AE_ERROR; | 1389 | return AE_ERROR; |
1371 | } | 1390 | } |
1372 | if (obj->buffer.length != 4) { | 1391 | if (obj->buffer.length != 4) { |
1373 | printk(ACER_WARNING "Unknown buffer length %d\n", | 1392 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); |
1374 | obj->buffer.length); | ||
1375 | kfree(obj); | 1393 | kfree(obj); |
1376 | return AE_ERROR; | 1394 | return AE_ERROR; |
1377 | } | 1395 | } |
@@ -1396,11 +1414,11 @@ static int acer_wmi_enable_ec_raw(void) | |||
1396 | status = wmid3_set_lm_mode(¶ms, &return_value); | 1414 | status = wmid3_set_lm_mode(¶ms, &return_value); |
1397 | 1415 | ||
1398 | if (return_value.error_code || return_value.ec_return_value) | 1416 | if (return_value.error_code || return_value.ec_return_value) |
1399 | printk(ACER_WARNING "Enabling EC raw mode failed: " | 1417 | pr_warning("Enabling EC raw mode failed: " |
1400 | "0x%x - 0x%x\n", return_value.error_code, | 1418 | "0x%x - 0x%x\n", return_value.error_code, |
1401 | return_value.ec_return_value); | 1419 | return_value.ec_return_value); |
1402 | else | 1420 | else |
1403 | printk(ACER_INFO "Enabled EC raw mode"); | 1421 | pr_info("Enabled EC raw mode"); |
1404 | 1422 | ||
1405 | return status; | 1423 | return status; |
1406 | } | 1424 | } |
@@ -1419,7 +1437,7 @@ static int acer_wmi_enable_lm(void) | |||
1419 | status = wmid3_set_lm_mode(¶ms, &return_value); | 1437 | status = wmid3_set_lm_mode(¶ms, &return_value); |
1420 | 1438 | ||
1421 | if (return_value.error_code || return_value.ec_return_value) | 1439 | if (return_value.error_code || return_value.ec_return_value) |
1422 | printk(ACER_WARNING "Enabling Launch Manager failed: " | 1440 | pr_warning("Enabling Launch Manager failed: " |
1423 | "0x%x - 0x%x\n", return_value.error_code, | 1441 | "0x%x - 0x%x\n", return_value.error_code, |
1424 | return_value.ec_return_value); | 1442 | return_value.ec_return_value); |
1425 | 1443 | ||
@@ -1553,6 +1571,7 @@ pm_message_t state) | |||
1553 | 1571 | ||
1554 | if (has_cap(ACER_CAP_MAILLED)) { | 1572 | if (has_cap(ACER_CAP_MAILLED)) { |
1555 | get_u32(&value, ACER_CAP_MAILLED); | 1573 | get_u32(&value, ACER_CAP_MAILLED); |
1574 | set_u32(LED_OFF, ACER_CAP_MAILLED); | ||
1556 | data->mailled = value; | 1575 | data->mailled = value; |
1557 | } | 1576 | } |
1558 | 1577 | ||
@@ -1580,6 +1599,17 @@ static int acer_platform_resume(struct platform_device *device) | |||
1580 | return 0; | 1599 | return 0; |
1581 | } | 1600 | } |
1582 | 1601 | ||
1602 | static void acer_platform_shutdown(struct platform_device *device) | ||
1603 | { | ||
1604 | struct acer_data *data = &interface->data; | ||
1605 | |||
1606 | if (!data) | ||
1607 | return; | ||
1608 | |||
1609 | if (has_cap(ACER_CAP_MAILLED)) | ||
1610 | set_u32(LED_OFF, ACER_CAP_MAILLED); | ||
1611 | } | ||
1612 | |||
1583 | static struct platform_driver acer_platform_driver = { | 1613 | static struct platform_driver acer_platform_driver = { |
1584 | .driver = { | 1614 | .driver = { |
1585 | .name = "acer-wmi", | 1615 | .name = "acer-wmi", |
@@ -1589,6 +1619,7 @@ static struct platform_driver acer_platform_driver = { | |||
1589 | .remove = acer_platform_remove, | 1619 | .remove = acer_platform_remove, |
1590 | .suspend = acer_platform_suspend, | 1620 | .suspend = acer_platform_suspend, |
1591 | .resume = acer_platform_resume, | 1621 | .resume = acer_platform_resume, |
1622 | .shutdown = acer_platform_shutdown, | ||
1592 | }; | 1623 | }; |
1593 | 1624 | ||
1594 | static struct platform_device *acer_platform_device; | 1625 | static struct platform_device *acer_platform_device; |
@@ -1636,7 +1667,7 @@ static int create_debugfs(void) | |||
1636 | { | 1667 | { |
1637 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); | 1668 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); |
1638 | if (!interface->debug.root) { | 1669 | if (!interface->debug.root) { |
1639 | printk(ACER_ERR "Failed to create debugfs directory"); | 1670 | pr_err("Failed to create debugfs directory"); |
1640 | return -ENOMEM; | 1671 | return -ENOMEM; |
1641 | } | 1672 | } |
1642 | 1673 | ||
@@ -1657,11 +1688,10 @@ static int __init acer_wmi_init(void) | |||
1657 | { | 1688 | { |
1658 | int err; | 1689 | int err; |
1659 | 1690 | ||
1660 | printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); | 1691 | pr_info("Acer Laptop ACPI-WMI Extras\n"); |
1661 | 1692 | ||
1662 | if (dmi_check_system(acer_blacklist)) { | 1693 | if (dmi_check_system(acer_blacklist)) { |
1663 | printk(ACER_INFO "Blacklisted hardware detected - " | 1694 | pr_info("Blacklisted hardware detected - not loading\n"); |
1664 | "not loading\n"); | ||
1665 | return -ENODEV; | 1695 | return -ENODEV; |
1666 | } | 1696 | } |
1667 | 1697 | ||
@@ -1678,12 +1708,11 @@ static int __init acer_wmi_init(void) | |||
1678 | 1708 | ||
1679 | if (wmi_has_guid(WMID_GUID2) && interface) { | 1709 | if (wmi_has_guid(WMID_GUID2) && interface) { |
1680 | if (ACPI_FAILURE(WMID_set_capabilities())) { | 1710 | if (ACPI_FAILURE(WMID_set_capabilities())) { |
1681 | printk(ACER_ERR "Unable to detect available WMID " | 1711 | pr_err("Unable to detect available WMID devices\n"); |
1682 | "devices\n"); | ||
1683 | return -ENODEV; | 1712 | return -ENODEV; |
1684 | } | 1713 | } |
1685 | } else if (!wmi_has_guid(WMID_GUID2) && interface) { | 1714 | } else if (!wmi_has_guid(WMID_GUID2) && interface) { |
1686 | printk(ACER_ERR "No WMID device detection method found\n"); | 1715 | pr_err("No WMID device detection method found\n"); |
1687 | return -ENODEV; | 1716 | return -ENODEV; |
1688 | } | 1717 | } |
1689 | 1718 | ||
@@ -1691,8 +1720,7 @@ static int __init acer_wmi_init(void) | |||
1691 | interface = &AMW0_interface; | 1720 | interface = &AMW0_interface; |
1692 | 1721 | ||
1693 | if (ACPI_FAILURE(AMW0_set_capabilities())) { | 1722 | if (ACPI_FAILURE(AMW0_set_capabilities())) { |
1694 | printk(ACER_ERR "Unable to detect available AMW0 " | 1723 | pr_err("Unable to detect available AMW0 devices\n"); |
1695 | "devices\n"); | ||
1696 | return -ENODEV; | 1724 | return -ENODEV; |
1697 | } | 1725 | } |
1698 | } | 1726 | } |
@@ -1701,8 +1729,7 @@ static int __init acer_wmi_init(void) | |||
1701 | AMW0_find_mailled(); | 1729 | AMW0_find_mailled(); |
1702 | 1730 | ||
1703 | if (!interface) { | 1731 | if (!interface) { |
1704 | printk(ACER_INFO "No or unsupported WMI interface, unable to " | 1732 | pr_err("No or unsupported WMI interface, unable to load\n"); |
1705 | "load\n"); | ||
1706 | return -ENODEV; | 1733 | return -ENODEV; |
1707 | } | 1734 | } |
1708 | 1735 | ||
@@ -1710,22 +1737,22 @@ static int __init acer_wmi_init(void) | |||
1710 | 1737 | ||
1711 | if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { | 1738 | if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { |
1712 | interface->capability &= ~ACER_CAP_BRIGHTNESS; | 1739 | interface->capability &= ~ACER_CAP_BRIGHTNESS; |
1713 | printk(ACER_INFO "Brightness must be controlled by " | 1740 | pr_info("Brightness must be controlled by " |
1714 | "generic video driver\n"); | 1741 | "generic video driver\n"); |
1715 | } | 1742 | } |
1716 | 1743 | ||
1717 | if (wmi_has_guid(WMID_GUID3)) { | 1744 | if (wmi_has_guid(WMID_GUID3)) { |
1718 | if (ec_raw_mode) { | 1745 | if (ec_raw_mode) { |
1719 | if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { | 1746 | if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { |
1720 | printk(ACER_ERR "Cannot enable EC raw mode\n"); | 1747 | pr_err("Cannot enable EC raw mode\n"); |
1721 | return -ENODEV; | 1748 | return -ENODEV; |
1722 | } | 1749 | } |
1723 | } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { | 1750 | } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { |
1724 | printk(ACER_ERR "Cannot enable Launch Manager mode\n"); | 1751 | pr_err("Cannot enable Launch Manager mode\n"); |
1725 | return -ENODEV; | 1752 | return -ENODEV; |
1726 | } | 1753 | } |
1727 | } else if (ec_raw_mode) { | 1754 | } else if (ec_raw_mode) { |
1728 | printk(ACER_INFO "No WMID EC raw mode enable method\n"); | 1755 | pr_info("No WMID EC raw mode enable method\n"); |
1729 | } | 1756 | } |
1730 | 1757 | ||
1731 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) { | 1758 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) { |
@@ -1736,7 +1763,7 @@ static int __init acer_wmi_init(void) | |||
1736 | 1763 | ||
1737 | err = platform_driver_register(&acer_platform_driver); | 1764 | err = platform_driver_register(&acer_platform_driver); |
1738 | if (err) { | 1765 | if (err) { |
1739 | printk(ACER_ERR "Unable to register platform driver.\n"); | 1766 | pr_err("Unable to register platform driver.\n"); |
1740 | goto error_platform_register; | 1767 | goto error_platform_register; |
1741 | } | 1768 | } |
1742 | 1769 | ||
@@ -1791,7 +1818,7 @@ static void __exit acer_wmi_exit(void) | |||
1791 | platform_device_unregister(acer_platform_device); | 1818 | platform_device_unregister(acer_platform_device); |
1792 | platform_driver_unregister(&acer_platform_driver); | 1819 | platform_driver_unregister(&acer_platform_driver); |
1793 | 1820 | ||
1794 | printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); | 1821 | pr_info("Acer Laptop WMI Extras unloaded\n"); |
1795 | return; | 1822 | return; |
1796 | } | 1823 | } |
1797 | 1824 | ||
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 5a6f7d7575d6..c53b3ff7978a 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
@@ -29,7 +29,7 @@ | |||
29 | * John Belmonte - ACPI code for Toshiba laptop was a good starting point. | 29 | * John Belmonte - ACPI code for Toshiba laptop was a good starting point. |
30 | * Eric Burghard - LED display support for W1N | 30 | * Eric Burghard - LED display support for W1N |
31 | * Josh Green - Light Sens support | 31 | * Josh Green - Light Sens support |
32 | * Thomas Tuttle - His first patch for led support was very helpfull | 32 | * Thomas Tuttle - His first patch for led support was very helpful |
33 | * Sam Lin - GPS support | 33 | * Sam Lin - GPS support |
34 | */ | 34 | */ |
35 | 35 | ||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/input/sparse-keymap.h> | 50 | #include <linux/input/sparse-keymap.h> |
51 | #include <linux/rfkill.h> | 51 | #include <linux/rfkill.h> |
52 | #include <linux/slab.h> | 52 | #include <linux/slab.h> |
53 | #include <linux/dmi.h> | ||
53 | #include <acpi/acpi_drivers.h> | 54 | #include <acpi/acpi_drivers.h> |
54 | #include <acpi/acpi_bus.h> | 55 | #include <acpi/acpi_bus.h> |
55 | 56 | ||
@@ -157,46 +158,9 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " | |||
157 | #define METHOD_BRIGHTNESS_SET "SPLV" | 158 | #define METHOD_BRIGHTNESS_SET "SPLV" |
158 | #define METHOD_BRIGHTNESS_GET "GPLV" | 159 | #define METHOD_BRIGHTNESS_GET "GPLV" |
159 | 160 | ||
160 | /* Backlight */ | ||
161 | static acpi_handle lcd_switch_handle; | ||
162 | static char *lcd_switch_paths[] = { | ||
163 | "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ | ||
164 | "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ | ||
165 | "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ | ||
166 | "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ | ||
167 | "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ | ||
168 | "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ | ||
169 | "\\_SB.PCI0.PX40.Q10", /* S1x */ | ||
170 | "\\Q10"}; /* A2x, L2D, L3D, M2E */ | ||
171 | |||
172 | /* Display */ | 161 | /* Display */ |
173 | #define METHOD_SWITCH_DISPLAY "SDSP" | 162 | #define METHOD_SWITCH_DISPLAY "SDSP" |
174 | 163 | ||
175 | static acpi_handle display_get_handle; | ||
176 | static char *display_get_paths[] = { | ||
177 | /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ | ||
178 | "\\_SB.PCI0.P0P1.VGA.GETD", | ||
179 | /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ | ||
180 | "\\_SB.PCI0.P0P2.VGA.GETD", | ||
181 | /* A6V A6Q */ | ||
182 | "\\_SB.PCI0.P0P3.VGA.GETD", | ||
183 | /* A6T, A6M */ | ||
184 | "\\_SB.PCI0.P0PA.VGA.GETD", | ||
185 | /* L3C */ | ||
186 | "\\_SB.PCI0.PCI1.VGAC.NMAP", | ||
187 | /* Z96F */ | ||
188 | "\\_SB.PCI0.VGA.GETD", | ||
189 | /* A2D */ | ||
190 | "\\ACTD", | ||
191 | /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ | ||
192 | "\\ADVG", | ||
193 | /* P30 */ | ||
194 | "\\DNXT", | ||
195 | /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ | ||
196 | "\\INFB", | ||
197 | /* A3F A6F A3N A3L M6N W3N W6A */ | ||
198 | "\\SSTE"}; | ||
199 | |||
200 | #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ | 164 | #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ |
201 | #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ | 165 | #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ |
202 | 166 | ||
@@ -246,7 +210,6 @@ struct asus_laptop { | |||
246 | 210 | ||
247 | int wireless_status; | 211 | int wireless_status; |
248 | bool have_rsts; | 212 | bool have_rsts; |
249 | int lcd_state; | ||
250 | 213 | ||
251 | struct rfkill *gps_rfkill; | 214 | struct rfkill *gps_rfkill; |
252 | 215 | ||
@@ -559,48 +522,6 @@ error: | |||
559 | /* | 522 | /* |
560 | * Backlight device | 523 | * Backlight device |
561 | */ | 524 | */ |
562 | static int asus_lcd_status(struct asus_laptop *asus) | ||
563 | { | ||
564 | return asus->lcd_state; | ||
565 | } | ||
566 | |||
567 | static int asus_lcd_set(struct asus_laptop *asus, int value) | ||
568 | { | ||
569 | int lcd = 0; | ||
570 | acpi_status status = 0; | ||
571 | |||
572 | lcd = !!value; | ||
573 | |||
574 | if (lcd == asus_lcd_status(asus)) | ||
575 | return 0; | ||
576 | |||
577 | if (!lcd_switch_handle) | ||
578 | return -ENODEV; | ||
579 | |||
580 | status = acpi_evaluate_object(lcd_switch_handle, | ||
581 | NULL, NULL, NULL); | ||
582 | |||
583 | if (ACPI_FAILURE(status)) { | ||
584 | pr_warning("Error switching LCD\n"); | ||
585 | return -ENODEV; | ||
586 | } | ||
587 | |||
588 | asus->lcd_state = lcd; | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static void lcd_blank(struct asus_laptop *asus, int blank) | ||
593 | { | ||
594 | struct backlight_device *bd = asus->backlight_device; | ||
595 | |||
596 | asus->lcd_state = (blank == FB_BLANK_UNBLANK); | ||
597 | |||
598 | if (bd) { | ||
599 | bd->props.power = blank; | ||
600 | backlight_update_status(bd); | ||
601 | } | ||
602 | } | ||
603 | |||
604 | static int asus_read_brightness(struct backlight_device *bd) | 525 | static int asus_read_brightness(struct backlight_device *bd) |
605 | { | 526 | { |
606 | struct asus_laptop *asus = bl_get_data(bd); | 527 | struct asus_laptop *asus = bl_get_data(bd); |
@@ -628,16 +549,9 @@ static int asus_set_brightness(struct backlight_device *bd, int value) | |||
628 | 549 | ||
629 | static int update_bl_status(struct backlight_device *bd) | 550 | static int update_bl_status(struct backlight_device *bd) |
630 | { | 551 | { |
631 | struct asus_laptop *asus = bl_get_data(bd); | ||
632 | int rv; | ||
633 | int value = bd->props.brightness; | 552 | int value = bd->props.brightness; |
634 | 553 | ||
635 | rv = asus_set_brightness(bd, value); | 554 | return asus_set_brightness(bd, value); |
636 | if (rv) | ||
637 | return rv; | ||
638 | |||
639 | value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; | ||
640 | return asus_lcd_set(asus, value); | ||
641 | } | 555 | } |
642 | 556 | ||
643 | static const struct backlight_ops asusbl_ops = { | 557 | static const struct backlight_ops asusbl_ops = { |
@@ -661,8 +575,7 @@ static int asus_backlight_init(struct asus_laptop *asus) | |||
661 | struct backlight_properties props; | 575 | struct backlight_properties props; |
662 | 576 | ||
663 | if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || | 577 | if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || |
664 | acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) || | 578 | acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL)) |
665 | !lcd_switch_handle) | ||
666 | return 0; | 579 | return 0; |
667 | 580 | ||
668 | memset(&props, 0, sizeof(struct backlight_properties)); | 581 | memset(&props, 0, sizeof(struct backlight_properties)); |
@@ -971,41 +884,6 @@ static void asus_set_display(struct asus_laptop *asus, int value) | |||
971 | return; | 884 | return; |
972 | } | 885 | } |
973 | 886 | ||
974 | static int read_display(struct asus_laptop *asus) | ||
975 | { | ||
976 | unsigned long long value = 0; | ||
977 | acpi_status rv = AE_OK; | ||
978 | |||
979 | /* | ||
980 | * In most of the case, we know how to set the display, but sometime | ||
981 | * we can't read it | ||
982 | */ | ||
983 | if (display_get_handle) { | ||
984 | rv = acpi_evaluate_integer(display_get_handle, NULL, | ||
985 | NULL, &value); | ||
986 | if (ACPI_FAILURE(rv)) | ||
987 | pr_warning("Error reading display status\n"); | ||
988 | } | ||
989 | |||
990 | value &= 0x0F; /* needed for some models, shouldn't hurt others */ | ||
991 | |||
992 | return value; | ||
993 | } | ||
994 | |||
995 | /* | ||
996 | * Now, *this* one could be more user-friendly, but so far, no-one has | ||
997 | * complained. The significance of bits is the same as in store_disp() | ||
998 | */ | ||
999 | static ssize_t show_disp(struct device *dev, | ||
1000 | struct device_attribute *attr, char *buf) | ||
1001 | { | ||
1002 | struct asus_laptop *asus = dev_get_drvdata(dev); | ||
1003 | |||
1004 | if (!display_get_handle) | ||
1005 | return -ENODEV; | ||
1006 | return sprintf(buf, "%d\n", read_display(asus)); | ||
1007 | } | ||
1008 | |||
1009 | /* | 887 | /* |
1010 | * Experimental support for display switching. As of now: 1 should activate | 888 | * Experimental support for display switching. As of now: 1 should activate |
1011 | * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. | 889 | * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. |
@@ -1247,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) | |||
1247 | struct asus_laptop *asus = acpi_driver_data(device); | 1125 | struct asus_laptop *asus = acpi_driver_data(device); |
1248 | u16 count; | 1126 | u16 count; |
1249 | 1127 | ||
1250 | /* | ||
1251 | * We need to tell the backlight device when the backlight power is | ||
1252 | * switched | ||
1253 | */ | ||
1254 | if (event == ATKD_LCD_ON) | ||
1255 | lcd_blank(asus, FB_BLANK_UNBLANK); | ||
1256 | else if (event == ATKD_LCD_OFF) | ||
1257 | lcd_blank(asus, FB_BLANK_POWERDOWN); | ||
1258 | |||
1259 | /* TODO Find a better way to handle events count. */ | 1128 | /* TODO Find a better way to handle events count. */ |
1260 | count = asus->event_count[event % 128]++; | 1129 | count = asus->event_count[event % 128]++; |
1261 | acpi_bus_generate_proc_event(asus->device, event, count); | 1130 | acpi_bus_generate_proc_event(asus->device, event, count); |
@@ -1282,7 +1151,7 @@ static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, | |||
1282 | show_bluetooth, store_bluetooth); | 1151 | show_bluetooth, store_bluetooth); |
1283 | static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); | 1152 | static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); |
1284 | static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); | 1153 | static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); |
1285 | static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); | 1154 | static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp); |
1286 | static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); | 1155 | static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); |
1287 | static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); | 1156 | static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); |
1288 | static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); | 1157 | static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); |
@@ -1393,26 +1262,6 @@ static struct platform_driver platform_driver = { | |||
1393 | } | 1262 | } |
1394 | }; | 1263 | }; |
1395 | 1264 | ||
1396 | static int asus_handle_init(char *name, acpi_handle * handle, | ||
1397 | char **paths, int num_paths) | ||
1398 | { | ||
1399 | int i; | ||
1400 | acpi_status status; | ||
1401 | |||
1402 | for (i = 0; i < num_paths; i++) { | ||
1403 | status = acpi_get_handle(NULL, paths[i], handle); | ||
1404 | if (ACPI_SUCCESS(status)) | ||
1405 | return 0; | ||
1406 | } | ||
1407 | |||
1408 | *handle = NULL; | ||
1409 | return -ENODEV; | ||
1410 | } | ||
1411 | |||
1412 | #define ASUS_HANDLE_INIT(object) \ | ||
1413 | asus_handle_init(#object, &object##_handle, object##_paths, \ | ||
1414 | ARRAY_SIZE(object##_paths)) | ||
1415 | |||
1416 | /* | 1265 | /* |
1417 | * This function is used to initialize the context with right values. In this | 1266 | * This function is used to initialize the context with right values. In this |
1418 | * method, we can make all the detection we want, and modify the asus_laptop | 1267 | * method, we can make all the detection we want, and modify the asus_laptop |
@@ -1498,10 +1347,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
1498 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) | 1347 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) |
1499 | asus->have_rsts = true; | 1348 | asus->have_rsts = true; |
1500 | 1349 | ||
1501 | /* Scheduled for removal */ | ||
1502 | ASUS_HANDLE_INIT(lcd_switch); | ||
1503 | ASUS_HANDLE_INIT(display_get); | ||
1504 | |||
1505 | kfree(model); | 1350 | kfree(model); |
1506 | 1351 | ||
1507 | return AE_OK; | 1352 | return AE_OK; |
@@ -1553,10 +1398,23 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) | |||
1553 | asus_als_level(asus, asus->light_level); | 1398 | asus_als_level(asus, asus->light_level); |
1554 | } | 1399 | } |
1555 | 1400 | ||
1556 | asus->lcd_state = 1; /* LCD should be on when the module load */ | ||
1557 | return result; | 1401 | return result; |
1558 | } | 1402 | } |
1559 | 1403 | ||
1404 | static void __devinit asus_dmi_check(void) | ||
1405 | { | ||
1406 | const char *model; | ||
1407 | |||
1408 | model = dmi_get_system_info(DMI_PRODUCT_NAME); | ||
1409 | if (!model) | ||
1410 | return; | ||
1411 | |||
1412 | /* On L1400B WLED control the sound card, don't mess with it ... */ | ||
1413 | if (strncmp(model, "L1400B", 6) == 0) { | ||
1414 | wlan_status = -1; | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1560 | static bool asus_device_present; | 1418 | static bool asus_device_present; |
1561 | 1419 | ||
1562 | static int __devinit asus_acpi_add(struct acpi_device *device) | 1420 | static int __devinit asus_acpi_add(struct acpi_device *device) |
@@ -1575,6 +1433,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device) | |||
1575 | device->driver_data = asus; | 1433 | device->driver_data = asus; |
1576 | asus->device = device; | 1434 | asus->device = device; |
1577 | 1435 | ||
1436 | asus_dmi_check(); | ||
1437 | |||
1578 | result = asus_acpi_init(asus); | 1438 | result = asus_acpi_init(asus); |
1579 | if (result) | 1439 | if (result) |
1580 | goto fail_platform; | 1440 | goto fail_platform; |
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c new file mode 100644 index 000000000000..0580d99b0798 --- /dev/null +++ b/drivers/platform/x86/asus-nb-wmi.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Asus Notebooks WMI hotkey driver | ||
3 | * | ||
4 | * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/input.h> | ||
27 | #include <linux/input/sparse-keymap.h> | ||
28 | |||
29 | #include "asus-wmi.h" | ||
30 | |||
31 | #define ASUS_NB_WMI_FILE "asus-nb-wmi" | ||
32 | |||
33 | MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>"); | ||
34 | MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | #define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" | ||
38 | |||
39 | MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); | ||
40 | |||
41 | static const struct key_entry asus_nb_wmi_keymap[] = { | ||
42 | { KE_KEY, 0x30, { KEY_VOLUMEUP } }, | ||
43 | { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, | ||
44 | { KE_KEY, 0x32, { KEY_MUTE } }, | ||
45 | { KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */ | ||
46 | { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */ | ||
47 | { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, | ||
48 | { KE_KEY, 0x41, { KEY_NEXTSONG } }, | ||
49 | { KE_KEY, 0x43, { KEY_STOPCD } }, | ||
50 | { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, | ||
51 | { KE_KEY, 0x4c, { KEY_MEDIA } }, | ||
52 | { KE_KEY, 0x50, { KEY_EMAIL } }, | ||
53 | { KE_KEY, 0x51, { KEY_WWW } }, | ||
54 | { KE_KEY, 0x55, { KEY_CALC } }, | ||
55 | { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ | ||
56 | { KE_KEY, 0x5D, { KEY_WLAN } }, | ||
57 | { KE_KEY, 0x5E, { KEY_WLAN } }, | ||
58 | { KE_KEY, 0x5F, { KEY_WLAN } }, | ||
59 | { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, | ||
60 | { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, | ||
61 | { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, | ||
62 | { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, | ||
63 | { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, | ||
64 | { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, | ||
65 | { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, | ||
66 | { KE_KEY, 0x82, { KEY_CAMERA } }, | ||
67 | { KE_KEY, 0x88, { KEY_RFKILL } }, | ||
68 | { KE_KEY, 0x8A, { KEY_PROG1 } }, | ||
69 | { KE_KEY, 0x95, { KEY_MEDIA } }, | ||
70 | { KE_KEY, 0x99, { KEY_PHONE } }, | ||
71 | { KE_KEY, 0xb5, { KEY_CALC } }, | ||
72 | { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, | ||
73 | { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, | ||
74 | { KE_END, 0}, | ||
75 | }; | ||
76 | |||
77 | static struct asus_wmi_driver asus_nb_wmi_driver = { | ||
78 | .name = ASUS_NB_WMI_FILE, | ||
79 | .owner = THIS_MODULE, | ||
80 | .event_guid = ASUS_NB_WMI_EVENT_GUID, | ||
81 | .keymap = asus_nb_wmi_keymap, | ||
82 | .input_name = "Asus WMI hotkeys", | ||
83 | .input_phys = ASUS_NB_WMI_FILE "/input0", | ||
84 | }; | ||
85 | |||
86 | |||
87 | static int __init asus_nb_wmi_init(void) | ||
88 | { | ||
89 | return asus_wmi_register_driver(&asus_nb_wmi_driver); | ||
90 | } | ||
91 | |||
92 | static void __exit asus_nb_wmi_exit(void) | ||
93 | { | ||
94 | asus_wmi_unregister_driver(&asus_nb_wmi_driver); | ||
95 | } | ||
96 | |||
97 | module_init(asus_nb_wmi_init); | ||
98 | module_exit(asus_nb_wmi_exit); | ||
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c new file mode 100644 index 000000000000..efc776cb0c66 --- /dev/null +++ b/drivers/platform/x86/asus-wmi.c | |||
@@ -0,0 +1,1656 @@ | |||
1 | /* | ||
2 | * Asus PC WMI hotkey driver | ||
3 | * | ||
4 | * Copyright(C) 2010 Intel Corporation. | ||
5 | * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> | ||
6 | * | ||
7 | * Portions based on wistron_btns.c: | ||
8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | ||
9 | * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> | ||
10 | * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
28 | |||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/input.h> | ||
35 | #include <linux/input/sparse-keymap.h> | ||
36 | #include <linux/fb.h> | ||
37 | #include <linux/backlight.h> | ||
38 | #include <linux/leds.h> | ||
39 | #include <linux/rfkill.h> | ||
40 | #include <linux/pci.h> | ||
41 | #include <linux/pci_hotplug.h> | ||
42 | #include <linux/hwmon.h> | ||
43 | #include <linux/hwmon-sysfs.h> | ||
44 | #include <linux/debugfs.h> | ||
45 | #include <linux/seq_file.h> | ||
46 | #include <linux/platform_device.h> | ||
47 | #include <acpi/acpi_bus.h> | ||
48 | #include <acpi/acpi_drivers.h> | ||
49 | |||
50 | #include "asus-wmi.h" | ||
51 | |||
52 | MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>, " | ||
53 | "Yong Wang <yong.y.wang@intel.com>"); | ||
54 | MODULE_DESCRIPTION("Asus Generic WMI Driver"); | ||
55 | MODULE_LICENSE("GPL"); | ||
56 | |||
57 | #define to_platform_driver(drv) \ | ||
58 | (container_of((drv), struct platform_driver, driver)) | ||
59 | |||
60 | #define to_asus_wmi_driver(pdrv) \ | ||
61 | (container_of((pdrv), struct asus_wmi_driver, platform_driver)) | ||
62 | |||
63 | #define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" | ||
64 | |||
65 | #define NOTIFY_BRNUP_MIN 0x11 | ||
66 | #define NOTIFY_BRNUP_MAX 0x1f | ||
67 | #define NOTIFY_BRNDOWN_MIN 0x20 | ||
68 | #define NOTIFY_BRNDOWN_MAX 0x2e | ||
69 | |||
70 | /* WMI Methods */ | ||
71 | #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ | ||
72 | #define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */ | ||
73 | #define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */ | ||
74 | #define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */ | ||
75 | #define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */ | ||
76 | #define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */ | ||
77 | #define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */ | ||
78 | #define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */ | ||
79 | #define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */ | ||
80 | #define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */ | ||
81 | #define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */ | ||
82 | #define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */ | ||
83 | #define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/ | ||
84 | #define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */ | ||
85 | #define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */ | ||
86 | #define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */ | ||
87 | #define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */ | ||
88 | #define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */ | ||
89 | #define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */ | ||
90 | |||
91 | #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE | ||
92 | |||
93 | /* Wireless */ | ||
94 | #define ASUS_WMI_DEVID_HW_SWITCH 0x00010001 | ||
95 | #define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 | ||
96 | #define ASUS_WMI_DEVID_WLAN 0x00010011 | ||
97 | #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 | ||
98 | #define ASUS_WMI_DEVID_GPS 0x00010015 | ||
99 | #define ASUS_WMI_DEVID_WIMAX 0x00010017 | ||
100 | #define ASUS_WMI_DEVID_WWAN3G 0x00010019 | ||
101 | #define ASUS_WMI_DEVID_UWB 0x00010021 | ||
102 | |||
103 | /* Leds */ | ||
104 | /* 0x000200XX and 0x000400XX */ | ||
105 | |||
106 | /* Backlight and Brightness */ | ||
107 | #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 | ||
108 | #define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 | ||
109 | #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 | ||
110 | #define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */ | ||
111 | |||
112 | /* Misc */ | ||
113 | #define ASUS_WMI_DEVID_CAMERA 0x00060013 | ||
114 | |||
115 | /* Storage */ | ||
116 | #define ASUS_WMI_DEVID_CARDREADER 0x00080013 | ||
117 | |||
118 | /* Input */ | ||
119 | #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 | ||
120 | #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 | ||
121 | |||
122 | /* Fan, Thermal */ | ||
123 | #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 | ||
124 | #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 | ||
125 | |||
126 | /* Power */ | ||
127 | #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 | ||
128 | |||
129 | /* DSTS masks */ | ||
130 | #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 | ||
131 | #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 | ||
132 | #define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000 | ||
133 | #define ASUS_WMI_DSTS_USER_BIT 0x00020000 | ||
134 | #define ASUS_WMI_DSTS_BIOS_BIT 0x00040000 | ||
135 | #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF | ||
136 | #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 | ||
137 | |||
138 | struct bios_args { | ||
139 | u32 arg0; | ||
140 | u32 arg1; | ||
141 | } __packed; | ||
142 | |||
143 | /* | ||
144 | * <platform>/ - debugfs root directory | ||
145 | * dev_id - current dev_id | ||
146 | * ctrl_param - current ctrl_param | ||
147 | * method_id - current method_id | ||
148 | * devs - call DEVS(dev_id, ctrl_param) and print result | ||
149 | * dsts - call DSTS(dev_id) and print result | ||
150 | * call - call method_id(dev_id, ctrl_param) and print result | ||
151 | */ | ||
152 | struct asus_wmi_debug { | ||
153 | struct dentry *root; | ||
154 | u32 method_id; | ||
155 | u32 dev_id; | ||
156 | u32 ctrl_param; | ||
157 | }; | ||
158 | |||
159 | struct asus_rfkill { | ||
160 | struct asus_wmi *asus; | ||
161 | struct rfkill *rfkill; | ||
162 | u32 dev_id; | ||
163 | }; | ||
164 | |||
165 | struct asus_wmi { | ||
166 | int dsts_id; | ||
167 | int spec; | ||
168 | int sfun; | ||
169 | |||
170 | struct input_dev *inputdev; | ||
171 | struct backlight_device *backlight_device; | ||
172 | struct device *hwmon_device; | ||
173 | struct platform_device *platform_device; | ||
174 | |||
175 | struct led_classdev tpd_led; | ||
176 | int tpd_led_wk; | ||
177 | struct workqueue_struct *led_workqueue; | ||
178 | struct work_struct tpd_led_work; | ||
179 | |||
180 | struct asus_rfkill wlan; | ||
181 | struct asus_rfkill bluetooth; | ||
182 | struct asus_rfkill wimax; | ||
183 | struct asus_rfkill wwan3g; | ||
184 | |||
185 | struct hotplug_slot *hotplug_slot; | ||
186 | struct mutex hotplug_lock; | ||
187 | struct mutex wmi_lock; | ||
188 | struct workqueue_struct *hotplug_workqueue; | ||
189 | struct work_struct hotplug_work; | ||
190 | |||
191 | struct asus_wmi_debug debug; | ||
192 | |||
193 | struct asus_wmi_driver *driver; | ||
194 | }; | ||
195 | |||
196 | static int asus_wmi_input_init(struct asus_wmi *asus) | ||
197 | { | ||
198 | int err; | ||
199 | |||
200 | asus->inputdev = input_allocate_device(); | ||
201 | if (!asus->inputdev) | ||
202 | return -ENOMEM; | ||
203 | |||
204 | asus->inputdev->name = asus->driver->input_phys; | ||
205 | asus->inputdev->phys = asus->driver->input_name; | ||
206 | asus->inputdev->id.bustype = BUS_HOST; | ||
207 | asus->inputdev->dev.parent = &asus->platform_device->dev; | ||
208 | |||
209 | err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); | ||
210 | if (err) | ||
211 | goto err_free_dev; | ||
212 | |||
213 | err = input_register_device(asus->inputdev); | ||
214 | if (err) | ||
215 | goto err_free_keymap; | ||
216 | |||
217 | return 0; | ||
218 | |||
219 | err_free_keymap: | ||
220 | sparse_keymap_free(asus->inputdev); | ||
221 | err_free_dev: | ||
222 | input_free_device(asus->inputdev); | ||
223 | return err; | ||
224 | } | ||
225 | |||
226 | static void asus_wmi_input_exit(struct asus_wmi *asus) | ||
227 | { | ||
228 | if (asus->inputdev) { | ||
229 | sparse_keymap_free(asus->inputdev); | ||
230 | input_unregister_device(asus->inputdev); | ||
231 | } | ||
232 | |||
233 | asus->inputdev = NULL; | ||
234 | } | ||
235 | |||
236 | static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, | ||
237 | u32 *retval) | ||
238 | { | ||
239 | struct bios_args args = { | ||
240 | .arg0 = arg0, | ||
241 | .arg1 = arg1, | ||
242 | }; | ||
243 | struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; | ||
244 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
245 | acpi_status status; | ||
246 | union acpi_object *obj; | ||
247 | u32 tmp; | ||
248 | |||
249 | status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, | ||
250 | &input, &output); | ||
251 | |||
252 | if (ACPI_FAILURE(status)) | ||
253 | goto exit; | ||
254 | |||
255 | obj = (union acpi_object *)output.pointer; | ||
256 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
257 | tmp = (u32) obj->integer.value; | ||
258 | else | ||
259 | tmp = 0; | ||
260 | |||
261 | if (retval) | ||
262 | *retval = tmp; | ||
263 | |||
264 | kfree(obj); | ||
265 | |||
266 | exit: | ||
267 | if (ACPI_FAILURE(status)) | ||
268 | return -EIO; | ||
269 | |||
270 | if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) | ||
271 | return -ENODEV; | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) | ||
277 | { | ||
278 | return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval); | ||
279 | } | ||
280 | |||
281 | static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, | ||
282 | u32 *retval) | ||
283 | { | ||
284 | return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, | ||
285 | ctrl_param, retval); | ||
286 | } | ||
287 | |||
288 | /* Helper for special devices with magic return codes */ | ||
289 | static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, | ||
290 | u32 dev_id, u32 mask) | ||
291 | { | ||
292 | u32 retval = 0; | ||
293 | int err; | ||
294 | |||
295 | err = asus_wmi_get_devstate(asus, dev_id, &retval); | ||
296 | |||
297 | if (err < 0) | ||
298 | return err; | ||
299 | |||
300 | if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) | ||
301 | return -ENODEV; | ||
302 | |||
303 | if (mask == ASUS_WMI_DSTS_STATUS_BIT) { | ||
304 | if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT) | ||
305 | return -ENODEV; | ||
306 | } | ||
307 | |||
308 | return retval & mask; | ||
309 | } | ||
310 | |||
311 | static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) | ||
312 | { | ||
313 | return asus_wmi_get_devstate_bits(asus, dev_id, | ||
314 | ASUS_WMI_DSTS_STATUS_BIT); | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * LEDs | ||
319 | */ | ||
320 | /* | ||
321 | * These functions actually update the LED's, and are called from a | ||
322 | * workqueue. By doing this as separate work rather than when the LED | ||
323 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a | ||
324 | * potentially bad time, such as a timer interrupt. | ||
325 | */ | ||
326 | static void tpd_led_update(struct work_struct *work) | ||
327 | { | ||
328 | int ctrl_param; | ||
329 | struct asus_wmi *asus; | ||
330 | |||
331 | asus = container_of(work, struct asus_wmi, tpd_led_work); | ||
332 | |||
333 | ctrl_param = asus->tpd_led_wk; | ||
334 | asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); | ||
335 | } | ||
336 | |||
337 | static void tpd_led_set(struct led_classdev *led_cdev, | ||
338 | enum led_brightness value) | ||
339 | { | ||
340 | struct asus_wmi *asus; | ||
341 | |||
342 | asus = container_of(led_cdev, struct asus_wmi, tpd_led); | ||
343 | |||
344 | asus->tpd_led_wk = !!value; | ||
345 | queue_work(asus->led_workqueue, &asus->tpd_led_work); | ||
346 | } | ||
347 | |||
348 | static int read_tpd_led_state(struct asus_wmi *asus) | ||
349 | { | ||
350 | return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED); | ||
351 | } | ||
352 | |||
353 | static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) | ||
354 | { | ||
355 | struct asus_wmi *asus; | ||
356 | |||
357 | asus = container_of(led_cdev, struct asus_wmi, tpd_led); | ||
358 | |||
359 | return read_tpd_led_state(asus); | ||
360 | } | ||
361 | |||
362 | static int asus_wmi_led_init(struct asus_wmi *asus) | ||
363 | { | ||
364 | int rv; | ||
365 | |||
366 | if (read_tpd_led_state(asus) < 0) | ||
367 | return 0; | ||
368 | |||
369 | asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); | ||
370 | if (!asus->led_workqueue) | ||
371 | return -ENOMEM; | ||
372 | INIT_WORK(&asus->tpd_led_work, tpd_led_update); | ||
373 | |||
374 | asus->tpd_led.name = "asus::touchpad"; | ||
375 | asus->tpd_led.brightness_set = tpd_led_set; | ||
376 | asus->tpd_led.brightness_get = tpd_led_get; | ||
377 | asus->tpd_led.max_brightness = 1; | ||
378 | |||
379 | rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led); | ||
380 | if (rv) { | ||
381 | destroy_workqueue(asus->led_workqueue); | ||
382 | return rv; | ||
383 | } | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static void asus_wmi_led_exit(struct asus_wmi *asus) | ||
389 | { | ||
390 | if (asus->tpd_led.dev) | ||
391 | led_classdev_unregister(&asus->tpd_led); | ||
392 | if (asus->led_workqueue) | ||
393 | destroy_workqueue(asus->led_workqueue); | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * PCI hotplug (for wlan rfkill) | ||
398 | */ | ||
399 | static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) | ||
400 | { | ||
401 | int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); | ||
402 | |||
403 | if (result < 0) | ||
404 | return false; | ||
405 | return !result; | ||
406 | } | ||
407 | |||
408 | static void asus_rfkill_hotplug(struct asus_wmi *asus) | ||
409 | { | ||
410 | struct pci_dev *dev; | ||
411 | struct pci_bus *bus; | ||
412 | bool blocked; | ||
413 | bool absent; | ||
414 | u32 l; | ||
415 | |||
416 | mutex_lock(&asus->wmi_lock); | ||
417 | blocked = asus_wlan_rfkill_blocked(asus); | ||
418 | mutex_unlock(&asus->wmi_lock); | ||
419 | |||
420 | mutex_lock(&asus->hotplug_lock); | ||
421 | |||
422 | if (asus->wlan.rfkill) | ||
423 | rfkill_set_sw_state(asus->wlan.rfkill, blocked); | ||
424 | |||
425 | if (asus->hotplug_slot) { | ||
426 | bus = pci_find_bus(0, 1); | ||
427 | if (!bus) { | ||
428 | pr_warning("Unable to find PCI bus 1?\n"); | ||
429 | goto out_unlock; | ||
430 | } | ||
431 | |||
432 | if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { | ||
433 | pr_err("Unable to read PCI config space?\n"); | ||
434 | goto out_unlock; | ||
435 | } | ||
436 | absent = (l == 0xffffffff); | ||
437 | |||
438 | if (blocked != absent) { | ||
439 | pr_warning("BIOS says wireless lan is %s, " | ||
440 | "but the pci device is %s\n", | ||
441 | blocked ? "blocked" : "unblocked", | ||
442 | absent ? "absent" : "present"); | ||
443 | pr_warning("skipped wireless hotplug as probably " | ||
444 | "inappropriate for this model\n"); | ||
445 | goto out_unlock; | ||
446 | } | ||
447 | |||
448 | if (!blocked) { | ||
449 | dev = pci_get_slot(bus, 0); | ||
450 | if (dev) { | ||
451 | /* Device already present */ | ||
452 | pci_dev_put(dev); | ||
453 | goto out_unlock; | ||
454 | } | ||
455 | dev = pci_scan_single_device(bus, 0); | ||
456 | if (dev) { | ||
457 | pci_bus_assign_resources(bus); | ||
458 | if (pci_bus_add_device(dev)) | ||
459 | pr_err("Unable to hotplug wifi\n"); | ||
460 | } | ||
461 | } else { | ||
462 | dev = pci_get_slot(bus, 0); | ||
463 | if (dev) { | ||
464 | pci_remove_bus_device(dev); | ||
465 | pci_dev_put(dev); | ||
466 | } | ||
467 | } | ||
468 | } | ||
469 | |||
470 | out_unlock: | ||
471 | mutex_unlock(&asus->hotplug_lock); | ||
472 | } | ||
473 | |||
474 | static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data) | ||
475 | { | ||
476 | struct asus_wmi *asus = data; | ||
477 | |||
478 | if (event != ACPI_NOTIFY_BUS_CHECK) | ||
479 | return; | ||
480 | |||
481 | /* | ||
482 | * We can't call directly asus_rfkill_hotplug because most | ||
483 | * of the time WMBC is still being executed and not reetrant. | ||
484 | * There is currently no way to tell ACPICA that we want this | ||
485 | * method to be serialized, we schedule a asus_rfkill_hotplug | ||
486 | * call later, in a safer context. | ||
487 | */ | ||
488 | queue_work(asus->hotplug_workqueue, &asus->hotplug_work); | ||
489 | } | ||
490 | |||
491 | static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node) | ||
492 | { | ||
493 | acpi_status status; | ||
494 | acpi_handle handle; | ||
495 | |||
496 | status = acpi_get_handle(NULL, node, &handle); | ||
497 | |||
498 | if (ACPI_SUCCESS(status)) { | ||
499 | status = acpi_install_notify_handler(handle, | ||
500 | ACPI_SYSTEM_NOTIFY, | ||
501 | asus_rfkill_notify, asus); | ||
502 | if (ACPI_FAILURE(status)) | ||
503 | pr_warning("Failed to register notify on %s\n", node); | ||
504 | } else | ||
505 | return -ENODEV; | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) | ||
511 | { | ||
512 | acpi_status status = AE_OK; | ||
513 | acpi_handle handle; | ||
514 | |||
515 | status = acpi_get_handle(NULL, node, &handle); | ||
516 | |||
517 | if (ACPI_SUCCESS(status)) { | ||
518 | status = acpi_remove_notify_handler(handle, | ||
519 | ACPI_SYSTEM_NOTIFY, | ||
520 | asus_rfkill_notify); | ||
521 | if (ACPI_FAILURE(status)) | ||
522 | pr_err("Error removing rfkill notify handler %s\n", | ||
523 | node); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, | ||
528 | u8 *value) | ||
529 | { | ||
530 | struct asus_wmi *asus = hotplug_slot->private; | ||
531 | int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); | ||
532 | |||
533 | if (result < 0) | ||
534 | return result; | ||
535 | |||
536 | *value = !!result; | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static void asus_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) | ||
541 | { | ||
542 | kfree(hotplug_slot->info); | ||
543 | kfree(hotplug_slot); | ||
544 | } | ||
545 | |||
546 | static struct hotplug_slot_ops asus_hotplug_slot_ops = { | ||
547 | .owner = THIS_MODULE, | ||
548 | .get_adapter_status = asus_get_adapter_status, | ||
549 | .get_power_status = asus_get_adapter_status, | ||
550 | }; | ||
551 | |||
552 | static void asus_hotplug_work(struct work_struct *work) | ||
553 | { | ||
554 | struct asus_wmi *asus; | ||
555 | |||
556 | asus = container_of(work, struct asus_wmi, hotplug_work); | ||
557 | asus_rfkill_hotplug(asus); | ||
558 | } | ||
559 | |||
560 | static int asus_setup_pci_hotplug(struct asus_wmi *asus) | ||
561 | { | ||
562 | int ret = -ENOMEM; | ||
563 | struct pci_bus *bus = pci_find_bus(0, 1); | ||
564 | |||
565 | if (!bus) { | ||
566 | pr_err("Unable to find wifi PCI bus\n"); | ||
567 | return -ENODEV; | ||
568 | } | ||
569 | |||
570 | asus->hotplug_workqueue = | ||
571 | create_singlethread_workqueue("hotplug_workqueue"); | ||
572 | if (!asus->hotplug_workqueue) | ||
573 | goto error_workqueue; | ||
574 | |||
575 | INIT_WORK(&asus->hotplug_work, asus_hotplug_work); | ||
576 | |||
577 | asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | ||
578 | if (!asus->hotplug_slot) | ||
579 | goto error_slot; | ||
580 | |||
581 | asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), | ||
582 | GFP_KERNEL); | ||
583 | if (!asus->hotplug_slot->info) | ||
584 | goto error_info; | ||
585 | |||
586 | asus->hotplug_slot->private = asus; | ||
587 | asus->hotplug_slot->release = &asus_cleanup_pci_hotplug; | ||
588 | asus->hotplug_slot->ops = &asus_hotplug_slot_ops; | ||
589 | asus_get_adapter_status(asus->hotplug_slot, | ||
590 | &asus->hotplug_slot->info->adapter_status); | ||
591 | |||
592 | ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi"); | ||
593 | if (ret) { | ||
594 | pr_err("Unable to register hotplug slot - %d\n", ret); | ||
595 | goto error_register; | ||
596 | } | ||
597 | |||
598 | return 0; | ||
599 | |||
600 | error_register: | ||
601 | kfree(asus->hotplug_slot->info); | ||
602 | error_info: | ||
603 | kfree(asus->hotplug_slot); | ||
604 | asus->hotplug_slot = NULL; | ||
605 | error_slot: | ||
606 | destroy_workqueue(asus->hotplug_workqueue); | ||
607 | error_workqueue: | ||
608 | return ret; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * Rfkill devices | ||
613 | */ | ||
614 | static int asus_rfkill_set(void *data, bool blocked) | ||
615 | { | ||
616 | struct asus_rfkill *priv = data; | ||
617 | u32 ctrl_param = !blocked; | ||
618 | |||
619 | return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL); | ||
620 | } | ||
621 | |||
622 | static void asus_rfkill_query(struct rfkill *rfkill, void *data) | ||
623 | { | ||
624 | struct asus_rfkill *priv = data; | ||
625 | int result; | ||
626 | |||
627 | result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id); | ||
628 | |||
629 | if (result < 0) | ||
630 | return; | ||
631 | |||
632 | rfkill_set_sw_state(priv->rfkill, !result); | ||
633 | } | ||
634 | |||
635 | static int asus_rfkill_wlan_set(void *data, bool blocked) | ||
636 | { | ||
637 | struct asus_rfkill *priv = data; | ||
638 | struct asus_wmi *asus = priv->asus; | ||
639 | int ret; | ||
640 | |||
641 | /* | ||
642 | * This handler is enabled only if hotplug is enabled. | ||
643 | * In this case, the asus_wmi_set_devstate() will | ||
644 | * trigger a wmi notification and we need to wait | ||
645 | * this call to finish before being able to call | ||
646 | * any wmi method | ||
647 | */ | ||
648 | mutex_lock(&asus->wmi_lock); | ||
649 | ret = asus_rfkill_set(data, blocked); | ||
650 | mutex_unlock(&asus->wmi_lock); | ||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | static const struct rfkill_ops asus_rfkill_wlan_ops = { | ||
655 | .set_block = asus_rfkill_wlan_set, | ||
656 | .query = asus_rfkill_query, | ||
657 | }; | ||
658 | |||
659 | static const struct rfkill_ops asus_rfkill_ops = { | ||
660 | .set_block = asus_rfkill_set, | ||
661 | .query = asus_rfkill_query, | ||
662 | }; | ||
663 | |||
664 | static int asus_new_rfkill(struct asus_wmi *asus, | ||
665 | struct asus_rfkill *arfkill, | ||
666 | const char *name, enum rfkill_type type, int dev_id) | ||
667 | { | ||
668 | int result = asus_wmi_get_devstate_simple(asus, dev_id); | ||
669 | struct rfkill **rfkill = &arfkill->rfkill; | ||
670 | |||
671 | if (result < 0) | ||
672 | return result; | ||
673 | |||
674 | arfkill->dev_id = dev_id; | ||
675 | arfkill->asus = asus; | ||
676 | |||
677 | if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless) | ||
678 | *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, | ||
679 | &asus_rfkill_wlan_ops, arfkill); | ||
680 | else | ||
681 | *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, | ||
682 | &asus_rfkill_ops, arfkill); | ||
683 | |||
684 | if (!*rfkill) | ||
685 | return -EINVAL; | ||
686 | |||
687 | rfkill_init_sw_state(*rfkill, !result); | ||
688 | result = rfkill_register(*rfkill); | ||
689 | if (result) { | ||
690 | rfkill_destroy(*rfkill); | ||
691 | *rfkill = NULL; | ||
692 | return result; | ||
693 | } | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static void asus_wmi_rfkill_exit(struct asus_wmi *asus) | ||
698 | { | ||
699 | asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); | ||
700 | asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); | ||
701 | asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); | ||
702 | if (asus->wlan.rfkill) { | ||
703 | rfkill_unregister(asus->wlan.rfkill); | ||
704 | rfkill_destroy(asus->wlan.rfkill); | ||
705 | asus->wlan.rfkill = NULL; | ||
706 | } | ||
707 | /* | ||
708 | * Refresh pci hotplug in case the rfkill state was changed after | ||
709 | * asus_unregister_rfkill_notifier() | ||
710 | */ | ||
711 | asus_rfkill_hotplug(asus); | ||
712 | if (asus->hotplug_slot) | ||
713 | pci_hp_deregister(asus->hotplug_slot); | ||
714 | if (asus->hotplug_workqueue) | ||
715 | destroy_workqueue(asus->hotplug_workqueue); | ||
716 | |||
717 | if (asus->bluetooth.rfkill) { | ||
718 | rfkill_unregister(asus->bluetooth.rfkill); | ||
719 | rfkill_destroy(asus->bluetooth.rfkill); | ||
720 | asus->bluetooth.rfkill = NULL; | ||
721 | } | ||
722 | if (asus->wimax.rfkill) { | ||
723 | rfkill_unregister(asus->wimax.rfkill); | ||
724 | rfkill_destroy(asus->wimax.rfkill); | ||
725 | asus->wimax.rfkill = NULL; | ||
726 | } | ||
727 | if (asus->wwan3g.rfkill) { | ||
728 | rfkill_unregister(asus->wwan3g.rfkill); | ||
729 | rfkill_destroy(asus->wwan3g.rfkill); | ||
730 | asus->wwan3g.rfkill = NULL; | ||
731 | } | ||
732 | } | ||
733 | |||
734 | static int asus_wmi_rfkill_init(struct asus_wmi *asus) | ||
735 | { | ||
736 | int result = 0; | ||
737 | |||
738 | mutex_init(&asus->hotplug_lock); | ||
739 | mutex_init(&asus->wmi_lock); | ||
740 | |||
741 | result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan", | ||
742 | RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN); | ||
743 | |||
744 | if (result && result != -ENODEV) | ||
745 | goto exit; | ||
746 | |||
747 | result = asus_new_rfkill(asus, &asus->bluetooth, | ||
748 | "asus-bluetooth", RFKILL_TYPE_BLUETOOTH, | ||
749 | ASUS_WMI_DEVID_BLUETOOTH); | ||
750 | |||
751 | if (result && result != -ENODEV) | ||
752 | goto exit; | ||
753 | |||
754 | result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax", | ||
755 | RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX); | ||
756 | |||
757 | if (result && result != -ENODEV) | ||
758 | goto exit; | ||
759 | |||
760 | result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g", | ||
761 | RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G); | ||
762 | |||
763 | if (result && result != -ENODEV) | ||
764 | goto exit; | ||
765 | |||
766 | if (!asus->driver->hotplug_wireless) | ||
767 | goto exit; | ||
768 | |||
769 | result = asus_setup_pci_hotplug(asus); | ||
770 | /* | ||
771 | * If we get -EBUSY then something else is handling the PCI hotplug - | ||
772 | * don't fail in this case | ||
773 | */ | ||
774 | if (result == -EBUSY) | ||
775 | result = 0; | ||
776 | |||
777 | asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); | ||
778 | asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); | ||
779 | asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); | ||
780 | /* | ||
781 | * Refresh pci hotplug in case the rfkill state was changed during | ||
782 | * setup. | ||
783 | */ | ||
784 | asus_rfkill_hotplug(asus); | ||
785 | |||
786 | exit: | ||
787 | if (result && result != -ENODEV) | ||
788 | asus_wmi_rfkill_exit(asus); | ||
789 | |||
790 | if (result == -ENODEV) | ||
791 | result = 0; | ||
792 | |||
793 | return result; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * Hwmon device | ||
798 | */ | ||
799 | static ssize_t asus_hwmon_pwm1(struct device *dev, | ||
800 | struct device_attribute *attr, | ||
801 | char *buf) | ||
802 | { | ||
803 | struct asus_wmi *asus = dev_get_drvdata(dev); | ||
804 | u32 value; | ||
805 | int err; | ||
806 | |||
807 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); | ||
808 | |||
809 | if (err < 0) | ||
810 | return err; | ||
811 | |||
812 | value |= 0xFF; | ||
813 | |||
814 | if (value == 1) /* Low Speed */ | ||
815 | value = 85; | ||
816 | else if (value == 2) | ||
817 | value = 170; | ||
818 | else if (value == 3) | ||
819 | value = 255; | ||
820 | else if (value != 0) { | ||
821 | pr_err("Unknown fan speed %#x", value); | ||
822 | value = -1; | ||
823 | } | ||
824 | |||
825 | return sprintf(buf, "%d\n", value); | ||
826 | } | ||
827 | |||
828 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); | ||
829 | |||
830 | static ssize_t | ||
831 | show_name(struct device *dev, struct device_attribute *attr, char *buf) | ||
832 | { | ||
833 | return sprintf(buf, "asus\n"); | ||
834 | } | ||
835 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); | ||
836 | |||
837 | static struct attribute *hwmon_attributes[] = { | ||
838 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
839 | &sensor_dev_attr_name.dev_attr.attr, | ||
840 | NULL | ||
841 | }; | ||
842 | |||
843 | static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, | ||
844 | struct attribute *attr, int idx) | ||
845 | { | ||
846 | struct device *dev = container_of(kobj, struct device, kobj); | ||
847 | struct platform_device *pdev = to_platform_device(dev->parent); | ||
848 | struct asus_wmi *asus = platform_get_drvdata(pdev); | ||
849 | bool ok = true; | ||
850 | int dev_id = -1; | ||
851 | u32 value = ASUS_WMI_UNSUPPORTED_METHOD; | ||
852 | |||
853 | if (attr == &sensor_dev_attr_pwm1.dev_attr.attr) | ||
854 | dev_id = ASUS_WMI_DEVID_FAN_CTRL; | ||
855 | |||
856 | if (dev_id != -1) { | ||
857 | int err = asus_wmi_get_devstate(asus, dev_id, &value); | ||
858 | |||
859 | if (err < 0) | ||
860 | return err; | ||
861 | } | ||
862 | |||
863 | if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) { | ||
864 | /* | ||
865 | * We need to find a better way, probably using sfun, | ||
866 | * bits or spec ... | ||
867 | * Currently we disable it if: | ||
868 | * - ASUS_WMI_UNSUPPORTED_METHOD is returned | ||
869 | * - reverved bits are non-zero | ||
870 | * - sfun and presence bit are not set | ||
871 | */ | ||
872 | if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 | ||
873 | || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) | ||
874 | ok = false; | ||
875 | } | ||
876 | |||
877 | return ok ? attr->mode : 0; | ||
878 | } | ||
879 | |||
880 | static struct attribute_group hwmon_attribute_group = { | ||
881 | .is_visible = asus_hwmon_sysfs_is_visible, | ||
882 | .attrs = hwmon_attributes | ||
883 | }; | ||
884 | |||
885 | static void asus_wmi_hwmon_exit(struct asus_wmi *asus) | ||
886 | { | ||
887 | struct device *hwmon; | ||
888 | |||
889 | hwmon = asus->hwmon_device; | ||
890 | if (!hwmon) | ||
891 | return; | ||
892 | sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group); | ||
893 | hwmon_device_unregister(hwmon); | ||
894 | asus->hwmon_device = NULL; | ||
895 | } | ||
896 | |||
897 | static int asus_wmi_hwmon_init(struct asus_wmi *asus) | ||
898 | { | ||
899 | struct device *hwmon; | ||
900 | int result; | ||
901 | |||
902 | hwmon = hwmon_device_register(&asus->platform_device->dev); | ||
903 | if (IS_ERR(hwmon)) { | ||
904 | pr_err("Could not register asus hwmon device\n"); | ||
905 | return PTR_ERR(hwmon); | ||
906 | } | ||
907 | asus->hwmon_device = hwmon; | ||
908 | result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group); | ||
909 | if (result) | ||
910 | asus_wmi_hwmon_exit(asus); | ||
911 | return result; | ||
912 | } | ||
913 | |||
914 | /* | ||
915 | * Backlight | ||
916 | */ | ||
917 | static int read_backlight_power(struct asus_wmi *asus) | ||
918 | { | ||
919 | int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT); | ||
920 | |||
921 | if (ret < 0) | ||
922 | return ret; | ||
923 | |||
924 | return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | ||
925 | } | ||
926 | |||
927 | static int read_brightness_max(struct asus_wmi *asus) | ||
928 | { | ||
929 | u32 retval; | ||
930 | int err; | ||
931 | |||
932 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); | ||
933 | |||
934 | if (err < 0) | ||
935 | return err; | ||
936 | |||
937 | retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK; | ||
938 | retval >>= 8; | ||
939 | |||
940 | if (!retval) | ||
941 | return -ENODEV; | ||
942 | |||
943 | return retval; | ||
944 | } | ||
945 | |||
946 | static int read_brightness(struct backlight_device *bd) | ||
947 | { | ||
948 | struct asus_wmi *asus = bl_get_data(bd); | ||
949 | u32 retval; | ||
950 | int err; | ||
951 | |||
952 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); | ||
953 | |||
954 | if (err < 0) | ||
955 | return err; | ||
956 | |||
957 | return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; | ||
958 | } | ||
959 | |||
960 | static int update_bl_status(struct backlight_device *bd) | ||
961 | { | ||
962 | struct asus_wmi *asus = bl_get_data(bd); | ||
963 | u32 ctrl_param; | ||
964 | int power, err; | ||
965 | |||
966 | ctrl_param = bd->props.brightness; | ||
967 | |||
968 | err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, | ||
969 | ctrl_param, NULL); | ||
970 | |||
971 | if (err < 0) | ||
972 | return err; | ||
973 | |||
974 | power = read_backlight_power(asus); | ||
975 | if (power != -ENODEV && bd->props.power != power) { | ||
976 | ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); | ||
977 | err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, | ||
978 | ctrl_param, NULL); | ||
979 | } | ||
980 | return err; | ||
981 | } | ||
982 | |||
983 | static const struct backlight_ops asus_wmi_bl_ops = { | ||
984 | .get_brightness = read_brightness, | ||
985 | .update_status = update_bl_status, | ||
986 | }; | ||
987 | |||
988 | static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code) | ||
989 | { | ||
990 | struct backlight_device *bd = asus->backlight_device; | ||
991 | int old = bd->props.brightness; | ||
992 | int new = old; | ||
993 | |||
994 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
995 | new = code - NOTIFY_BRNUP_MIN + 1; | ||
996 | else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) | ||
997 | new = code - NOTIFY_BRNDOWN_MIN; | ||
998 | |||
999 | bd->props.brightness = new; | ||
1000 | backlight_update_status(bd); | ||
1001 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); | ||
1002 | |||
1003 | return old; | ||
1004 | } | ||
1005 | |||
1006 | static int asus_wmi_backlight_init(struct asus_wmi *asus) | ||
1007 | { | ||
1008 | struct backlight_device *bd; | ||
1009 | struct backlight_properties props; | ||
1010 | int max; | ||
1011 | int power; | ||
1012 | |||
1013 | max = read_brightness_max(asus); | ||
1014 | |||
1015 | if (max == -ENODEV) | ||
1016 | max = 0; | ||
1017 | else if (max < 0) | ||
1018 | return max; | ||
1019 | |||
1020 | power = read_backlight_power(asus); | ||
1021 | |||
1022 | if (power == -ENODEV) | ||
1023 | power = FB_BLANK_UNBLANK; | ||
1024 | else if (power < 0) | ||
1025 | return power; | ||
1026 | |||
1027 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
1028 | props.max_brightness = max; | ||
1029 | bd = backlight_device_register(asus->driver->name, | ||
1030 | &asus->platform_device->dev, asus, | ||
1031 | &asus_wmi_bl_ops, &props); | ||
1032 | if (IS_ERR(bd)) { | ||
1033 | pr_err("Could not register backlight device\n"); | ||
1034 | return PTR_ERR(bd); | ||
1035 | } | ||
1036 | |||
1037 | asus->backlight_device = bd; | ||
1038 | |||
1039 | bd->props.brightness = read_brightness(bd); | ||
1040 | bd->props.power = power; | ||
1041 | backlight_update_status(bd); | ||
1042 | |||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | static void asus_wmi_backlight_exit(struct asus_wmi *asus) | ||
1047 | { | ||
1048 | if (asus->backlight_device) | ||
1049 | backlight_device_unregister(asus->backlight_device); | ||
1050 | |||
1051 | asus->backlight_device = NULL; | ||
1052 | } | ||
1053 | |||
1054 | static void asus_wmi_notify(u32 value, void *context) | ||
1055 | { | ||
1056 | struct asus_wmi *asus = context; | ||
1057 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1058 | union acpi_object *obj; | ||
1059 | acpi_status status; | ||
1060 | int code; | ||
1061 | int orig_code; | ||
1062 | |||
1063 | status = wmi_get_event_data(value, &response); | ||
1064 | if (status != AE_OK) { | ||
1065 | pr_err("bad event status 0x%x\n", status); | ||
1066 | return; | ||
1067 | } | ||
1068 | |||
1069 | obj = (union acpi_object *)response.pointer; | ||
1070 | |||
1071 | if (!obj || obj->type != ACPI_TYPE_INTEGER) | ||
1072 | goto exit; | ||
1073 | |||
1074 | code = obj->integer.value; | ||
1075 | orig_code = code; | ||
1076 | |||
1077 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
1078 | code = NOTIFY_BRNUP_MIN; | ||
1079 | else if (code >= NOTIFY_BRNDOWN_MIN && | ||
1080 | code <= NOTIFY_BRNDOWN_MAX) | ||
1081 | code = NOTIFY_BRNDOWN_MIN; | ||
1082 | |||
1083 | if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { | ||
1084 | if (!acpi_video_backlight_support()) | ||
1085 | asus_wmi_backlight_notify(asus, orig_code); | ||
1086 | } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) | ||
1087 | pr_info("Unknown key %x pressed\n", code); | ||
1088 | |||
1089 | exit: | ||
1090 | kfree(obj); | ||
1091 | } | ||
1092 | |||
1093 | /* | ||
1094 | * Sys helpers | ||
1095 | */ | ||
1096 | static int parse_arg(const char *buf, unsigned long count, int *val) | ||
1097 | { | ||
1098 | if (!count) | ||
1099 | return 0; | ||
1100 | if (sscanf(buf, "%i", val) != 1) | ||
1101 | return -EINVAL; | ||
1102 | return count; | ||
1103 | } | ||
1104 | |||
1105 | static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, | ||
1106 | const char *buf, size_t count) | ||
1107 | { | ||
1108 | u32 retval; | ||
1109 | int rv, err, value; | ||
1110 | |||
1111 | value = asus_wmi_get_devstate_simple(asus, devid); | ||
1112 | if (value == -ENODEV) /* Check device presence */ | ||
1113 | return value; | ||
1114 | |||
1115 | rv = parse_arg(buf, count, &value); | ||
1116 | err = asus_wmi_set_devstate(devid, value, &retval); | ||
1117 | |||
1118 | if (err < 0) | ||
1119 | return err; | ||
1120 | |||
1121 | return rv; | ||
1122 | } | ||
1123 | |||
1124 | static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) | ||
1125 | { | ||
1126 | int value = asus_wmi_get_devstate_simple(asus, devid); | ||
1127 | |||
1128 | if (value < 0) | ||
1129 | return value; | ||
1130 | |||
1131 | return sprintf(buf, "%d\n", value); | ||
1132 | } | ||
1133 | |||
1134 | #define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ | ||
1135 | static ssize_t show_##_name(struct device *dev, \ | ||
1136 | struct device_attribute *attr, \ | ||
1137 | char *buf) \ | ||
1138 | { \ | ||
1139 | struct asus_wmi *asus = dev_get_drvdata(dev); \ | ||
1140 | \ | ||
1141 | return show_sys_wmi(asus, _cm, buf); \ | ||
1142 | } \ | ||
1143 | static ssize_t store_##_name(struct device *dev, \ | ||
1144 | struct device_attribute *attr, \ | ||
1145 | const char *buf, size_t count) \ | ||
1146 | { \ | ||
1147 | struct asus_wmi *asus = dev_get_drvdata(dev); \ | ||
1148 | \ | ||
1149 | return store_sys_wmi(asus, _cm, buf, count); \ | ||
1150 | } \ | ||
1151 | static struct device_attribute dev_attr_##_name = { \ | ||
1152 | .attr = { \ | ||
1153 | .name = __stringify(_name), \ | ||
1154 | .mode = _mode }, \ | ||
1155 | .show = show_##_name, \ | ||
1156 | .store = store_##_name, \ | ||
1157 | } | ||
1158 | |||
1159 | ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); | ||
1160 | ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); | ||
1161 | ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); | ||
1162 | |||
1163 | static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, | ||
1164 | const char *buf, size_t count) | ||
1165 | { | ||
1166 | int value; | ||
1167 | |||
1168 | if (!count || sscanf(buf, "%i", &value) != 1) | ||
1169 | return -EINVAL; | ||
1170 | if (value < 0 || value > 2) | ||
1171 | return -EINVAL; | ||
1172 | |||
1173 | return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); | ||
1174 | } | ||
1175 | |||
1176 | static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); | ||
1177 | |||
1178 | static struct attribute *platform_attributes[] = { | ||
1179 | &dev_attr_cpufv.attr, | ||
1180 | &dev_attr_camera.attr, | ||
1181 | &dev_attr_cardr.attr, | ||
1182 | &dev_attr_touchpad.attr, | ||
1183 | NULL | ||
1184 | }; | ||
1185 | |||
1186 | static mode_t asus_sysfs_is_visible(struct kobject *kobj, | ||
1187 | struct attribute *attr, int idx) | ||
1188 | { | ||
1189 | struct device *dev = container_of(kobj, struct device, kobj); | ||
1190 | struct platform_device *pdev = to_platform_device(dev); | ||
1191 | struct asus_wmi *asus = platform_get_drvdata(pdev); | ||
1192 | bool ok = true; | ||
1193 | int devid = -1; | ||
1194 | |||
1195 | if (attr == &dev_attr_camera.attr) | ||
1196 | devid = ASUS_WMI_DEVID_CAMERA; | ||
1197 | else if (attr == &dev_attr_cardr.attr) | ||
1198 | devid = ASUS_WMI_DEVID_CARDREADER; | ||
1199 | else if (attr == &dev_attr_touchpad.attr) | ||
1200 | devid = ASUS_WMI_DEVID_TOUCHPAD; | ||
1201 | |||
1202 | if (devid != -1) | ||
1203 | ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); | ||
1204 | |||
1205 | return ok ? attr->mode : 0; | ||
1206 | } | ||
1207 | |||
1208 | static struct attribute_group platform_attribute_group = { | ||
1209 | .is_visible = asus_sysfs_is_visible, | ||
1210 | .attrs = platform_attributes | ||
1211 | }; | ||
1212 | |||
1213 | static void asus_wmi_sysfs_exit(struct platform_device *device) | ||
1214 | { | ||
1215 | sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); | ||
1216 | } | ||
1217 | |||
1218 | static int asus_wmi_sysfs_init(struct platform_device *device) | ||
1219 | { | ||
1220 | return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); | ||
1221 | } | ||
1222 | |||
1223 | /* | ||
1224 | * Platform device | ||
1225 | */ | ||
1226 | static int __init asus_wmi_platform_init(struct asus_wmi *asus) | ||
1227 | { | ||
1228 | int rv; | ||
1229 | |||
1230 | /* INIT enable hotkeys on some models */ | ||
1231 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv)) | ||
1232 | pr_info("Initialization: %#x", rv); | ||
1233 | |||
1234 | /* We don't know yet what to do with this version... */ | ||
1235 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { | ||
1236 | pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF); | ||
1237 | asus->spec = rv; | ||
1238 | } | ||
1239 | |||
1240 | /* | ||
1241 | * The SFUN method probably allows the original driver to get the list | ||
1242 | * of features supported by a given model. For now, 0x0100 or 0x0800 | ||
1243 | * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. | ||
1244 | * The significance of others is yet to be found. | ||
1245 | */ | ||
1246 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) { | ||
1247 | pr_info("SFUN value: %#x", rv); | ||
1248 | asus->sfun = rv; | ||
1249 | } | ||
1250 | |||
1251 | /* | ||
1252 | * Eee PC and Notebooks seems to have different method_id for DSTS, | ||
1253 | * but it may also be related to the BIOS's SPEC. | ||
1254 | * Note, on most Eeepc, there is no way to check if a method exist | ||
1255 | * or note, while on notebooks, they returns 0xFFFFFFFE on failure, | ||
1256 | * but once again, SPEC may probably be used for that kind of things. | ||
1257 | */ | ||
1258 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) | ||
1259 | asus->dsts_id = ASUS_WMI_METHODID_DSTS; | ||
1260 | else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL)) | ||
1261 | asus->dsts_id = ASUS_WMI_METHODID_DSTS2; | ||
1262 | |||
1263 | if (!asus->dsts_id) { | ||
1264 | pr_err("Can't find DSTS"); | ||
1265 | return -ENODEV; | ||
1266 | } | ||
1267 | |||
1268 | return asus_wmi_sysfs_init(asus->platform_device); | ||
1269 | } | ||
1270 | |||
1271 | static void asus_wmi_platform_exit(struct asus_wmi *asus) | ||
1272 | { | ||
1273 | asus_wmi_sysfs_exit(asus->platform_device); | ||
1274 | } | ||
1275 | |||
1276 | /* | ||
1277 | * debugfs | ||
1278 | */ | ||
1279 | struct asus_wmi_debugfs_node { | ||
1280 | struct asus_wmi *asus; | ||
1281 | char *name; | ||
1282 | int (*show) (struct seq_file *m, void *data); | ||
1283 | }; | ||
1284 | |||
1285 | static int show_dsts(struct seq_file *m, void *data) | ||
1286 | { | ||
1287 | struct asus_wmi *asus = m->private; | ||
1288 | int err; | ||
1289 | u32 retval = -1; | ||
1290 | |||
1291 | err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); | ||
1292 | |||
1293 | if (err < 0) | ||
1294 | return err; | ||
1295 | |||
1296 | seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval); | ||
1297 | |||
1298 | return 0; | ||
1299 | } | ||
1300 | |||
1301 | static int show_devs(struct seq_file *m, void *data) | ||
1302 | { | ||
1303 | struct asus_wmi *asus = m->private; | ||
1304 | int err; | ||
1305 | u32 retval = -1; | ||
1306 | |||
1307 | err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, | ||
1308 | &retval); | ||
1309 | |||
1310 | if (err < 0) | ||
1311 | return err; | ||
1312 | |||
1313 | seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id, | ||
1314 | asus->debug.ctrl_param, retval); | ||
1315 | |||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static int show_call(struct seq_file *m, void *data) | ||
1320 | { | ||
1321 | struct asus_wmi *asus = m->private; | ||
1322 | struct bios_args args = { | ||
1323 | .arg0 = asus->debug.dev_id, | ||
1324 | .arg1 = asus->debug.ctrl_param, | ||
1325 | }; | ||
1326 | struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; | ||
1327 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1328 | union acpi_object *obj; | ||
1329 | acpi_status status; | ||
1330 | |||
1331 | status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, | ||
1332 | 1, asus->debug.method_id, | ||
1333 | &input, &output); | ||
1334 | |||
1335 | if (ACPI_FAILURE(status)) | ||
1336 | return -EIO; | ||
1337 | |||
1338 | obj = (union acpi_object *)output.pointer; | ||
1339 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
1340 | seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id, | ||
1341 | asus->debug.dev_id, asus->debug.ctrl_param, | ||
1342 | (u32) obj->integer.value); | ||
1343 | else | ||
1344 | seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id, | ||
1345 | asus->debug.dev_id, asus->debug.ctrl_param, | ||
1346 | obj ? obj->type : -1); | ||
1347 | |||
1348 | kfree(obj); | ||
1349 | |||
1350 | return 0; | ||
1351 | } | ||
1352 | |||
1353 | static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = { | ||
1354 | {NULL, "devs", show_devs}, | ||
1355 | {NULL, "dsts", show_dsts}, | ||
1356 | {NULL, "call", show_call}, | ||
1357 | }; | ||
1358 | |||
1359 | static int asus_wmi_debugfs_open(struct inode *inode, struct file *file) | ||
1360 | { | ||
1361 | struct asus_wmi_debugfs_node *node = inode->i_private; | ||
1362 | |||
1363 | return single_open(file, node->show, node->asus); | ||
1364 | } | ||
1365 | |||
1366 | static const struct file_operations asus_wmi_debugfs_io_ops = { | ||
1367 | .owner = THIS_MODULE, | ||
1368 | .open = asus_wmi_debugfs_open, | ||
1369 | .read = seq_read, | ||
1370 | .llseek = seq_lseek, | ||
1371 | .release = single_release, | ||
1372 | }; | ||
1373 | |||
1374 | static void asus_wmi_debugfs_exit(struct asus_wmi *asus) | ||
1375 | { | ||
1376 | debugfs_remove_recursive(asus->debug.root); | ||
1377 | } | ||
1378 | |||
1379 | static int asus_wmi_debugfs_init(struct asus_wmi *asus) | ||
1380 | { | ||
1381 | struct dentry *dent; | ||
1382 | int i; | ||
1383 | |||
1384 | asus->debug.root = debugfs_create_dir(asus->driver->name, NULL); | ||
1385 | if (!asus->debug.root) { | ||
1386 | pr_err("failed to create debugfs directory"); | ||
1387 | goto error_debugfs; | ||
1388 | } | ||
1389 | |||
1390 | dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, | ||
1391 | asus->debug.root, &asus->debug.method_id); | ||
1392 | if (!dent) | ||
1393 | goto error_debugfs; | ||
1394 | |||
1395 | dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, | ||
1396 | asus->debug.root, &asus->debug.dev_id); | ||
1397 | if (!dent) | ||
1398 | goto error_debugfs; | ||
1399 | |||
1400 | dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, | ||
1401 | asus->debug.root, &asus->debug.ctrl_param); | ||
1402 | if (!dent) | ||
1403 | goto error_debugfs; | ||
1404 | |||
1405 | for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) { | ||
1406 | struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i]; | ||
1407 | |||
1408 | node->asus = asus; | ||
1409 | dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, | ||
1410 | asus->debug.root, node, | ||
1411 | &asus_wmi_debugfs_io_ops); | ||
1412 | if (!dent) { | ||
1413 | pr_err("failed to create debug file: %s\n", node->name); | ||
1414 | goto error_debugfs; | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1418 | return 0; | ||
1419 | |||
1420 | error_debugfs: | ||
1421 | asus_wmi_debugfs_exit(asus); | ||
1422 | return -ENOMEM; | ||
1423 | } | ||
1424 | |||
1425 | /* | ||
1426 | * WMI Driver | ||
1427 | */ | ||
1428 | static int asus_wmi_add(struct platform_device *pdev) | ||
1429 | { | ||
1430 | struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); | ||
1431 | struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); | ||
1432 | struct asus_wmi *asus; | ||
1433 | acpi_status status; | ||
1434 | int err; | ||
1435 | |||
1436 | asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL); | ||
1437 | if (!asus) | ||
1438 | return -ENOMEM; | ||
1439 | |||
1440 | asus->driver = wdrv; | ||
1441 | asus->platform_device = pdev; | ||
1442 | wdrv->platform_device = pdev; | ||
1443 | platform_set_drvdata(asus->platform_device, asus); | ||
1444 | |||
1445 | if (wdrv->quirks) | ||
1446 | wdrv->quirks(asus->driver); | ||
1447 | |||
1448 | err = asus_wmi_platform_init(asus); | ||
1449 | if (err) | ||
1450 | goto fail_platform; | ||
1451 | |||
1452 | err = asus_wmi_input_init(asus); | ||
1453 | if (err) | ||
1454 | goto fail_input; | ||
1455 | |||
1456 | err = asus_wmi_hwmon_init(asus); | ||
1457 | if (err) | ||
1458 | goto fail_hwmon; | ||
1459 | |||
1460 | err = asus_wmi_led_init(asus); | ||
1461 | if (err) | ||
1462 | goto fail_leds; | ||
1463 | |||
1464 | err = asus_wmi_rfkill_init(asus); | ||
1465 | if (err) | ||
1466 | goto fail_rfkill; | ||
1467 | |||
1468 | if (!acpi_video_backlight_support()) { | ||
1469 | err = asus_wmi_backlight_init(asus); | ||
1470 | if (err && err != -ENODEV) | ||
1471 | goto fail_backlight; | ||
1472 | } else | ||
1473 | pr_info("Backlight controlled by ACPI video driver\n"); | ||
1474 | |||
1475 | status = wmi_install_notify_handler(asus->driver->event_guid, | ||
1476 | asus_wmi_notify, asus); | ||
1477 | if (ACPI_FAILURE(status)) { | ||
1478 | pr_err("Unable to register notify handler - %d\n", status); | ||
1479 | err = -ENODEV; | ||
1480 | goto fail_wmi_handler; | ||
1481 | } | ||
1482 | |||
1483 | err = asus_wmi_debugfs_init(asus); | ||
1484 | if (err) | ||
1485 | goto fail_debugfs; | ||
1486 | |||
1487 | return 0; | ||
1488 | |||
1489 | fail_debugfs: | ||
1490 | wmi_remove_notify_handler(asus->driver->event_guid); | ||
1491 | fail_wmi_handler: | ||
1492 | asus_wmi_backlight_exit(asus); | ||
1493 | fail_backlight: | ||
1494 | asus_wmi_rfkill_exit(asus); | ||
1495 | fail_rfkill: | ||
1496 | asus_wmi_led_exit(asus); | ||
1497 | fail_leds: | ||
1498 | asus_wmi_hwmon_exit(asus); | ||
1499 | fail_hwmon: | ||
1500 | asus_wmi_input_exit(asus); | ||
1501 | fail_input: | ||
1502 | asus_wmi_platform_exit(asus); | ||
1503 | fail_platform: | ||
1504 | kfree(asus); | ||
1505 | return err; | ||
1506 | } | ||
1507 | |||
1508 | static int asus_wmi_remove(struct platform_device *device) | ||
1509 | { | ||
1510 | struct asus_wmi *asus; | ||
1511 | |||
1512 | asus = platform_get_drvdata(device); | ||
1513 | wmi_remove_notify_handler(asus->driver->event_guid); | ||
1514 | asus_wmi_backlight_exit(asus); | ||
1515 | asus_wmi_input_exit(asus); | ||
1516 | asus_wmi_hwmon_exit(asus); | ||
1517 | asus_wmi_led_exit(asus); | ||
1518 | asus_wmi_rfkill_exit(asus); | ||
1519 | asus_wmi_debugfs_exit(asus); | ||
1520 | asus_wmi_platform_exit(asus); | ||
1521 | |||
1522 | kfree(asus); | ||
1523 | return 0; | ||
1524 | } | ||
1525 | |||
1526 | /* | ||
1527 | * Platform driver - hibernate/resume callbacks | ||
1528 | */ | ||
1529 | static int asus_hotk_thaw(struct device *device) | ||
1530 | { | ||
1531 | struct asus_wmi *asus = dev_get_drvdata(device); | ||
1532 | |||
1533 | if (asus->wlan.rfkill) { | ||
1534 | bool wlan; | ||
1535 | |||
1536 | /* | ||
1537 | * Work around bios bug - acpi _PTS turns off the wireless led | ||
1538 | * during suspend. Normally it restores it on resume, but | ||
1539 | * we should kick it ourselves in case hibernation is aborted. | ||
1540 | */ | ||
1541 | wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); | ||
1542 | asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); | ||
1543 | } | ||
1544 | |||
1545 | return 0; | ||
1546 | } | ||
1547 | |||
1548 | static int asus_hotk_restore(struct device *device) | ||
1549 | { | ||
1550 | struct asus_wmi *asus = dev_get_drvdata(device); | ||
1551 | int bl; | ||
1552 | |||
1553 | /* Refresh both wlan rfkill state and pci hotplug */ | ||
1554 | if (asus->wlan.rfkill) | ||
1555 | asus_rfkill_hotplug(asus); | ||
1556 | |||
1557 | if (asus->bluetooth.rfkill) { | ||
1558 | bl = !asus_wmi_get_devstate_simple(asus, | ||
1559 | ASUS_WMI_DEVID_BLUETOOTH); | ||
1560 | rfkill_set_sw_state(asus->bluetooth.rfkill, bl); | ||
1561 | } | ||
1562 | if (asus->wimax.rfkill) { | ||
1563 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX); | ||
1564 | rfkill_set_sw_state(asus->wimax.rfkill, bl); | ||
1565 | } | ||
1566 | if (asus->wwan3g.rfkill) { | ||
1567 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); | ||
1568 | rfkill_set_sw_state(asus->wwan3g.rfkill, bl); | ||
1569 | } | ||
1570 | |||
1571 | return 0; | ||
1572 | } | ||
1573 | |||
1574 | static const struct dev_pm_ops asus_pm_ops = { | ||
1575 | .thaw = asus_hotk_thaw, | ||
1576 | .restore = asus_hotk_restore, | ||
1577 | }; | ||
1578 | |||
1579 | static int asus_wmi_probe(struct platform_device *pdev) | ||
1580 | { | ||
1581 | struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); | ||
1582 | struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); | ||
1583 | int ret; | ||
1584 | |||
1585 | if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { | ||
1586 | pr_warning("Management GUID not found\n"); | ||
1587 | return -ENODEV; | ||
1588 | } | ||
1589 | |||
1590 | if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) { | ||
1591 | pr_warning("Event GUID not found\n"); | ||
1592 | return -ENODEV; | ||
1593 | } | ||
1594 | |||
1595 | if (wdrv->probe) { | ||
1596 | ret = wdrv->probe(pdev); | ||
1597 | if (ret) | ||
1598 | return ret; | ||
1599 | } | ||
1600 | |||
1601 | return asus_wmi_add(pdev); | ||
1602 | } | ||
1603 | |||
1604 | static bool used; | ||
1605 | |||
1606 | int asus_wmi_register_driver(struct asus_wmi_driver *driver) | ||
1607 | { | ||
1608 | struct platform_driver *platform_driver; | ||
1609 | struct platform_device *platform_device; | ||
1610 | |||
1611 | if (used) | ||
1612 | return -EBUSY; | ||
1613 | |||
1614 | platform_driver = &driver->platform_driver; | ||
1615 | platform_driver->remove = asus_wmi_remove; | ||
1616 | platform_driver->driver.owner = driver->owner; | ||
1617 | platform_driver->driver.name = driver->name; | ||
1618 | platform_driver->driver.pm = &asus_pm_ops; | ||
1619 | |||
1620 | platform_device = platform_create_bundle(platform_driver, | ||
1621 | asus_wmi_probe, | ||
1622 | NULL, 0, NULL, 0); | ||
1623 | if (IS_ERR(platform_device)) | ||
1624 | return PTR_ERR(platform_device); | ||
1625 | |||
1626 | used = true; | ||
1627 | return 0; | ||
1628 | } | ||
1629 | EXPORT_SYMBOL_GPL(asus_wmi_register_driver); | ||
1630 | |||
1631 | void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) | ||
1632 | { | ||
1633 | platform_device_unregister(driver->platform_device); | ||
1634 | platform_driver_unregister(&driver->platform_driver); | ||
1635 | used = false; | ||
1636 | } | ||
1637 | EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver); | ||
1638 | |||
1639 | static int __init asus_wmi_init(void) | ||
1640 | { | ||
1641 | if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { | ||
1642 | pr_info("Asus Management GUID not found"); | ||
1643 | return -ENODEV; | ||
1644 | } | ||
1645 | |||
1646 | pr_info("ASUS WMI generic driver loaded"); | ||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | static void __exit asus_wmi_exit(void) | ||
1651 | { | ||
1652 | pr_info("ASUS WMI generic driver unloaded"); | ||
1653 | } | ||
1654 | |||
1655 | module_init(asus_wmi_init); | ||
1656 | module_exit(asus_wmi_exit); | ||
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h new file mode 100644 index 000000000000..c044522c8766 --- /dev/null +++ b/drivers/platform/x86/asus-wmi.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Asus PC WMI hotkey driver | ||
3 | * | ||
4 | * Copyright(C) 2010 Intel Corporation. | ||
5 | * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> | ||
6 | * | ||
7 | * Portions based on wistron_btns.c: | ||
8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | ||
9 | * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> | ||
10 | * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #ifndef _ASUS_WMI_H_ | ||
28 | #define _ASUS_WMI_H_ | ||
29 | |||
30 | #include <linux/platform_device.h> | ||
31 | |||
32 | struct module; | ||
33 | struct key_entry; | ||
34 | struct asus_wmi; | ||
35 | |||
36 | struct asus_wmi_driver { | ||
37 | bool hotplug_wireless; | ||
38 | |||
39 | const char *name; | ||
40 | struct module *owner; | ||
41 | |||
42 | const char *event_guid; | ||
43 | |||
44 | const struct key_entry *keymap; | ||
45 | const char *input_name; | ||
46 | const char *input_phys; | ||
47 | |||
48 | int (*probe) (struct platform_device *device); | ||
49 | void (*quirks) (struct asus_wmi_driver *driver); | ||
50 | |||
51 | struct platform_driver platform_driver; | ||
52 | struct platform_device *platform_device; | ||
53 | }; | ||
54 | |||
55 | int asus_wmi_register_driver(struct asus_wmi_driver *driver); | ||
56 | void asus_wmi_unregister_driver(struct asus_wmi_driver *driver); | ||
57 | |||
58 | #endif /* !_ASUS_WMI_H_ */ | ||
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index eb95878fa583..c16a27641ced 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c | |||
@@ -201,7 +201,7 @@ static bool extra_features; | |||
201 | * into 0x4F and read a few bytes from the output, like so: | 201 | * into 0x4F and read a few bytes from the output, like so: |
202 | * u8 writeData = 0x33; | 202 | * u8 writeData = 0x33; |
203 | * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); | 203 | * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); |
204 | * That address is labled "fan1 table information" in the service manual. | 204 | * That address is labelled "fan1 table information" in the service manual. |
205 | * It should be clear which value in 'buffer' changes). This seems to be | 205 | * It should be clear which value in 'buffer' changes). This seems to be |
206 | * related to fan speed. It isn't a proper 'realtime' fan speed value | 206 | * related to fan speed. It isn't a proper 'realtime' fan speed value |
207 | * though, because physically stopping or speeding up the fan doesn't | 207 | * though, because physically stopping or speeding up the fan doesn't |
@@ -275,7 +275,7 @@ static int set_backlight_level(int level) | |||
275 | 275 | ||
276 | ec_write(BACKLIGHT_LEVEL_ADDR, level); | 276 | ec_write(BACKLIGHT_LEVEL_ADDR, level); |
277 | 277 | ||
278 | return 1; | 278 | return 0; |
279 | } | 279 | } |
280 | 280 | ||
281 | static int get_backlight_level(void) | 281 | static int get_backlight_level(void) |
@@ -763,7 +763,7 @@ static int dmi_check_cb(const struct dmi_system_id *id) | |||
763 | printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", | 763 | printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", |
764 | id->ident); | 764 | id->ident); |
765 | extra_features = false; | 765 | extra_features = false; |
766 | return 0; | 766 | return 1; |
767 | } | 767 | } |
768 | 768 | ||
769 | static int dmi_check_cb_extra(const struct dmi_system_id *id) | 769 | static int dmi_check_cb_extra(const struct dmi_system_id *id) |
@@ -772,7 +772,7 @@ static int dmi_check_cb_extra(const struct dmi_system_id *id) | |||
772 | "enabling extra features\n", | 772 | "enabling extra features\n", |
773 | id->ident); | 773 | id->ident); |
774 | extra_features = true; | 774 | extra_features = true; |
775 | return 0; | 775 | return 1; |
776 | } | 776 | } |
777 | 777 | ||
778 | static struct dmi_system_id __initdata compal_dmi_table[] = { | 778 | static struct dmi_system_id __initdata compal_dmi_table[] = { |
diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c new file mode 100644 index 000000000000..0ed84573ae1f --- /dev/null +++ b/drivers/platform/x86/dell-wmi-aio.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * WMI hotkeys support for Dell All-In-One series | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/input.h> | ||
25 | #include <linux/input/sparse-keymap.h> | ||
26 | #include <acpi/acpi_drivers.h> | ||
27 | #include <linux/acpi.h> | ||
28 | #include <linux/string.h> | ||
29 | |||
30 | MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | #define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4" | ||
34 | #define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8" | ||
35 | |||
36 | static const char *dell_wmi_aio_guids[] = { | ||
37 | EVENT_GUID1, | ||
38 | EVENT_GUID2, | ||
39 | NULL | ||
40 | }; | ||
41 | |||
42 | MODULE_ALIAS("wmi:"EVENT_GUID1); | ||
43 | MODULE_ALIAS("wmi:"EVENT_GUID2); | ||
44 | |||
45 | static const struct key_entry dell_wmi_aio_keymap[] = { | ||
46 | { KE_KEY, 0xc0, { KEY_VOLUMEUP } }, | ||
47 | { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } }, | ||
48 | { KE_END, 0 } | ||
49 | }; | ||
50 | |||
51 | static struct input_dev *dell_wmi_aio_input_dev; | ||
52 | |||
53 | static void dell_wmi_aio_notify(u32 value, void *context) | ||
54 | { | ||
55 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
56 | union acpi_object *obj; | ||
57 | acpi_status status; | ||
58 | |||
59 | status = wmi_get_event_data(value, &response); | ||
60 | if (status != AE_OK) { | ||
61 | pr_info("bad event status 0x%x\n", status); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | obj = (union acpi_object *)response.pointer; | ||
66 | if (obj) { | ||
67 | unsigned int scancode; | ||
68 | |||
69 | switch (obj->type) { | ||
70 | case ACPI_TYPE_INTEGER: | ||
71 | /* Most All-In-One correctly return integer scancode */ | ||
72 | scancode = obj->integer.value; | ||
73 | sparse_keymap_report_event(dell_wmi_aio_input_dev, | ||
74 | scancode, 1, true); | ||
75 | break; | ||
76 | case ACPI_TYPE_BUFFER: | ||
77 | /* Broken machines return the scancode in a buffer */ | ||
78 | if (obj->buffer.pointer && obj->buffer.length > 0) { | ||
79 | scancode = obj->buffer.pointer[0]; | ||
80 | sparse_keymap_report_event( | ||
81 | dell_wmi_aio_input_dev, | ||
82 | scancode, 1, true); | ||
83 | } | ||
84 | break; | ||
85 | } | ||
86 | } | ||
87 | kfree(obj); | ||
88 | } | ||
89 | |||
90 | static int __init dell_wmi_aio_input_setup(void) | ||
91 | { | ||
92 | int err; | ||
93 | |||
94 | dell_wmi_aio_input_dev = input_allocate_device(); | ||
95 | |||
96 | if (!dell_wmi_aio_input_dev) | ||
97 | return -ENOMEM; | ||
98 | |||
99 | dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys"; | ||
100 | dell_wmi_aio_input_dev->phys = "wmi/input0"; | ||
101 | dell_wmi_aio_input_dev->id.bustype = BUS_HOST; | ||
102 | |||
103 | err = sparse_keymap_setup(dell_wmi_aio_input_dev, | ||
104 | dell_wmi_aio_keymap, NULL); | ||
105 | if (err) { | ||
106 | pr_err("Unable to setup input device keymap\n"); | ||
107 | goto err_free_dev; | ||
108 | } | ||
109 | err = input_register_device(dell_wmi_aio_input_dev); | ||
110 | if (err) { | ||
111 | pr_info("Unable to register input device\n"); | ||
112 | goto err_free_keymap; | ||
113 | } | ||
114 | return 0; | ||
115 | |||
116 | err_free_keymap: | ||
117 | sparse_keymap_free(dell_wmi_aio_input_dev); | ||
118 | err_free_dev: | ||
119 | input_free_device(dell_wmi_aio_input_dev); | ||
120 | return err; | ||
121 | } | ||
122 | |||
123 | static const char *dell_wmi_aio_find(void) | ||
124 | { | ||
125 | int i; | ||
126 | |||
127 | for (i = 0; dell_wmi_aio_guids[i] != NULL; i++) | ||
128 | if (wmi_has_guid(dell_wmi_aio_guids[i])) | ||
129 | return dell_wmi_aio_guids[i]; | ||
130 | |||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | static int __init dell_wmi_aio_init(void) | ||
135 | { | ||
136 | int err; | ||
137 | const char *guid; | ||
138 | |||
139 | guid = dell_wmi_aio_find(); | ||
140 | if (!guid) { | ||
141 | pr_warning("No known WMI GUID found\n"); | ||
142 | return -ENXIO; | ||
143 | } | ||
144 | |||
145 | err = dell_wmi_aio_input_setup(); | ||
146 | if (err) | ||
147 | return err; | ||
148 | |||
149 | err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL); | ||
150 | if (err) { | ||
151 | pr_err("Unable to register notify handler - %d\n", err); | ||
152 | sparse_keymap_free(dell_wmi_aio_input_dev); | ||
153 | input_unregister_device(dell_wmi_aio_input_dev); | ||
154 | return err; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static void __exit dell_wmi_aio_exit(void) | ||
161 | { | ||
162 | const char *guid; | ||
163 | |||
164 | guid = dell_wmi_aio_find(); | ||
165 | wmi_remove_notify_handler(guid); | ||
166 | sparse_keymap_free(dell_wmi_aio_input_dev); | ||
167 | input_unregister_device(dell_wmi_aio_input_dev); | ||
168 | } | ||
169 | |||
170 | module_init(dell_wmi_aio_init); | ||
171 | module_exit(dell_wmi_aio_exit); | ||
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6605beac0d0e..5f2dd386152b 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
@@ -1322,7 +1322,7 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) | |||
1322 | { | 1322 | { |
1323 | int dummy; | 1323 | int dummy; |
1324 | 1324 | ||
1325 | /* Some BIOSes do not report cm although it is avaliable. | 1325 | /* Some BIOSes do not report cm although it is available. |
1326 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | 1326 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ |
1327 | if (!(eeepc->cm_supported & (1 << cm)) | 1327 | if (!(eeepc->cm_supported & (1 << cm)) |
1328 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { | 1328 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { |
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 4d38f98aa976..0ddc434fb93b 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Eee PC WMI hotkey driver | 2 | * Eee PC WMI hotkey driver |
3 | * | 3 | * |
4 | * Copyright(C) 2010 Intel Corporation. | 4 | * Copyright(C) 2010 Intel Corporation. |
5 | * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> | 5 | * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> |
6 | * | 6 | * |
7 | * Portions based on wistron_btns.c: | 7 | * Portions based on wistron_btns.c: |
8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | 8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> |
@@ -29,841 +29,57 @@ | |||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/types.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/input.h> | 32 | #include <linux/input.h> |
35 | #include <linux/input/sparse-keymap.h> | 33 | #include <linux/input/sparse-keymap.h> |
36 | #include <linux/fb.h> | 34 | #include <linux/dmi.h> |
37 | #include <linux/backlight.h> | ||
38 | #include <linux/leds.h> | ||
39 | #include <linux/rfkill.h> | ||
40 | #include <linux/debugfs.h> | ||
41 | #include <linux/seq_file.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | #include <acpi/acpi_bus.h> | 35 | #include <acpi/acpi_bus.h> |
44 | #include <acpi/acpi_drivers.h> | 36 | |
37 | #include "asus-wmi.h" | ||
45 | 38 | ||
46 | #define EEEPC_WMI_FILE "eeepc-wmi" | 39 | #define EEEPC_WMI_FILE "eeepc-wmi" |
47 | 40 | ||
48 | MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); | 41 | MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>"); |
49 | MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); | 42 | MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); |
50 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
51 | 44 | ||
52 | #define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ | 45 | #define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ |
53 | 46 | ||
54 | #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" | 47 | #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" |
55 | #define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" | ||
56 | 48 | ||
57 | MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); | 49 | MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); |
58 | MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); | ||
59 | |||
60 | #define NOTIFY_BRNUP_MIN 0x11 | ||
61 | #define NOTIFY_BRNUP_MAX 0x1f | ||
62 | #define NOTIFY_BRNDOWN_MIN 0x20 | ||
63 | #define NOTIFY_BRNDOWN_MAX 0x2e | ||
64 | 50 | ||
65 | #define EEEPC_WMI_METHODID_DEVS 0x53564544 | 51 | static bool hotplug_wireless; |
66 | #define EEEPC_WMI_METHODID_DSTS 0x53544344 | ||
67 | #define EEEPC_WMI_METHODID_CFVS 0x53564643 | ||
68 | 52 | ||
69 | #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 | 53 | module_param(hotplug_wireless, bool, 0444); |
70 | #define EEEPC_WMI_DEVID_TPDLED 0x00100011 | 54 | MODULE_PARM_DESC(hotplug_wireless, |
71 | #define EEEPC_WMI_DEVID_WLAN 0x00010011 | 55 | "Enable hotplug for wireless device. " |
72 | #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 | 56 | "If your laptop needs that, please report to " |
73 | #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 | 57 | "acpi4asus-user@lists.sourceforge.net."); |
74 | 58 | ||
75 | static const struct key_entry eeepc_wmi_keymap[] = { | 59 | static const struct key_entry eeepc_wmi_keymap[] = { |
76 | /* Sleep already handled via generic ACPI code */ | 60 | /* Sleep already handled via generic ACPI code */ |
77 | { KE_KEY, 0x5d, { KEY_WLAN } }, | ||
78 | { KE_KEY, 0x32, { KEY_MUTE } }, | ||
79 | { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, | ||
80 | { KE_KEY, 0x30, { KEY_VOLUMEUP } }, | 61 | { KE_KEY, 0x30, { KEY_VOLUMEUP } }, |
81 | { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, | 62 | { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, |
82 | { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, | 63 | { KE_KEY, 0x32, { KEY_MUTE } }, |
64 | { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ | ||
65 | { KE_KEY, 0x5d, { KEY_WLAN } }, | ||
66 | { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */ | ||
67 | { KE_KEY, 0x82, { KEY_CAMERA } }, | ||
68 | { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, | ||
69 | { KE_KEY, 0x88, { KEY_WLAN } }, | ||
83 | { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, | 70 | { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, |
84 | { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ | 71 | { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ |
85 | { KE_KEY, 0xe1, { KEY_F14 } }, | 72 | { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ |
86 | { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } }, | 73 | { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, |
87 | { KE_KEY, 0xe0, { KEY_PROG1 } }, | 74 | { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, |
88 | { KE_KEY, 0x5c, { KEY_F15 } }, | 75 | { KE_KEY, 0xec, { KEY_CAMERA_UP } }, |
76 | { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, | ||
77 | { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, | ||
78 | { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, | ||
89 | { KE_END, 0}, | 79 | { KE_END, 0}, |
90 | }; | 80 | }; |
91 | 81 | ||
92 | struct bios_args { | 82 | static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level, |
93 | u32 dev_id; | ||
94 | u32 ctrl_param; | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * eeepc-wmi/ - debugfs root directory | ||
99 | * dev_id - current dev_id | ||
100 | * ctrl_param - current ctrl_param | ||
101 | * devs - call DEVS(dev_id, ctrl_param) and print result | ||
102 | * dsts - call DSTS(dev_id) and print result | ||
103 | */ | ||
104 | struct eeepc_wmi_debug { | ||
105 | struct dentry *root; | ||
106 | u32 dev_id; | ||
107 | u32 ctrl_param; | ||
108 | }; | ||
109 | |||
110 | struct eeepc_wmi { | ||
111 | struct input_dev *inputdev; | ||
112 | struct backlight_device *backlight_device; | ||
113 | struct platform_device *platform_device; | ||
114 | |||
115 | struct led_classdev tpd_led; | ||
116 | int tpd_led_wk; | ||
117 | struct workqueue_struct *led_workqueue; | ||
118 | struct work_struct tpd_led_work; | ||
119 | |||
120 | struct rfkill *wlan_rfkill; | ||
121 | struct rfkill *bluetooth_rfkill; | ||
122 | struct rfkill *wwan3g_rfkill; | ||
123 | |||
124 | struct eeepc_wmi_debug debug; | ||
125 | }; | ||
126 | |||
127 | /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ | ||
128 | static struct platform_device *platform_device; | ||
129 | |||
130 | static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) | ||
131 | { | ||
132 | int err; | ||
133 | |||
134 | eeepc->inputdev = input_allocate_device(); | ||
135 | if (!eeepc->inputdev) | ||
136 | return -ENOMEM; | ||
137 | |||
138 | eeepc->inputdev->name = "Eee PC WMI hotkeys"; | ||
139 | eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; | ||
140 | eeepc->inputdev->id.bustype = BUS_HOST; | ||
141 | eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; | ||
142 | |||
143 | err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); | ||
144 | if (err) | ||
145 | goto err_free_dev; | ||
146 | |||
147 | err = input_register_device(eeepc->inputdev); | ||
148 | if (err) | ||
149 | goto err_free_keymap; | ||
150 | |||
151 | return 0; | ||
152 | |||
153 | err_free_keymap: | ||
154 | sparse_keymap_free(eeepc->inputdev); | ||
155 | err_free_dev: | ||
156 | input_free_device(eeepc->inputdev); | ||
157 | return err; | ||
158 | } | ||
159 | |||
160 | static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) | ||
161 | { | ||
162 | if (eeepc->inputdev) { | ||
163 | sparse_keymap_free(eeepc->inputdev); | ||
164 | input_unregister_device(eeepc->inputdev); | ||
165 | } | ||
166 | |||
167 | eeepc->inputdev = NULL; | ||
168 | } | ||
169 | |||
170 | static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) | ||
171 | { | ||
172 | struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; | ||
173 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
174 | union acpi_object *obj; | ||
175 | acpi_status status; | ||
176 | u32 tmp; | ||
177 | |||
178 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, | ||
179 | 1, EEEPC_WMI_METHODID_DSTS, &input, &output); | ||
180 | |||
181 | if (ACPI_FAILURE(status)) | ||
182 | return status; | ||
183 | |||
184 | obj = (union acpi_object *)output.pointer; | ||
185 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
186 | tmp = (u32)obj->integer.value; | ||
187 | else | ||
188 | tmp = 0; | ||
189 | |||
190 | if (retval) | ||
191 | *retval = tmp; | ||
192 | |||
193 | kfree(obj); | ||
194 | |||
195 | return status; | ||
196 | |||
197 | } | ||
198 | |||
199 | static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, | ||
200 | u32 *retval) | ||
201 | { | ||
202 | struct bios_args args = { | ||
203 | .dev_id = dev_id, | ||
204 | .ctrl_param = ctrl_param, | ||
205 | }; | ||
206 | struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; | ||
207 | acpi_status status; | ||
208 | |||
209 | if (!retval) { | ||
210 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, | ||
211 | EEEPC_WMI_METHODID_DEVS, | ||
212 | &input, NULL); | ||
213 | } else { | ||
214 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
215 | union acpi_object *obj; | ||
216 | u32 tmp; | ||
217 | |||
218 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, | ||
219 | EEEPC_WMI_METHODID_DEVS, | ||
220 | &input, &output); | ||
221 | |||
222 | if (ACPI_FAILURE(status)) | ||
223 | return status; | ||
224 | |||
225 | obj = (union acpi_object *)output.pointer; | ||
226 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
227 | tmp = (u32)obj->integer.value; | ||
228 | else | ||
229 | tmp = 0; | ||
230 | |||
231 | *retval = tmp; | ||
232 | |||
233 | kfree(obj); | ||
234 | } | ||
235 | |||
236 | return status; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * LEDs | ||
241 | */ | ||
242 | /* | ||
243 | * These functions actually update the LED's, and are called from a | ||
244 | * workqueue. By doing this as separate work rather than when the LED | ||
245 | * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a | ||
246 | * potentially bad time, such as a timer interrupt. | ||
247 | */ | ||
248 | static void tpd_led_update(struct work_struct *work) | ||
249 | { | ||
250 | int ctrl_param; | ||
251 | struct eeepc_wmi *eeepc; | ||
252 | |||
253 | eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); | ||
254 | |||
255 | ctrl_param = eeepc->tpd_led_wk; | ||
256 | eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL); | ||
257 | } | ||
258 | |||
259 | static void tpd_led_set(struct led_classdev *led_cdev, | ||
260 | enum led_brightness value) | ||
261 | { | ||
262 | struct eeepc_wmi *eeepc; | ||
263 | |||
264 | eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); | ||
265 | |||
266 | eeepc->tpd_led_wk = !!value; | ||
267 | queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); | ||
268 | } | ||
269 | |||
270 | static int read_tpd_state(struct eeepc_wmi *eeepc) | ||
271 | { | ||
272 | u32 retval; | ||
273 | acpi_status status; | ||
274 | |||
275 | status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval); | ||
276 | |||
277 | if (ACPI_FAILURE(status)) | ||
278 | return -1; | ||
279 | else if (!retval || retval == 0x00060000) | ||
280 | /* | ||
281 | * if touchpad led is present, DSTS will set some bits, | ||
282 | * usually 0x00020000. | ||
283 | * 0x00060000 means that the device is not supported | ||
284 | */ | ||
285 | return -ENODEV; | ||
286 | else | ||
287 | /* Status is stored in the first bit */ | ||
288 | return retval & 0x1; | ||
289 | } | ||
290 | |||
291 | static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) | ||
292 | { | ||
293 | struct eeepc_wmi *eeepc; | ||
294 | |||
295 | eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); | ||
296 | |||
297 | return read_tpd_state(eeepc); | ||
298 | } | ||
299 | |||
300 | static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) | ||
301 | { | ||
302 | int rv; | ||
303 | |||
304 | if (read_tpd_state(eeepc) < 0) | ||
305 | return 0; | ||
306 | |||
307 | eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); | ||
308 | if (!eeepc->led_workqueue) | ||
309 | return -ENOMEM; | ||
310 | INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); | ||
311 | |||
312 | eeepc->tpd_led.name = "eeepc::touchpad"; | ||
313 | eeepc->tpd_led.brightness_set = tpd_led_set; | ||
314 | eeepc->tpd_led.brightness_get = tpd_led_get; | ||
315 | eeepc->tpd_led.max_brightness = 1; | ||
316 | |||
317 | rv = led_classdev_register(&eeepc->platform_device->dev, | ||
318 | &eeepc->tpd_led); | ||
319 | if (rv) { | ||
320 | destroy_workqueue(eeepc->led_workqueue); | ||
321 | return rv; | ||
322 | } | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) | ||
328 | { | ||
329 | if (eeepc->tpd_led.dev) | ||
330 | led_classdev_unregister(&eeepc->tpd_led); | ||
331 | if (eeepc->led_workqueue) | ||
332 | destroy_workqueue(eeepc->led_workqueue); | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Rfkill devices | ||
337 | */ | ||
338 | static int eeepc_rfkill_set(void *data, bool blocked) | ||
339 | { | ||
340 | int dev_id = (unsigned long)data; | ||
341 | u32 ctrl_param = !blocked; | ||
342 | |||
343 | return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); | ||
344 | } | ||
345 | |||
346 | static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) | ||
347 | { | ||
348 | int dev_id = (unsigned long)data; | ||
349 | u32 retval; | ||
350 | acpi_status status; | ||
351 | |||
352 | status = eeepc_wmi_get_devstate(dev_id, &retval); | ||
353 | |||
354 | if (ACPI_FAILURE(status)) | ||
355 | return ; | ||
356 | |||
357 | rfkill_set_sw_state(rfkill, !(retval & 0x1)); | ||
358 | } | ||
359 | |||
360 | static const struct rfkill_ops eeepc_rfkill_ops = { | ||
361 | .set_block = eeepc_rfkill_set, | ||
362 | .query = eeepc_rfkill_query, | ||
363 | }; | ||
364 | |||
365 | static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, | ||
366 | struct rfkill **rfkill, | ||
367 | const char *name, | ||
368 | enum rfkill_type type, int dev_id) | ||
369 | { | ||
370 | int result; | ||
371 | u32 retval; | ||
372 | acpi_status status; | ||
373 | |||
374 | status = eeepc_wmi_get_devstate(dev_id, &retval); | ||
375 | |||
376 | if (ACPI_FAILURE(status)) | ||
377 | return -1; | ||
378 | |||
379 | /* If the device is present, DSTS will always set some bits | ||
380 | * 0x00070000 - 1110000000000000000 - device supported | ||
381 | * 0x00060000 - 1100000000000000000 - not supported | ||
382 | * 0x00020000 - 0100000000000000000 - device supported | ||
383 | * 0x00010000 - 0010000000000000000 - not supported / special mode ? | ||
384 | */ | ||
385 | if (!retval || retval == 0x00060000) | ||
386 | return -ENODEV; | ||
387 | |||
388 | *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, | ||
389 | &eeepc_rfkill_ops, (void *)(long)dev_id); | ||
390 | |||
391 | if (!*rfkill) | ||
392 | return -EINVAL; | ||
393 | |||
394 | rfkill_init_sw_state(*rfkill, !(retval & 0x1)); | ||
395 | result = rfkill_register(*rfkill); | ||
396 | if (result) { | ||
397 | rfkill_destroy(*rfkill); | ||
398 | *rfkill = NULL; | ||
399 | return result; | ||
400 | } | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) | ||
405 | { | ||
406 | if (eeepc->wlan_rfkill) { | ||
407 | rfkill_unregister(eeepc->wlan_rfkill); | ||
408 | rfkill_destroy(eeepc->wlan_rfkill); | ||
409 | eeepc->wlan_rfkill = NULL; | ||
410 | } | ||
411 | if (eeepc->bluetooth_rfkill) { | ||
412 | rfkill_unregister(eeepc->bluetooth_rfkill); | ||
413 | rfkill_destroy(eeepc->bluetooth_rfkill); | ||
414 | eeepc->bluetooth_rfkill = NULL; | ||
415 | } | ||
416 | if (eeepc->wwan3g_rfkill) { | ||
417 | rfkill_unregister(eeepc->wwan3g_rfkill); | ||
418 | rfkill_destroy(eeepc->wwan3g_rfkill); | ||
419 | eeepc->wwan3g_rfkill = NULL; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) | ||
424 | { | ||
425 | int result = 0; | ||
426 | |||
427 | result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, | ||
428 | "eeepc-wlan", RFKILL_TYPE_WLAN, | ||
429 | EEEPC_WMI_DEVID_WLAN); | ||
430 | |||
431 | if (result && result != -ENODEV) | ||
432 | goto exit; | ||
433 | |||
434 | result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, | ||
435 | "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, | ||
436 | EEEPC_WMI_DEVID_BLUETOOTH); | ||
437 | |||
438 | if (result && result != -ENODEV) | ||
439 | goto exit; | ||
440 | |||
441 | result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, | ||
442 | "eeepc-wwan3g", RFKILL_TYPE_WWAN, | ||
443 | EEEPC_WMI_DEVID_WWAN3G); | ||
444 | |||
445 | if (result && result != -ENODEV) | ||
446 | goto exit; | ||
447 | |||
448 | exit: | ||
449 | if (result && result != -ENODEV) | ||
450 | eeepc_wmi_rfkill_exit(eeepc); | ||
451 | |||
452 | if (result == -ENODEV) | ||
453 | result = 0; | ||
454 | |||
455 | return result; | ||
456 | } | ||
457 | |||
458 | /* | ||
459 | * Backlight | ||
460 | */ | ||
461 | static int read_brightness(struct backlight_device *bd) | ||
462 | { | ||
463 | u32 retval; | ||
464 | acpi_status status; | ||
465 | |||
466 | status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval); | ||
467 | |||
468 | if (ACPI_FAILURE(status)) | ||
469 | return -1; | ||
470 | else | ||
471 | return retval & 0xFF; | ||
472 | } | ||
473 | |||
474 | static int update_bl_status(struct backlight_device *bd) | ||
475 | { | ||
476 | |||
477 | u32 ctrl_param; | ||
478 | acpi_status status; | ||
479 | |||
480 | ctrl_param = bd->props.brightness; | ||
481 | |||
482 | status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, | ||
483 | ctrl_param, NULL); | ||
484 | |||
485 | if (ACPI_FAILURE(status)) | ||
486 | return -1; | ||
487 | else | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static const struct backlight_ops eeepc_wmi_bl_ops = { | ||
492 | .get_brightness = read_brightness, | ||
493 | .update_status = update_bl_status, | ||
494 | }; | ||
495 | |||
496 | static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) | ||
497 | { | ||
498 | struct backlight_device *bd = eeepc->backlight_device; | ||
499 | int old = bd->props.brightness; | ||
500 | int new = old; | ||
501 | |||
502 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
503 | new = code - NOTIFY_BRNUP_MIN + 1; | ||
504 | else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) | ||
505 | new = code - NOTIFY_BRNDOWN_MIN; | ||
506 | |||
507 | bd->props.brightness = new; | ||
508 | backlight_update_status(bd); | ||
509 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); | ||
510 | |||
511 | return old; | ||
512 | } | ||
513 | |||
514 | static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) | ||
515 | { | ||
516 | struct backlight_device *bd; | ||
517 | struct backlight_properties props; | ||
518 | |||
519 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
520 | props.max_brightness = 15; | ||
521 | bd = backlight_device_register(EEEPC_WMI_FILE, | ||
522 | &eeepc->platform_device->dev, eeepc, | ||
523 | &eeepc_wmi_bl_ops, &props); | ||
524 | if (IS_ERR(bd)) { | ||
525 | pr_err("Could not register backlight device\n"); | ||
526 | return PTR_ERR(bd); | ||
527 | } | ||
528 | |||
529 | eeepc->backlight_device = bd; | ||
530 | |||
531 | bd->props.brightness = read_brightness(bd); | ||
532 | bd->props.power = FB_BLANK_UNBLANK; | ||
533 | backlight_update_status(bd); | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc) | ||
539 | { | ||
540 | if (eeepc->backlight_device) | ||
541 | backlight_device_unregister(eeepc->backlight_device); | ||
542 | |||
543 | eeepc->backlight_device = NULL; | ||
544 | } | ||
545 | |||
546 | static void eeepc_wmi_notify(u32 value, void *context) | ||
547 | { | ||
548 | struct eeepc_wmi *eeepc = context; | ||
549 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
550 | union acpi_object *obj; | ||
551 | acpi_status status; | ||
552 | int code; | ||
553 | int orig_code; | ||
554 | |||
555 | status = wmi_get_event_data(value, &response); | ||
556 | if (status != AE_OK) { | ||
557 | pr_err("bad event status 0x%x\n", status); | ||
558 | return; | ||
559 | } | ||
560 | |||
561 | obj = (union acpi_object *)response.pointer; | ||
562 | |||
563 | if (obj && obj->type == ACPI_TYPE_INTEGER) { | ||
564 | code = obj->integer.value; | ||
565 | orig_code = code; | ||
566 | |||
567 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
568 | code = NOTIFY_BRNUP_MIN; | ||
569 | else if (code >= NOTIFY_BRNDOWN_MIN && | ||
570 | code <= NOTIFY_BRNDOWN_MAX) | ||
571 | code = NOTIFY_BRNDOWN_MIN; | ||
572 | |||
573 | if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { | ||
574 | if (!acpi_video_backlight_support()) | ||
575 | eeepc_wmi_backlight_notify(eeepc, orig_code); | ||
576 | } | ||
577 | |||
578 | if (!sparse_keymap_report_event(eeepc->inputdev, | ||
579 | code, 1, true)) | ||
580 | pr_info("Unknown key %x pressed\n", code); | ||
581 | } | ||
582 | |||
583 | kfree(obj); | ||
584 | } | ||
585 | |||
586 | static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, | ||
587 | const char *buf, size_t count) | ||
588 | { | ||
589 | int value; | ||
590 | struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; | ||
591 | acpi_status status; | ||
592 | |||
593 | if (!count || sscanf(buf, "%i", &value) != 1) | ||
594 | return -EINVAL; | ||
595 | if (value < 0 || value > 2) | ||
596 | return -EINVAL; | ||
597 | |||
598 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, | ||
599 | 1, EEEPC_WMI_METHODID_CFVS, &input, NULL); | ||
600 | |||
601 | if (ACPI_FAILURE(status)) | ||
602 | return -EIO; | ||
603 | else | ||
604 | return count; | ||
605 | } | ||
606 | |||
607 | static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); | ||
608 | |||
609 | static struct attribute *platform_attributes[] = { | ||
610 | &dev_attr_cpufv.attr, | ||
611 | NULL | ||
612 | }; | ||
613 | |||
614 | static struct attribute_group platform_attribute_group = { | ||
615 | .attrs = platform_attributes | ||
616 | }; | ||
617 | |||
618 | static void eeepc_wmi_sysfs_exit(struct platform_device *device) | ||
619 | { | ||
620 | sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); | ||
621 | } | ||
622 | |||
623 | static int eeepc_wmi_sysfs_init(struct platform_device *device) | ||
624 | { | ||
625 | return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); | ||
626 | } | ||
627 | |||
628 | /* | ||
629 | * Platform device | ||
630 | */ | ||
631 | static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) | ||
632 | { | ||
633 | int err; | ||
634 | |||
635 | eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); | ||
636 | if (!eeepc->platform_device) | ||
637 | return -ENOMEM; | ||
638 | platform_set_drvdata(eeepc->platform_device, eeepc); | ||
639 | |||
640 | err = platform_device_add(eeepc->platform_device); | ||
641 | if (err) | ||
642 | goto fail_platform_device; | ||
643 | |||
644 | err = eeepc_wmi_sysfs_init(eeepc->platform_device); | ||
645 | if (err) | ||
646 | goto fail_sysfs; | ||
647 | return 0; | ||
648 | |||
649 | fail_sysfs: | ||
650 | platform_device_del(eeepc->platform_device); | ||
651 | fail_platform_device: | ||
652 | platform_device_put(eeepc->platform_device); | ||
653 | return err; | ||
654 | } | ||
655 | |||
656 | static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) | ||
657 | { | ||
658 | eeepc_wmi_sysfs_exit(eeepc->platform_device); | ||
659 | platform_device_unregister(eeepc->platform_device); | ||
660 | } | ||
661 | |||
662 | /* | ||
663 | * debugfs | ||
664 | */ | ||
665 | struct eeepc_wmi_debugfs_node { | ||
666 | struct eeepc_wmi *eeepc; | ||
667 | char *name; | ||
668 | int (*show)(struct seq_file *m, void *data); | ||
669 | }; | ||
670 | |||
671 | static int show_dsts(struct seq_file *m, void *data) | ||
672 | { | ||
673 | struct eeepc_wmi *eeepc = m->private; | ||
674 | acpi_status status; | ||
675 | u32 retval = -1; | ||
676 | |||
677 | status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); | ||
678 | |||
679 | if (ACPI_FAILURE(status)) | ||
680 | return -EIO; | ||
681 | |||
682 | seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int show_devs(struct seq_file *m, void *data) | ||
688 | { | ||
689 | struct eeepc_wmi *eeepc = m->private; | ||
690 | acpi_status status; | ||
691 | u32 retval = -1; | ||
692 | |||
693 | status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, | ||
694 | eeepc->debug.ctrl_param, &retval); | ||
695 | if (ACPI_FAILURE(status)) | ||
696 | return -EIO; | ||
697 | |||
698 | seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, | ||
699 | eeepc->debug.ctrl_param, retval); | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { | ||
705 | { NULL, "devs", show_devs }, | ||
706 | { NULL, "dsts", show_dsts }, | ||
707 | }; | ||
708 | |||
709 | static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) | ||
710 | { | ||
711 | struct eeepc_wmi_debugfs_node *node = inode->i_private; | ||
712 | |||
713 | return single_open(file, node->show, node->eeepc); | ||
714 | } | ||
715 | |||
716 | static const struct file_operations eeepc_wmi_debugfs_io_ops = { | ||
717 | .owner = THIS_MODULE, | ||
718 | .open = eeepc_wmi_debugfs_open, | ||
719 | .read = seq_read, | ||
720 | .llseek = seq_lseek, | ||
721 | .release = single_release, | ||
722 | }; | ||
723 | |||
724 | static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) | ||
725 | { | ||
726 | debugfs_remove_recursive(eeepc->debug.root); | ||
727 | } | ||
728 | |||
729 | static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) | ||
730 | { | ||
731 | struct dentry *dent; | ||
732 | int i; | ||
733 | |||
734 | eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); | ||
735 | if (!eeepc->debug.root) { | ||
736 | pr_err("failed to create debugfs directory"); | ||
737 | goto error_debugfs; | ||
738 | } | ||
739 | |||
740 | dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, | ||
741 | eeepc->debug.root, &eeepc->debug.dev_id); | ||
742 | if (!dent) | ||
743 | goto error_debugfs; | ||
744 | |||
745 | dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, | ||
746 | eeepc->debug.root, &eeepc->debug.ctrl_param); | ||
747 | if (!dent) | ||
748 | goto error_debugfs; | ||
749 | |||
750 | for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { | ||
751 | struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; | ||
752 | |||
753 | node->eeepc = eeepc; | ||
754 | dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, | ||
755 | eeepc->debug.root, node, | ||
756 | &eeepc_wmi_debugfs_io_ops); | ||
757 | if (!dent) { | ||
758 | pr_err("failed to create debug file: %s\n", node->name); | ||
759 | goto error_debugfs; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | return 0; | ||
764 | |||
765 | error_debugfs: | ||
766 | eeepc_wmi_debugfs_exit(eeepc); | ||
767 | return -ENOMEM; | ||
768 | } | ||
769 | |||
770 | /* | ||
771 | * WMI Driver | ||
772 | */ | ||
773 | static struct platform_device * __init eeepc_wmi_add(void) | ||
774 | { | ||
775 | struct eeepc_wmi *eeepc; | ||
776 | acpi_status status; | ||
777 | int err; | ||
778 | |||
779 | eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); | ||
780 | if (!eeepc) | ||
781 | return ERR_PTR(-ENOMEM); | ||
782 | |||
783 | /* | ||
784 | * Register the platform device first. It is used as a parent for the | ||
785 | * sub-devices below. | ||
786 | */ | ||
787 | err = eeepc_wmi_platform_init(eeepc); | ||
788 | if (err) | ||
789 | goto fail_platform; | ||
790 | |||
791 | err = eeepc_wmi_input_init(eeepc); | ||
792 | if (err) | ||
793 | goto fail_input; | ||
794 | |||
795 | err = eeepc_wmi_led_init(eeepc); | ||
796 | if (err) | ||
797 | goto fail_leds; | ||
798 | |||
799 | err = eeepc_wmi_rfkill_init(eeepc); | ||
800 | if (err) | ||
801 | goto fail_rfkill; | ||
802 | |||
803 | if (!acpi_video_backlight_support()) { | ||
804 | err = eeepc_wmi_backlight_init(eeepc); | ||
805 | if (err) | ||
806 | goto fail_backlight; | ||
807 | } else | ||
808 | pr_info("Backlight controlled by ACPI video driver\n"); | ||
809 | |||
810 | status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, | ||
811 | eeepc_wmi_notify, eeepc); | ||
812 | if (ACPI_FAILURE(status)) { | ||
813 | pr_err("Unable to register notify handler - %d\n", | ||
814 | status); | ||
815 | err = -ENODEV; | ||
816 | goto fail_wmi_handler; | ||
817 | } | ||
818 | |||
819 | err = eeepc_wmi_debugfs_init(eeepc); | ||
820 | if (err) | ||
821 | goto fail_debugfs; | ||
822 | |||
823 | return eeepc->platform_device; | ||
824 | |||
825 | fail_debugfs: | ||
826 | wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); | ||
827 | fail_wmi_handler: | ||
828 | eeepc_wmi_backlight_exit(eeepc); | ||
829 | fail_backlight: | ||
830 | eeepc_wmi_rfkill_exit(eeepc); | ||
831 | fail_rfkill: | ||
832 | eeepc_wmi_led_exit(eeepc); | ||
833 | fail_leds: | ||
834 | eeepc_wmi_input_exit(eeepc); | ||
835 | fail_input: | ||
836 | eeepc_wmi_platform_exit(eeepc); | ||
837 | fail_platform: | ||
838 | kfree(eeepc); | ||
839 | return ERR_PTR(err); | ||
840 | } | ||
841 | |||
842 | static int eeepc_wmi_remove(struct platform_device *device) | ||
843 | { | ||
844 | struct eeepc_wmi *eeepc; | ||
845 | |||
846 | eeepc = platform_get_drvdata(device); | ||
847 | wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); | ||
848 | eeepc_wmi_backlight_exit(eeepc); | ||
849 | eeepc_wmi_input_exit(eeepc); | ||
850 | eeepc_wmi_led_exit(eeepc); | ||
851 | eeepc_wmi_rfkill_exit(eeepc); | ||
852 | eeepc_wmi_debugfs_exit(eeepc); | ||
853 | eeepc_wmi_platform_exit(eeepc); | ||
854 | |||
855 | kfree(eeepc); | ||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static struct platform_driver platform_driver = { | ||
860 | .driver = { | ||
861 | .name = EEEPC_WMI_FILE, | ||
862 | .owner = THIS_MODULE, | ||
863 | }, | ||
864 | }; | ||
865 | |||
866 | static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, | ||
867 | void *context, void **retval) | 83 | void *context, void **retval) |
868 | { | 84 | { |
869 | pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); | 85 | pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); |
@@ -871,7 +87,7 @@ static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, | |||
871 | return AE_CTRL_TERMINATE; | 87 | return AE_CTRL_TERMINATE; |
872 | } | 88 | } |
873 | 89 | ||
874 | static int __init eeepc_wmi_check_atkd(void) | 90 | static int eeepc_wmi_check_atkd(void) |
875 | { | 91 | { |
876 | acpi_status status; | 92 | acpi_status status; |
877 | bool found = false; | 93 | bool found = false; |
@@ -884,16 +100,8 @@ static int __init eeepc_wmi_check_atkd(void) | |||
884 | return -1; | 100 | return -1; |
885 | } | 101 | } |
886 | 102 | ||
887 | static int __init eeepc_wmi_init(void) | 103 | static int eeepc_wmi_probe(struct platform_device *pdev) |
888 | { | 104 | { |
889 | int err; | ||
890 | |||
891 | if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || | ||
892 | !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { | ||
893 | pr_warning("No known WMI GUID found\n"); | ||
894 | return -ENODEV; | ||
895 | } | ||
896 | |||
897 | if (eeepc_wmi_check_atkd()) { | 105 | if (eeepc_wmi_check_atkd()) { |
898 | pr_warning("WMI device present, but legacy ATKD device is also " | 106 | pr_warning("WMI device present, but legacy ATKD device is also " |
899 | "present and enabled."); | 107 | "present and enabled."); |
@@ -901,33 +109,59 @@ static int __init eeepc_wmi_init(void) | |||
901 | "acpi_osi=\"!Windows 2009\""); | 109 | "acpi_osi=\"!Windows 2009\""); |
902 | pr_warning("Can't load eeepc-wmi, use default acpi_osi " | 110 | pr_warning("Can't load eeepc-wmi, use default acpi_osi " |
903 | "(preferred) or eeepc-laptop"); | 111 | "(preferred) or eeepc-laptop"); |
904 | return -ENODEV; | 112 | return -EBUSY; |
905 | } | 113 | } |
114 | return 0; | ||
115 | } | ||
906 | 116 | ||
907 | platform_device = eeepc_wmi_add(); | 117 | static void eeepc_dmi_check(struct asus_wmi_driver *driver) |
908 | if (IS_ERR(platform_device)) { | 118 | { |
909 | err = PTR_ERR(platform_device); | 119 | const char *model; |
910 | goto fail_eeepc_wmi; | 120 | |
911 | } | 121 | model = dmi_get_system_info(DMI_PRODUCT_NAME); |
122 | if (!model) | ||
123 | return; | ||
912 | 124 | ||
913 | err = platform_driver_register(&platform_driver); | 125 | /* |
914 | if (err) { | 126 | * Whitelist for wlan hotplug |
915 | pr_warning("Unable to register platform driver\n"); | 127 | * |
916 | goto fail_platform_driver; | 128 | * Asus 1000H needs the current hotplug code to handle |
129 | * Fn+F2 correctly. We may add other Asus here later, but | ||
130 | * it seems that most of the laptops supported by asus-wmi | ||
131 | * don't need to be on this list | ||
132 | */ | ||
133 | if (strcmp(model, "1000H") == 0) { | ||
134 | driver->hotplug_wireless = true; | ||
135 | pr_info("wlan hotplug enabled\n"); | ||
917 | } | 136 | } |
137 | } | ||
138 | |||
139 | static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) | ||
140 | { | ||
141 | driver->hotplug_wireless = hotplug_wireless; | ||
142 | eeepc_dmi_check(driver); | ||
143 | } | ||
144 | |||
145 | static struct asus_wmi_driver asus_wmi_driver = { | ||
146 | .name = EEEPC_WMI_FILE, | ||
147 | .owner = THIS_MODULE, | ||
148 | .event_guid = EEEPC_WMI_EVENT_GUID, | ||
149 | .keymap = eeepc_wmi_keymap, | ||
150 | .input_name = "Eee PC WMI hotkeys", | ||
151 | .input_phys = EEEPC_WMI_FILE "/input0", | ||
152 | .probe = eeepc_wmi_probe, | ||
153 | .quirks = eeepc_wmi_quirks, | ||
154 | }; | ||
918 | 155 | ||
919 | return 0; | ||
920 | 156 | ||
921 | fail_platform_driver: | 157 | static int __init eeepc_wmi_init(void) |
922 | eeepc_wmi_remove(platform_device); | 158 | { |
923 | fail_eeepc_wmi: | 159 | return asus_wmi_register_driver(&asus_wmi_driver); |
924 | return err; | ||
925 | } | 160 | } |
926 | 161 | ||
927 | static void __exit eeepc_wmi_exit(void) | 162 | static void __exit eeepc_wmi_exit(void) |
928 | { | 163 | { |
929 | eeepc_wmi_remove(platform_device); | 164 | asus_wmi_unregister_driver(&asus_wmi_driver); |
930 | platform_driver_unregister(&platform_driver); | ||
931 | } | 165 | } |
932 | 166 | ||
933 | module_init(eeepc_wmi_init); | 167 | module_init(eeepc_wmi_init); |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 9e05af9c41cb..1bc4a7539ba9 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * HP WMI hotkeys | 2 | * HP WMI hotkeys |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Red Hat <mjg@redhat.com> | 4 | * Copyright (C) 2008 Red Hat <mjg@redhat.com> |
5 | * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi> | ||
5 | * | 6 | * |
6 | * Portions based on wistron_btns.c: | 7 | * Portions based on wistron_btns.c: |
7 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | 8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> |
@@ -51,6 +52,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
51 | #define HPWMI_HARDWARE_QUERY 0x4 | 52 | #define HPWMI_HARDWARE_QUERY 0x4 |
52 | #define HPWMI_WIRELESS_QUERY 0x5 | 53 | #define HPWMI_WIRELESS_QUERY 0x5 |
53 | #define HPWMI_HOTKEY_QUERY 0xc | 54 | #define HPWMI_HOTKEY_QUERY 0xc |
55 | #define HPWMI_WIRELESS2_QUERY 0x1b | ||
54 | 56 | ||
55 | #define PREFIX "HP WMI: " | 57 | #define PREFIX "HP WMI: " |
56 | #define UNIMP "Unimplemented " | 58 | #define UNIMP "Unimplemented " |
@@ -86,7 +88,46 @@ struct bios_args { | |||
86 | struct bios_return { | 88 | struct bios_return { |
87 | u32 sigpass; | 89 | u32 sigpass; |
88 | u32 return_code; | 90 | u32 return_code; |
89 | u32 value; | 91 | }; |
92 | |||
93 | enum hp_return_value { | ||
94 | HPWMI_RET_WRONG_SIGNATURE = 0x02, | ||
95 | HPWMI_RET_UNKNOWN_COMMAND = 0x03, | ||
96 | HPWMI_RET_UNKNOWN_CMDTYPE = 0x04, | ||
97 | HPWMI_RET_INVALID_PARAMETERS = 0x05, | ||
98 | }; | ||
99 | |||
100 | enum hp_wireless2_bits { | ||
101 | HPWMI_POWER_STATE = 0x01, | ||
102 | HPWMI_POWER_SOFT = 0x02, | ||
103 | HPWMI_POWER_BIOS = 0x04, | ||
104 | HPWMI_POWER_HARD = 0x08, | ||
105 | }; | ||
106 | |||
107 | #define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \ | ||
108 | != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) | ||
109 | #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) | ||
110 | |||
111 | struct bios_rfkill2_device_state { | ||
112 | u8 radio_type; | ||
113 | u8 bus_type; | ||
114 | u16 vendor_id; | ||
115 | u16 product_id; | ||
116 | u16 subsys_vendor_id; | ||
117 | u16 subsys_product_id; | ||
118 | u8 rfkill_id; | ||
119 | u8 power; | ||
120 | u8 unknown[4]; | ||
121 | }; | ||
122 | |||
123 | /* 7 devices fit into the 128 byte buffer */ | ||
124 | #define HPWMI_MAX_RFKILL2_DEVICES 7 | ||
125 | |||
126 | struct bios_rfkill2_state { | ||
127 | u8 unknown[7]; | ||
128 | u8 count; | ||
129 | u8 pad[8]; | ||
130 | struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES]; | ||
90 | }; | 131 | }; |
91 | 132 | ||
92 | static const struct key_entry hp_wmi_keymap[] = { | 133 | static const struct key_entry hp_wmi_keymap[] = { |
@@ -108,6 +149,15 @@ static struct rfkill *wifi_rfkill; | |||
108 | static struct rfkill *bluetooth_rfkill; | 149 | static struct rfkill *bluetooth_rfkill; |
109 | static struct rfkill *wwan_rfkill; | 150 | static struct rfkill *wwan_rfkill; |
110 | 151 | ||
152 | struct rfkill2_device { | ||
153 | u8 id; | ||
154 | int num; | ||
155 | struct rfkill *rfkill; | ||
156 | }; | ||
157 | |||
158 | static int rfkill2_count; | ||
159 | static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; | ||
160 | |||
111 | static const struct dev_pm_ops hp_wmi_pm_ops = { | 161 | static const struct dev_pm_ops hp_wmi_pm_ops = { |
112 | .resume = hp_wmi_resume_handler, | 162 | .resume = hp_wmi_resume_handler, |
113 | .restore = hp_wmi_resume_handler, | 163 | .restore = hp_wmi_resume_handler, |
@@ -129,7 +179,8 @@ static struct platform_driver hp_wmi_driver = { | |||
129 | * query: The commandtype -> What should be queried | 179 | * query: The commandtype -> What should be queried |
130 | * write: The command -> 0 read, 1 write, 3 ODM specific | 180 | * write: The command -> 0 read, 1 write, 3 ODM specific |
131 | * buffer: Buffer used as input and/or output | 181 | * buffer: Buffer used as input and/or output |
132 | * buffersize: Size of buffer | 182 | * insize: Size of input buffer |
183 | * outsize: Size of output buffer | ||
133 | * | 184 | * |
134 | * returns zero on success | 185 | * returns zero on success |
135 | * an HP WMI query specific error code (which is positive) | 186 | * an HP WMI query specific error code (which is positive) |
@@ -140,25 +191,29 @@ static struct platform_driver hp_wmi_driver = { | |||
140 | * size. E.g. Battery info query (0x7) is defined to have 1 byte input | 191 | * size. E.g. Battery info query (0x7) is defined to have 1 byte input |
141 | * and 128 byte output. The caller would do: | 192 | * and 128 byte output. The caller would do: |
142 | * buffer = kzalloc(128, GFP_KERNEL); | 193 | * buffer = kzalloc(128, GFP_KERNEL); |
143 | * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) | 194 | * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128) |
144 | */ | 195 | */ |
145 | static int hp_wmi_perform_query(int query, int write, u32 *buffer, | 196 | static int hp_wmi_perform_query(int query, int write, void *buffer, |
146 | int buffersize) | 197 | int insize, int outsize) |
147 | { | 198 | { |
148 | struct bios_return bios_return; | 199 | struct bios_return *bios_return; |
149 | acpi_status status; | 200 | int actual_outsize; |
150 | union acpi_object *obj; | 201 | union acpi_object *obj; |
151 | struct bios_args args = { | 202 | struct bios_args args = { |
152 | .signature = 0x55434553, | 203 | .signature = 0x55434553, |
153 | .command = write ? 0x2 : 0x1, | 204 | .command = write ? 0x2 : 0x1, |
154 | .commandtype = query, | 205 | .commandtype = query, |
155 | .datasize = buffersize, | 206 | .datasize = insize, |
156 | .data = *buffer, | 207 | .data = 0, |
157 | }; | 208 | }; |
158 | struct acpi_buffer input = { sizeof(struct bios_args), &args }; | 209 | struct acpi_buffer input = { sizeof(struct bios_args), &args }; |
159 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 210 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; |
160 | 211 | ||
161 | status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); | 212 | if (WARN_ON(insize > sizeof(args.data))) |
213 | return -EINVAL; | ||
214 | memcpy(&args.data, buffer, insize); | ||
215 | |||
216 | wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); | ||
162 | 217 | ||
163 | obj = output.pointer; | 218 | obj = output.pointer; |
164 | 219 | ||
@@ -169,10 +224,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, | |||
169 | return -EINVAL; | 224 | return -EINVAL; |
170 | } | 225 | } |
171 | 226 | ||
172 | bios_return = *((struct bios_return *)obj->buffer.pointer); | 227 | bios_return = (struct bios_return *)obj->buffer.pointer; |
173 | 228 | ||
174 | memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); | 229 | if (bios_return->return_code) { |
230 | if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE) | ||
231 | printk(KERN_WARNING PREFIX "query 0x%x returned " | ||
232 | "error 0x%x\n", | ||
233 | query, bios_return->return_code); | ||
234 | kfree(obj); | ||
235 | return bios_return->return_code; | ||
236 | } | ||
237 | |||
238 | if (!outsize) { | ||
239 | /* ignore output data */ | ||
240 | kfree(obj); | ||
241 | return 0; | ||
242 | } | ||
175 | 243 | ||
244 | actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); | ||
245 | memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); | ||
246 | memset(buffer + actual_outsize, 0, outsize - actual_outsize); | ||
176 | kfree(obj); | 247 | kfree(obj); |
177 | return 0; | 248 | return 0; |
178 | } | 249 | } |
@@ -181,7 +252,7 @@ static int hp_wmi_display_state(void) | |||
181 | { | 252 | { |
182 | int state = 0; | 253 | int state = 0; |
183 | int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, | 254 | int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, |
184 | sizeof(state)); | 255 | sizeof(state), sizeof(state)); |
185 | if (ret) | 256 | if (ret) |
186 | return -EINVAL; | 257 | return -EINVAL; |
187 | return state; | 258 | return state; |
@@ -191,7 +262,7 @@ static int hp_wmi_hddtemp_state(void) | |||
191 | { | 262 | { |
192 | int state = 0; | 263 | int state = 0; |
193 | int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, | 264 | int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, |
194 | sizeof(state)); | 265 | sizeof(state), sizeof(state)); |
195 | if (ret) | 266 | if (ret) |
196 | return -EINVAL; | 267 | return -EINVAL; |
197 | return state; | 268 | return state; |
@@ -201,7 +272,7 @@ static int hp_wmi_als_state(void) | |||
201 | { | 272 | { |
202 | int state = 0; | 273 | int state = 0; |
203 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, | 274 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, |
204 | sizeof(state)); | 275 | sizeof(state), sizeof(state)); |
205 | if (ret) | 276 | if (ret) |
206 | return -EINVAL; | 277 | return -EINVAL; |
207 | return state; | 278 | return state; |
@@ -211,7 +282,7 @@ static int hp_wmi_dock_state(void) | |||
211 | { | 282 | { |
212 | int state = 0; | 283 | int state = 0; |
213 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, | 284 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, |
214 | sizeof(state)); | 285 | sizeof(state), sizeof(state)); |
215 | 286 | ||
216 | if (ret) | 287 | if (ret) |
217 | return -EINVAL; | 288 | return -EINVAL; |
@@ -223,7 +294,7 @@ static int hp_wmi_tablet_state(void) | |||
223 | { | 294 | { |
224 | int state = 0; | 295 | int state = 0; |
225 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, | 296 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, |
226 | sizeof(state)); | 297 | sizeof(state), sizeof(state)); |
227 | if (ret) | 298 | if (ret) |
228 | return ret; | 299 | return ret; |
229 | 300 | ||
@@ -237,7 +308,7 @@ static int hp_wmi_set_block(void *data, bool blocked) | |||
237 | int ret; | 308 | int ret; |
238 | 309 | ||
239 | ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, | 310 | ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, |
240 | &query, sizeof(query)); | 311 | &query, sizeof(query), 0); |
241 | if (ret) | 312 | if (ret) |
242 | return -EINVAL; | 313 | return -EINVAL; |
243 | return 0; | 314 | return 0; |
@@ -252,7 +323,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) | |||
252 | int wireless = 0; | 323 | int wireless = 0; |
253 | int mask; | 324 | int mask; |
254 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, | 325 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, |
255 | &wireless, sizeof(wireless)); | 326 | &wireless, sizeof(wireless), |
327 | sizeof(wireless)); | ||
256 | /* TBD: Pass error */ | 328 | /* TBD: Pass error */ |
257 | 329 | ||
258 | mask = 0x200 << (r * 8); | 330 | mask = 0x200 << (r * 8); |
@@ -268,7 +340,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) | |||
268 | int wireless = 0; | 340 | int wireless = 0; |
269 | int mask; | 341 | int mask; |
270 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, | 342 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, |
271 | &wireless, sizeof(wireless)); | 343 | &wireless, sizeof(wireless), |
344 | sizeof(wireless)); | ||
272 | /* TBD: Pass error */ | 345 | /* TBD: Pass error */ |
273 | 346 | ||
274 | mask = 0x800 << (r * 8); | 347 | mask = 0x800 << (r * 8); |
@@ -279,6 +352,51 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) | |||
279 | return true; | 352 | return true; |
280 | } | 353 | } |
281 | 354 | ||
355 | static int hp_wmi_rfkill2_set_block(void *data, bool blocked) | ||
356 | { | ||
357 | int rfkill_id = (int)(long)data; | ||
358 | char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; | ||
359 | |||
360 | if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1, | ||
361 | buffer, sizeof(buffer), 0)) | ||
362 | return -EINVAL; | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static const struct rfkill_ops hp_wmi_rfkill2_ops = { | ||
367 | .set_block = hp_wmi_rfkill2_set_block, | ||
368 | }; | ||
369 | |||
370 | static int hp_wmi_rfkill2_refresh(void) | ||
371 | { | ||
372 | int err, i; | ||
373 | struct bios_rfkill2_state state; | ||
374 | |||
375 | err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, | ||
376 | 0, sizeof(state)); | ||
377 | if (err) | ||
378 | return err; | ||
379 | |||
380 | for (i = 0; i < rfkill2_count; i++) { | ||
381 | int num = rfkill2[i].num; | ||
382 | struct bios_rfkill2_device_state *devstate; | ||
383 | devstate = &state.device[num]; | ||
384 | |||
385 | if (num >= state.count || | ||
386 | devstate->rfkill_id != rfkill2[i].id) { | ||
387 | printk(KERN_WARNING PREFIX "power configuration of " | ||
388 | "the wireless devices unexpectedly changed\n"); | ||
389 | continue; | ||
390 | } | ||
391 | |||
392 | rfkill_set_states(rfkill2[i].rfkill, | ||
393 | IS_SWBLOCKED(devstate->power), | ||
394 | IS_HWBLOCKED(devstate->power)); | ||
395 | } | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
282 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, | 400 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, |
283 | char *buf) | 401 | char *buf) |
284 | { | 402 | { |
@@ -329,7 +447,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, | |||
329 | { | 447 | { |
330 | u32 tmp = simple_strtoul(buf, NULL, 10); | 448 | u32 tmp = simple_strtoul(buf, NULL, 10); |
331 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, | 449 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, |
332 | sizeof(tmp)); | 450 | sizeof(tmp), sizeof(tmp)); |
333 | if (ret) | 451 | if (ret) |
334 | return -EINVAL; | 452 | return -EINVAL; |
335 | 453 | ||
@@ -402,6 +520,7 @@ static void hp_wmi_notify(u32 value, void *context) | |||
402 | case HPWMI_BEZEL_BUTTON: | 520 | case HPWMI_BEZEL_BUTTON: |
403 | ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, | 521 | ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, |
404 | &key_code, | 522 | &key_code, |
523 | sizeof(key_code), | ||
405 | sizeof(key_code)); | 524 | sizeof(key_code)); |
406 | if (ret) | 525 | if (ret) |
407 | break; | 526 | break; |
@@ -412,6 +531,11 @@ static void hp_wmi_notify(u32 value, void *context) | |||
412 | key_code); | 531 | key_code); |
413 | break; | 532 | break; |
414 | case HPWMI_WIRELESS: | 533 | case HPWMI_WIRELESS: |
534 | if (rfkill2_count) { | ||
535 | hp_wmi_rfkill2_refresh(); | ||
536 | break; | ||
537 | } | ||
538 | |||
415 | if (wifi_rfkill) | 539 | if (wifi_rfkill) |
416 | rfkill_set_states(wifi_rfkill, | 540 | rfkill_set_states(wifi_rfkill, |
417 | hp_wmi_get_sw_state(HPWMI_WIFI), | 541 | hp_wmi_get_sw_state(HPWMI_WIFI), |
@@ -502,32 +626,16 @@ static void cleanup_sysfs(struct platform_device *device) | |||
502 | device_remove_file(&device->dev, &dev_attr_tablet); | 626 | device_remove_file(&device->dev, &dev_attr_tablet); |
503 | } | 627 | } |
504 | 628 | ||
505 | static int __devinit hp_wmi_bios_setup(struct platform_device *device) | 629 | static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) |
506 | { | 630 | { |
507 | int err; | 631 | int err; |
508 | int wireless = 0; | 632 | int wireless = 0; |
509 | 633 | ||
510 | err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, | 634 | err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, |
511 | sizeof(wireless)); | 635 | sizeof(wireless), sizeof(wireless)); |
512 | if (err) | 636 | if (err) |
513 | return err; | 637 | return err; |
514 | 638 | ||
515 | err = device_create_file(&device->dev, &dev_attr_display); | ||
516 | if (err) | ||
517 | goto add_sysfs_error; | ||
518 | err = device_create_file(&device->dev, &dev_attr_hddtemp); | ||
519 | if (err) | ||
520 | goto add_sysfs_error; | ||
521 | err = device_create_file(&device->dev, &dev_attr_als); | ||
522 | if (err) | ||
523 | goto add_sysfs_error; | ||
524 | err = device_create_file(&device->dev, &dev_attr_dock); | ||
525 | if (err) | ||
526 | goto add_sysfs_error; | ||
527 | err = device_create_file(&device->dev, &dev_attr_tablet); | ||
528 | if (err) | ||
529 | goto add_sysfs_error; | ||
530 | |||
531 | if (wireless & 0x1) { | 639 | if (wireless & 0x1) { |
532 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, | 640 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, |
533 | RFKILL_TYPE_WLAN, | 641 | RFKILL_TYPE_WLAN, |
@@ -573,14 +681,131 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device) | |||
573 | return 0; | 681 | return 0; |
574 | register_wwan_err: | 682 | register_wwan_err: |
575 | rfkill_destroy(wwan_rfkill); | 683 | rfkill_destroy(wwan_rfkill); |
684 | wwan_rfkill = NULL; | ||
576 | if (bluetooth_rfkill) | 685 | if (bluetooth_rfkill) |
577 | rfkill_unregister(bluetooth_rfkill); | 686 | rfkill_unregister(bluetooth_rfkill); |
578 | register_bluetooth_error: | 687 | register_bluetooth_error: |
579 | rfkill_destroy(bluetooth_rfkill); | 688 | rfkill_destroy(bluetooth_rfkill); |
689 | bluetooth_rfkill = NULL; | ||
580 | if (wifi_rfkill) | 690 | if (wifi_rfkill) |
581 | rfkill_unregister(wifi_rfkill); | 691 | rfkill_unregister(wifi_rfkill); |
582 | register_wifi_error: | 692 | register_wifi_error: |
583 | rfkill_destroy(wifi_rfkill); | 693 | rfkill_destroy(wifi_rfkill); |
694 | wifi_rfkill = NULL; | ||
695 | return err; | ||
696 | } | ||
697 | |||
698 | static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device) | ||
699 | { | ||
700 | int err, i; | ||
701 | struct bios_rfkill2_state state; | ||
702 | err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, | ||
703 | 0, sizeof(state)); | ||
704 | if (err) | ||
705 | return err; | ||
706 | |||
707 | if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { | ||
708 | printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n"); | ||
709 | return -EINVAL; | ||
710 | } | ||
711 | |||
712 | for (i = 0; i < state.count; i++) { | ||
713 | struct rfkill *rfkill; | ||
714 | enum rfkill_type type; | ||
715 | char *name; | ||
716 | switch (state.device[i].radio_type) { | ||
717 | case HPWMI_WIFI: | ||
718 | type = RFKILL_TYPE_WLAN; | ||
719 | name = "hp-wifi"; | ||
720 | break; | ||
721 | case HPWMI_BLUETOOTH: | ||
722 | type = RFKILL_TYPE_BLUETOOTH; | ||
723 | name = "hp-bluetooth"; | ||
724 | break; | ||
725 | case HPWMI_WWAN: | ||
726 | type = RFKILL_TYPE_WWAN; | ||
727 | name = "hp-wwan"; | ||
728 | break; | ||
729 | default: | ||
730 | printk(KERN_WARNING PREFIX "unknown device type 0x%x\n", | ||
731 | state.device[i].radio_type); | ||
732 | continue; | ||
733 | } | ||
734 | |||
735 | if (!state.device[i].vendor_id) { | ||
736 | printk(KERN_WARNING PREFIX "zero device %d while %d " | ||
737 | "reported\n", i, state.count); | ||
738 | continue; | ||
739 | } | ||
740 | |||
741 | rfkill = rfkill_alloc(name, &device->dev, type, | ||
742 | &hp_wmi_rfkill2_ops, (void *)(long)i); | ||
743 | if (!rfkill) { | ||
744 | err = -ENOMEM; | ||
745 | goto fail; | ||
746 | } | ||
747 | |||
748 | rfkill2[rfkill2_count].id = state.device[i].rfkill_id; | ||
749 | rfkill2[rfkill2_count].num = i; | ||
750 | rfkill2[rfkill2_count].rfkill = rfkill; | ||
751 | |||
752 | rfkill_init_sw_state(rfkill, | ||
753 | IS_SWBLOCKED(state.device[i].power)); | ||
754 | rfkill_set_hw_state(rfkill, | ||
755 | IS_HWBLOCKED(state.device[i].power)); | ||
756 | |||
757 | if (!(state.device[i].power & HPWMI_POWER_BIOS)) | ||
758 | printk(KERN_INFO PREFIX "device %s blocked by BIOS\n", | ||
759 | name); | ||
760 | |||
761 | err = rfkill_register(rfkill); | ||
762 | if (err) { | ||
763 | rfkill_destroy(rfkill); | ||
764 | goto fail; | ||
765 | } | ||
766 | |||
767 | rfkill2_count++; | ||
768 | } | ||
769 | |||
770 | return 0; | ||
771 | fail: | ||
772 | for (; rfkill2_count > 0; rfkill2_count--) { | ||
773 | rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill); | ||
774 | rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill); | ||
775 | } | ||
776 | return err; | ||
777 | } | ||
778 | |||
779 | static int __devinit hp_wmi_bios_setup(struct platform_device *device) | ||
780 | { | ||
781 | int err; | ||
782 | |||
783 | /* clear detected rfkill devices */ | ||
784 | wifi_rfkill = NULL; | ||
785 | bluetooth_rfkill = NULL; | ||
786 | wwan_rfkill = NULL; | ||
787 | rfkill2_count = 0; | ||
788 | |||
789 | if (hp_wmi_rfkill_setup(device)) | ||
790 | hp_wmi_rfkill2_setup(device); | ||
791 | |||
792 | err = device_create_file(&device->dev, &dev_attr_display); | ||
793 | if (err) | ||
794 | goto add_sysfs_error; | ||
795 | err = device_create_file(&device->dev, &dev_attr_hddtemp); | ||
796 | if (err) | ||
797 | goto add_sysfs_error; | ||
798 | err = device_create_file(&device->dev, &dev_attr_als); | ||
799 | if (err) | ||
800 | goto add_sysfs_error; | ||
801 | err = device_create_file(&device->dev, &dev_attr_dock); | ||
802 | if (err) | ||
803 | goto add_sysfs_error; | ||
804 | err = device_create_file(&device->dev, &dev_attr_tablet); | ||
805 | if (err) | ||
806 | goto add_sysfs_error; | ||
807 | return 0; | ||
808 | |||
584 | add_sysfs_error: | 809 | add_sysfs_error: |
585 | cleanup_sysfs(device); | 810 | cleanup_sysfs(device); |
586 | return err; | 811 | return err; |
@@ -588,8 +813,14 @@ add_sysfs_error: | |||
588 | 813 | ||
589 | static int __exit hp_wmi_bios_remove(struct platform_device *device) | 814 | static int __exit hp_wmi_bios_remove(struct platform_device *device) |
590 | { | 815 | { |
816 | int i; | ||
591 | cleanup_sysfs(device); | 817 | cleanup_sysfs(device); |
592 | 818 | ||
819 | for (i = 0; i < rfkill2_count; i++) { | ||
820 | rfkill_unregister(rfkill2[i].rfkill); | ||
821 | rfkill_destroy(rfkill2[i].rfkill); | ||
822 | } | ||
823 | |||
593 | if (wifi_rfkill) { | 824 | if (wifi_rfkill) { |
594 | rfkill_unregister(wifi_rfkill); | 825 | rfkill_unregister(wifi_rfkill); |
595 | rfkill_destroy(wifi_rfkill); | 826 | rfkill_destroy(wifi_rfkill); |
@@ -622,6 +853,9 @@ static int hp_wmi_resume_handler(struct device *device) | |||
622 | input_sync(hp_wmi_input_dev); | 853 | input_sync(hp_wmi_input_dev); |
623 | } | 854 | } |
624 | 855 | ||
856 | if (rfkill2_count) | ||
857 | hp_wmi_rfkill2_refresh(); | ||
858 | |||
625 | if (wifi_rfkill) | 859 | if (wifi_rfkill) |
626 | rfkill_set_states(wifi_rfkill, | 860 | rfkill_set_states(wifi_rfkill, |
627 | hp_wmi_get_sw_state(HPWMI_WIFI), | 861 | hp_wmi_get_sw_state(HPWMI_WIFI), |
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 114d95247cdf..21b101899bae 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
@@ -459,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) | |||
459 | if (test_bit(vpc_bit, &vpc1)) { | 459 | if (test_bit(vpc_bit, &vpc1)) { |
460 | if (vpc_bit == 9) | 460 | if (vpc_bit == 9) |
461 | ideapad_sync_rfk_state(adevice); | 461 | ideapad_sync_rfk_state(adevice); |
462 | else if (vpc_bit == 4) | ||
463 | read_ec_data(handle, 0x12, &vpc2); | ||
462 | else | 464 | else |
463 | ideapad_input_report(priv, vpc_bit); | 465 | ideapad_input_report(priv, vpc_bit); |
464 | } | 466 | } |
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 1294a39373ba..85c8ad43c0c5 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c | |||
@@ -1111,7 +1111,7 @@ static int ips_monitor(void *data) | |||
1111 | last_msecs = jiffies_to_msecs(jiffies); | 1111 | last_msecs = jiffies_to_msecs(jiffies); |
1112 | expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); | 1112 | expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); |
1113 | 1113 | ||
1114 | __set_current_state(TASK_UNINTERRUPTIBLE); | 1114 | __set_current_state(TASK_INTERRUPTIBLE); |
1115 | mod_timer(&timer, expire); | 1115 | mod_timer(&timer, expire); |
1116 | schedule(); | 1116 | schedule(); |
1117 | 1117 | ||
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c new file mode 100644 index 000000000000..213e79ba68d5 --- /dev/null +++ b/drivers/platform/x86/intel_mid_powerbtn.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Power button driver for Medfield. | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/input.h> | ||
26 | #include <asm/intel_scu_ipc.h> | ||
27 | |||
28 | #define DRIVER_NAME "msic_power_btn" | ||
29 | |||
30 | #define MSIC_IRQ_STAT 0x02 | ||
31 | #define MSIC_IRQ_PB (1 << 0) | ||
32 | #define MSIC_PB_CONFIG 0x3e | ||
33 | #define MSIC_PB_STATUS 0x3f | ||
34 | #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ | ||
35 | |||
36 | struct mfld_pb_priv { | ||
37 | struct input_dev *input; | ||
38 | unsigned int irq; | ||
39 | }; | ||
40 | |||
41 | static irqreturn_t mfld_pb_isr(int irq, void *dev_id) | ||
42 | { | ||
43 | struct mfld_pb_priv *priv = dev_id; | ||
44 | int ret; | ||
45 | u8 pbstat; | ||
46 | |||
47 | ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat); | ||
48 | if (ret < 0) | ||
49 | return IRQ_HANDLED; | ||
50 | |||
51 | input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL)); | ||
52 | input_sync(priv->input); | ||
53 | |||
54 | return IRQ_HANDLED; | ||
55 | } | ||
56 | |||
57 | static int __devinit mfld_pb_probe(struct platform_device *pdev) | ||
58 | { | ||
59 | struct mfld_pb_priv *priv; | ||
60 | struct input_dev *input; | ||
61 | int irq; | ||
62 | int error; | ||
63 | |||
64 | irq = platform_get_irq(pdev, 0); | ||
65 | if (irq < 0) | ||
66 | return -EINVAL; | ||
67 | |||
68 | priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL); | ||
69 | input = input_allocate_device(); | ||
70 | if (!priv || !input) { | ||
71 | error = -ENOMEM; | ||
72 | goto err_free_mem; | ||
73 | } | ||
74 | |||
75 | priv->input = input; | ||
76 | priv->irq = irq; | ||
77 | |||
78 | input->name = pdev->name; | ||
79 | input->phys = "power-button/input0"; | ||
80 | input->id.bustype = BUS_HOST; | ||
81 | input->dev.parent = &pdev->dev; | ||
82 | |||
83 | input_set_capability(input, EV_KEY, KEY_POWER); | ||
84 | |||
85 | error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr, | ||
86 | 0, DRIVER_NAME, priv); | ||
87 | if (error) { | ||
88 | dev_err(&pdev->dev, | ||
89 | "unable to request irq %d for mfld power button\n", | ||
90 | irq); | ||
91 | goto err_free_mem; | ||
92 | } | ||
93 | |||
94 | error = input_register_device(input); | ||
95 | if (error) { | ||
96 | dev_err(&pdev->dev, | ||
97 | "unable to register input dev, error %d\n", error); | ||
98 | goto err_free_irq; | ||
99 | } | ||
100 | |||
101 | platform_set_drvdata(pdev, priv); | ||
102 | return 0; | ||
103 | |||
104 | err_free_irq: | ||
105 | free_irq(priv->irq, priv); | ||
106 | err_free_mem: | ||
107 | input_free_device(input); | ||
108 | kfree(priv); | ||
109 | return error; | ||
110 | } | ||
111 | |||
112 | static int __devexit mfld_pb_remove(struct platform_device *pdev) | ||
113 | { | ||
114 | struct mfld_pb_priv *priv = platform_get_drvdata(pdev); | ||
115 | |||
116 | free_irq(priv->irq, priv); | ||
117 | input_unregister_device(priv->input); | ||
118 | kfree(priv); | ||
119 | |||
120 | platform_set_drvdata(pdev, NULL); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static struct platform_driver mfld_pb_driver = { | ||
125 | .driver = { | ||
126 | .name = DRIVER_NAME, | ||
127 | .owner = THIS_MODULE, | ||
128 | }, | ||
129 | .probe = mfld_pb_probe, | ||
130 | .remove = __devexit_p(mfld_pb_remove), | ||
131 | }; | ||
132 | |||
133 | static int __init mfld_pb_init(void) | ||
134 | { | ||
135 | return platform_driver_register(&mfld_pb_driver); | ||
136 | } | ||
137 | module_init(mfld_pb_init); | ||
138 | |||
139 | static void __exit mfld_pb_exit(void) | ||
140 | { | ||
141 | platform_driver_unregister(&mfld_pb_driver); | ||
142 | } | ||
143 | module_exit(mfld_pb_exit); | ||
144 | |||
145 | MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>"); | ||
146 | MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); | ||
147 | MODULE_LICENSE("GPL v2"); | ||
148 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c new file mode 100644 index 000000000000..6c12db503161 --- /dev/null +++ b/drivers/platform/x86/intel_mid_thermal.c | |||
@@ -0,0 +1,576 @@ | |||
1 | /* | ||
2 | * intel_mid_thermal.c - Intel MID platform thermal driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Intel Corporation | ||
5 | * | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
20 | * | ||
21 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
22 | * Author: Durgadoss R <durgadoss.r@intel.com> | ||
23 | */ | ||
24 | |||
25 | #define pr_fmt(fmt) "intel_mid_thermal: " fmt | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/err.h> | ||
30 | #include <linux/param.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/pm.h> | ||
35 | #include <linux/thermal.h> | ||
36 | |||
37 | #include <asm/intel_scu_ipc.h> | ||
38 | |||
39 | /* Number of thermal sensors */ | ||
40 | #define MSIC_THERMAL_SENSORS 4 | ||
41 | |||
42 | /* ADC1 - thermal registers */ | ||
43 | #define MSIC_THERM_ADC1CNTL1 0x1C0 | ||
44 | #define MSIC_ADC_ENBL 0x10 | ||
45 | #define MSIC_ADC_START 0x08 | ||
46 | |||
47 | #define MSIC_THERM_ADC1CNTL3 0x1C2 | ||
48 | #define MSIC_ADCTHERM_ENBL 0x04 | ||
49 | #define MSIC_ADCRRDATA_ENBL 0x05 | ||
50 | #define MSIC_CHANL_MASK_VAL 0x0F | ||
51 | |||
52 | #define MSIC_STOPBIT_MASK 16 | ||
53 | #define MSIC_ADCTHERM_MASK 4 | ||
54 | #define ADC_CHANLS_MAX 15 /* Number of ADC channels */ | ||
55 | #define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS) | ||
56 | |||
57 | /* ADC channel code values */ | ||
58 | #define SKIN_SENSOR0_CODE 0x08 | ||
59 | #define SKIN_SENSOR1_CODE 0x09 | ||
60 | #define SYS_SENSOR_CODE 0x0A | ||
61 | #define MSIC_DIE_SENSOR_CODE 0x03 | ||
62 | |||
63 | #define SKIN_THERM_SENSOR0 0 | ||
64 | #define SKIN_THERM_SENSOR1 1 | ||
65 | #define SYS_THERM_SENSOR2 2 | ||
66 | #define MSIC_DIE_THERM_SENSOR3 3 | ||
67 | |||
68 | /* ADC code range */ | ||
69 | #define ADC_MAX 977 | ||
70 | #define ADC_MIN 162 | ||
71 | #define ADC_VAL0C 887 | ||
72 | #define ADC_VAL20C 720 | ||
73 | #define ADC_VAL40C 508 | ||
74 | #define ADC_VAL60C 315 | ||
75 | |||
76 | /* ADC base addresses */ | ||
77 | #define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ | ||
78 | #define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ | ||
79 | |||
80 | /* MSIC die attributes */ | ||
81 | #define MSIC_DIE_ADC_MIN 488 | ||
82 | #define MSIC_DIE_ADC_MAX 1004 | ||
83 | |||
84 | /* This holds the address of the first free ADC channel, | ||
85 | * among the 15 channels | ||
86 | */ | ||
87 | static int channel_index; | ||
88 | |||
89 | struct platform_info { | ||
90 | struct platform_device *pdev; | ||
91 | struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS]; | ||
92 | }; | ||
93 | |||
94 | struct thermal_device_info { | ||
95 | unsigned int chnl_addr; | ||
96 | int direct; | ||
97 | /* This holds the current temperature in millidegree celsius */ | ||
98 | long curr_temp; | ||
99 | }; | ||
100 | |||
101 | /** | ||
102 | * to_msic_die_temp - converts adc_val to msic_die temperature | ||
103 | * @adc_val: ADC value to be converted | ||
104 | * | ||
105 | * Can sleep | ||
106 | */ | ||
107 | static int to_msic_die_temp(uint16_t adc_val) | ||
108 | { | ||
109 | return (368 * (adc_val) / 1000) - 220; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * is_valid_adc - checks whether the adc code is within the defined range | ||
114 | * @min: minimum value for the sensor | ||
115 | * @max: maximum value for the sensor | ||
116 | * | ||
117 | * Can sleep | ||
118 | */ | ||
119 | static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max) | ||
120 | { | ||
121 | return (adc_val >= min) && (adc_val <= max); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * adc_to_temp - converts the ADC code to temperature in C | ||
126 | * @direct: true if ths channel is direct index | ||
127 | * @adc_val: the adc_val that needs to be converted | ||
128 | * @tp: temperature return value | ||
129 | * | ||
130 | * Linear approximation is used to covert the skin adc value into temperature. | ||
131 | * This technique is used to avoid very long look-up table to get | ||
132 | * the appropriate temp value from ADC value. | ||
133 | * The adc code vs sensor temp curve is split into five parts | ||
134 | * to achieve very close approximate temp value with less than | ||
135 | * 0.5C error | ||
136 | */ | ||
137 | static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp) | ||
138 | { | ||
139 | int temp; | ||
140 | |||
141 | /* Direct conversion for die temperature */ | ||
142 | if (direct) { | ||
143 | if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) { | ||
144 | *tp = to_msic_die_temp(adc_val) * 1000; | ||
145 | return 0; | ||
146 | } | ||
147 | return -ERANGE; | ||
148 | } | ||
149 | |||
150 | if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX)) | ||
151 | return -ERANGE; | ||
152 | |||
153 | /* Linear approximation for skin temperature */ | ||
154 | if (adc_val > ADC_VAL0C) | ||
155 | temp = 177 - (adc_val/5); | ||
156 | else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C)) | ||
157 | temp = 111 - (adc_val/8); | ||
158 | else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C)) | ||
159 | temp = 92 - (adc_val/10); | ||
160 | else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C)) | ||
161 | temp = 91 - (adc_val/10); | ||
162 | else | ||
163 | temp = 112 - (adc_val/6); | ||
164 | |||
165 | /* Convert temperature in celsius to milli degree celsius */ | ||
166 | *tp = temp * 1000; | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * mid_read_temp - read sensors for temperature | ||
172 | * @temp: holds the current temperature for the sensor after reading | ||
173 | * | ||
174 | * reads the adc_code from the channel and converts it to real | ||
175 | * temperature. The converted value is stored in temp. | ||
176 | * | ||
177 | * Can sleep | ||
178 | */ | ||
179 | static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) | ||
180 | { | ||
181 | struct thermal_device_info *td_info = tzd->devdata; | ||
182 | uint16_t adc_val, addr; | ||
183 | uint8_t data = 0; | ||
184 | int ret; | ||
185 | unsigned long curr_temp; | ||
186 | |||
187 | |||
188 | addr = td_info->chnl_addr; | ||
189 | |||
190 | /* Enable the msic for conversion before reading */ | ||
191 | ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); | ||
192 | if (ret) | ||
193 | return ret; | ||
194 | |||
195 | /* Re-toggle the RRDATARD bit (temporary workaround) */ | ||
196 | ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL); | ||
197 | if (ret) | ||
198 | return ret; | ||
199 | |||
200 | /* Read the higher bits of data */ | ||
201 | ret = intel_scu_ipc_ioread8(addr, &data); | ||
202 | if (ret) | ||
203 | return ret; | ||
204 | |||
205 | /* Shift bits to accomodate the lower two data bits */ | ||
206 | adc_val = (data << 2); | ||
207 | addr++; | ||
208 | |||
209 | ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */ | ||
210 | if (ret) | ||
211 | return ret; | ||
212 | |||
213 | /* Adding lower two bits to the higher bits */ | ||
214 | data &= 03; | ||
215 | adc_val += data; | ||
216 | |||
217 | /* Convert ADC value to temperature */ | ||
218 | ret = adc_to_temp(td_info->direct, adc_val, &curr_temp); | ||
219 | if (ret == 0) | ||
220 | *temp = td_info->curr_temp = curr_temp; | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * configure_adc - enables/disables the ADC for conversion | ||
226 | * @val: zero: disables the ADC non-zero:enables the ADC | ||
227 | * | ||
228 | * Enable/Disable the ADC depending on the argument | ||
229 | * | ||
230 | * Can sleep | ||
231 | */ | ||
232 | static int configure_adc(int val) | ||
233 | { | ||
234 | int ret; | ||
235 | uint8_t data; | ||
236 | |||
237 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); | ||
238 | if (ret) | ||
239 | return ret; | ||
240 | |||
241 | if (val) { | ||
242 | /* Enable and start the ADC */ | ||
243 | data |= (MSIC_ADC_ENBL | MSIC_ADC_START); | ||
244 | } else { | ||
245 | /* Just stop the ADC */ | ||
246 | data &= (~MSIC_ADC_START); | ||
247 | } | ||
248 | |||
249 | return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * set_up_therm_channel - enable thermal channel for conversion | ||
254 | * @base_addr: index of free msic ADC channel | ||
255 | * | ||
256 | * Enable all the three channels for conversion | ||
257 | * | ||
258 | * Can sleep | ||
259 | */ | ||
260 | static int set_up_therm_channel(u16 base_addr) | ||
261 | { | ||
262 | int ret; | ||
263 | |||
264 | /* Enable all the sensor channels */ | ||
265 | ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE); | ||
266 | if (ret) | ||
267 | return ret; | ||
268 | |||
269 | ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE); | ||
270 | if (ret) | ||
271 | return ret; | ||
272 | |||
273 | ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE); | ||
274 | if (ret) | ||
275 | return ret; | ||
276 | |||
277 | /* Since this is the last channel, set the stop bit | ||
278 | to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ | ||
279 | ret = intel_scu_ipc_iowrite8(base_addr + 3, | ||
280 | (MSIC_DIE_SENSOR_CODE | 0x10)); | ||
281 | if (ret) | ||
282 | return ret; | ||
283 | |||
284 | /* Enable ADC and start it */ | ||
285 | return configure_adc(1); | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * reset_stopbit - sets the stop bit to 0 on the given channel | ||
290 | * @addr: address of the channel | ||
291 | * | ||
292 | * Can sleep | ||
293 | */ | ||
294 | static int reset_stopbit(uint16_t addr) | ||
295 | { | ||
296 | int ret; | ||
297 | uint8_t data; | ||
298 | ret = intel_scu_ipc_ioread8(addr, &data); | ||
299 | if (ret) | ||
300 | return ret; | ||
301 | /* Set the stop bit to zero */ | ||
302 | return intel_scu_ipc_iowrite8(addr, (data & 0xEF)); | ||
303 | } | ||
304 | |||
305 | /** | ||
306 | * find_free_channel - finds an empty channel for conversion | ||
307 | * | ||
308 | * If the ADC is not enabled then start using 0th channel | ||
309 | * itself. Otherwise find an empty channel by looking for a | ||
310 | * channel in which the stopbit is set to 1. returns the index | ||
311 | * of the first free channel if succeeds or an error code. | ||
312 | * | ||
313 | * Context: can sleep | ||
314 | * | ||
315 | * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc | ||
316 | * code. | ||
317 | */ | ||
318 | static int find_free_channel(void) | ||
319 | { | ||
320 | int ret; | ||
321 | int i; | ||
322 | uint8_t data; | ||
323 | |||
324 | /* check whether ADC is enabled */ | ||
325 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); | ||
326 | if (ret) | ||
327 | return ret; | ||
328 | |||
329 | if ((data & MSIC_ADC_ENBL) == 0) | ||
330 | return 0; | ||
331 | |||
332 | /* ADC is already enabled; Looking for an empty channel */ | ||
333 | for (i = 0; i < ADC_CHANLS_MAX; i++) { | ||
334 | ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data); | ||
335 | if (ret) | ||
336 | return ret; | ||
337 | |||
338 | if (data & MSIC_STOPBIT_MASK) { | ||
339 | ret = i; | ||
340 | break; | ||
341 | } | ||
342 | } | ||
343 | return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * mid_initialize_adc - initializing the ADC | ||
348 | * @dev: our device structure | ||
349 | * | ||
350 | * Initialize the ADC for reading thermistor values. Can sleep. | ||
351 | */ | ||
352 | static int mid_initialize_adc(struct device *dev) | ||
353 | { | ||
354 | u8 data; | ||
355 | u16 base_addr; | ||
356 | int ret; | ||
357 | |||
358 | /* | ||
359 | * Ensure that adctherm is disabled before we | ||
360 | * initialize the ADC | ||
361 | */ | ||
362 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data); | ||
363 | if (ret) | ||
364 | return ret; | ||
365 | |||
366 | if (data & MSIC_ADCTHERM_MASK) | ||
367 | dev_warn(dev, "ADCTHERM already set"); | ||
368 | |||
369 | /* Index of the first channel in which the stop bit is set */ | ||
370 | channel_index = find_free_channel(); | ||
371 | if (channel_index < 0) { | ||
372 | dev_err(dev, "No free ADC channels"); | ||
373 | return channel_index; | ||
374 | } | ||
375 | |||
376 | base_addr = ADC_CHNL_START_ADDR + channel_index; | ||
377 | |||
378 | if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { | ||
379 | /* Reset stop bit for channels other than 0 and 12 */ | ||
380 | ret = reset_stopbit(base_addr); | ||
381 | if (ret) | ||
382 | return ret; | ||
383 | |||
384 | /* Index of the first free channel */ | ||
385 | base_addr++; | ||
386 | channel_index++; | ||
387 | } | ||
388 | |||
389 | ret = set_up_therm_channel(base_addr); | ||
390 | if (ret) { | ||
391 | dev_err(dev, "unable to enable ADC"); | ||
392 | return ret; | ||
393 | } | ||
394 | dev_dbg(dev, "ADC initialization successful"); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | * initialize_sensor - sets default temp and timer ranges | ||
400 | * @index: index of the sensor | ||
401 | * | ||
402 | * Context: can sleep | ||
403 | */ | ||
404 | static struct thermal_device_info *initialize_sensor(int index) | ||
405 | { | ||
406 | struct thermal_device_info *td_info = | ||
407 | kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL); | ||
408 | |||
409 | if (!td_info) | ||
410 | return NULL; | ||
411 | |||
412 | /* Set the base addr of the channel for this sensor */ | ||
413 | td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index); | ||
414 | /* Sensor 3 is direct conversion */ | ||
415 | if (index == 3) | ||
416 | td_info->direct = 1; | ||
417 | return td_info; | ||
418 | } | ||
419 | |||
420 | /** | ||
421 | * mid_thermal_resume - resume routine | ||
422 | * @pdev: platform device structure | ||
423 | * | ||
424 | * mid thermal resume: re-initializes the adc. Can sleep. | ||
425 | */ | ||
426 | static int mid_thermal_resume(struct platform_device *pdev) | ||
427 | { | ||
428 | return mid_initialize_adc(&pdev->dev); | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * mid_thermal_suspend - suspend routine | ||
433 | * @pdev: platform device structure | ||
434 | * | ||
435 | * mid thermal suspend implements the suspend functionality | ||
436 | * by stopping the ADC. Can sleep. | ||
437 | */ | ||
438 | static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
439 | { | ||
440 | /* | ||
441 | * This just stops the ADC and does not disable it. | ||
442 | * temporary workaround until we have a generic ADC driver. | ||
443 | * If 0 is passed, it disables the ADC. | ||
444 | */ | ||
445 | return configure_adc(0); | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * read_curr_temp - reads the current temperature and stores in temp | ||
450 | * @temp: holds the current temperature value after reading | ||
451 | * | ||
452 | * Can sleep | ||
453 | */ | ||
454 | static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp) | ||
455 | { | ||
456 | WARN_ON(tzd == NULL); | ||
457 | return mid_read_temp(tzd, temp); | ||
458 | } | ||
459 | |||
460 | /* Can't be const */ | ||
461 | static struct thermal_zone_device_ops tzd_ops = { | ||
462 | .get_temp = read_curr_temp, | ||
463 | }; | ||
464 | |||
465 | |||
466 | /** | ||
467 | * mid_thermal_probe - mfld thermal initialize | ||
468 | * @pdev: platform device structure | ||
469 | * | ||
470 | * mid thermal probe initializes the hardware and registers | ||
471 | * all the sensors with the generic thermal framework. Can sleep. | ||
472 | */ | ||
473 | static int mid_thermal_probe(struct platform_device *pdev) | ||
474 | { | ||
475 | static char *name[MSIC_THERMAL_SENSORS] = { | ||
476 | "skin0", "skin1", "sys", "msicdie" | ||
477 | }; | ||
478 | |||
479 | int ret; | ||
480 | int i; | ||
481 | struct platform_info *pinfo; | ||
482 | |||
483 | pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL); | ||
484 | if (!pinfo) | ||
485 | return -ENOMEM; | ||
486 | |||
487 | /* Initializing the hardware */ | ||
488 | ret = mid_initialize_adc(&pdev->dev); | ||
489 | if (ret) { | ||
490 | dev_err(&pdev->dev, "ADC init failed"); | ||
491 | kfree(pinfo); | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | /* Register each sensor with the generic thermal framework*/ | ||
496 | for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { | ||
497 | pinfo->tzd[i] = thermal_zone_device_register(name[i], | ||
498 | 0, initialize_sensor(i), | ||
499 | &tzd_ops, 0, 0, 0, 0); | ||
500 | if (IS_ERR(pinfo->tzd[i])) | ||
501 | goto reg_fail; | ||
502 | } | ||
503 | |||
504 | pinfo->pdev = pdev; | ||
505 | platform_set_drvdata(pdev, pinfo); | ||
506 | return 0; | ||
507 | |||
508 | reg_fail: | ||
509 | ret = PTR_ERR(pinfo->tzd[i]); | ||
510 | while (--i >= 0) | ||
511 | thermal_zone_device_unregister(pinfo->tzd[i]); | ||
512 | configure_adc(0); | ||
513 | kfree(pinfo); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * mid_thermal_remove - mfld thermal finalize | ||
519 | * @dev: platform device structure | ||
520 | * | ||
521 | * MLFD thermal remove unregisters all the sensors from the generic | ||
522 | * thermal framework. Can sleep. | ||
523 | */ | ||
524 | static int mid_thermal_remove(struct platform_device *pdev) | ||
525 | { | ||
526 | int i; | ||
527 | struct platform_info *pinfo = platform_get_drvdata(pdev); | ||
528 | |||
529 | for (i = 0; i < MSIC_THERMAL_SENSORS; i++) | ||
530 | thermal_zone_device_unregister(pinfo->tzd[i]); | ||
531 | |||
532 | platform_set_drvdata(pdev, NULL); | ||
533 | |||
534 | /* Stop the ADC */ | ||
535 | return configure_adc(0); | ||
536 | } | ||
537 | |||
538 | /********************************************************************* | ||
539 | * Driver initialisation and finalization | ||
540 | *********************************************************************/ | ||
541 | |||
542 | #define DRIVER_NAME "msic_sensor" | ||
543 | |||
544 | static const struct platform_device_id therm_id_table[] = { | ||
545 | { DRIVER_NAME, 1 }, | ||
546 | { } | ||
547 | }; | ||
548 | |||
549 | static struct platform_driver mid_thermal_driver = { | ||
550 | .driver = { | ||
551 | .name = DRIVER_NAME, | ||
552 | .owner = THIS_MODULE, | ||
553 | }, | ||
554 | .probe = mid_thermal_probe, | ||
555 | .suspend = mid_thermal_suspend, | ||
556 | .resume = mid_thermal_resume, | ||
557 | .remove = __devexit_p(mid_thermal_remove), | ||
558 | .id_table = therm_id_table, | ||
559 | }; | ||
560 | |||
561 | static int __init mid_thermal_module_init(void) | ||
562 | { | ||
563 | return platform_driver_register(&mid_thermal_driver); | ||
564 | } | ||
565 | |||
566 | static void __exit mid_thermal_module_exit(void) | ||
567 | { | ||
568 | platform_driver_unregister(&mid_thermal_driver); | ||
569 | } | ||
570 | |||
571 | module_init(mid_thermal_module_init); | ||
572 | module_exit(mid_thermal_module_exit); | ||
573 | |||
574 | MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>"); | ||
575 | MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver"); | ||
576 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 61433d492862..d653104b59cb 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c | |||
@@ -257,9 +257,11 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) | |||
257 | } | 257 | } |
258 | 258 | ||
259 | for (i = 0; i < 8; i++) { | 259 | for (i = 0; i < 8; i++) { |
260 | set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip, | 260 | irq_set_chip_and_handler_name(i + pg->irq_base, |
261 | handle_simple_irq, "demux"); | 261 | &pmic_irqchip, |
262 | set_irq_chip_data(i + pg->irq_base, pg); | 262 | handle_simple_irq, |
263 | "demux"); | ||
264 | irq_set_chip_data(i + pg->irq_base, pg); | ||
263 | } | 265 | } |
264 | return 0; | 266 | return 0; |
265 | err: | 267 | err: |
diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c index 2b11a33325e6..bde47e9080cd 100644 --- a/drivers/platform/x86/intel_rar_register.c +++ b/drivers/platform/x86/intel_rar_register.c | |||
@@ -485,7 +485,7 @@ EXPORT_SYMBOL(rar_lock); | |||
485 | * | 485 | * |
486 | * The register_rar function is to used by other device drivers | 486 | * The register_rar function is to used by other device drivers |
487 | * to ensure that this driver is ready. As we cannot be sure of | 487 | * to ensure that this driver is ready. As we cannot be sure of |
488 | * the compile/execute order of drivers in ther kernel, it is | 488 | * the compile/execute order of drivers in the kernel, it is |
489 | * best to give this driver a callback function to call when | 489 | * best to give this driver a callback function to call when |
490 | * it is ready to give out addresses. The callback function | 490 | * it is ready to give out addresses. The callback function |
491 | * would have those steps that continue the initialization of | 491 | * would have those steps that continue the initialization of |
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index a91d510a798b..940accbe28d3 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * as published by the Free Software Foundation; version 2 | 9 | * as published by the Free Software Foundation; version 2 |
10 | * of the License. | 10 | * of the License. |
11 | * | 11 | * |
12 | * SCU runing in ARC processor communicates with other entity running in IA | 12 | * SCU running in ARC processor communicates with other entity running in IA |
13 | * core through IPC mechanism which in turn messaging between IA core ad SCU. | 13 | * core through IPC mechanism which in turn messaging between IA core ad SCU. |
14 | * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and | 14 | * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and |
15 | * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with | 15 | * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with |
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 142d38579314..23fb2afda00b 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c | |||
@@ -51,6 +51,8 @@ | |||
51 | * laptop as MSI S270. YMMV. | 51 | * laptop as MSI S270. YMMV. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
55 | |||
54 | #include <linux/module.h> | 56 | #include <linux/module.h> |
55 | #include <linux/kernel.h> | 57 | #include <linux/kernel.h> |
56 | #include <linux/init.h> | 58 | #include <linux/init.h> |
@@ -60,6 +62,8 @@ | |||
60 | #include <linux/platform_device.h> | 62 | #include <linux/platform_device.h> |
61 | #include <linux/rfkill.h> | 63 | #include <linux/rfkill.h> |
62 | #include <linux/i8042.h> | 64 | #include <linux/i8042.h> |
65 | #include <linux/input.h> | ||
66 | #include <linux/input/sparse-keymap.h> | ||
63 | 67 | ||
64 | #define MSI_DRIVER_VERSION "0.5" | 68 | #define MSI_DRIVER_VERSION "0.5" |
65 | 69 | ||
@@ -78,6 +82,9 @@ | |||
78 | #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d | 82 | #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d |
79 | #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) | 83 | #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) |
80 | 84 | ||
85 | #define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4 | ||
86 | #define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4) | ||
87 | |||
81 | static int msi_laptop_resume(struct platform_device *device); | 88 | static int msi_laptop_resume(struct platform_device *device); |
82 | 89 | ||
83 | #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f | 90 | #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f |
@@ -90,6 +97,14 @@ static int auto_brightness; | |||
90 | module_param(auto_brightness, int, 0); | 97 | module_param(auto_brightness, int, 0); |
91 | MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); | 98 | MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); |
92 | 99 | ||
100 | static const struct key_entry msi_laptop_keymap[] = { | ||
101 | {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */ | ||
102 | {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */ | ||
103 | {KE_END, 0} | ||
104 | }; | ||
105 | |||
106 | static struct input_dev *msi_laptop_input_dev; | ||
107 | |||
93 | static bool old_ec_model; | 108 | static bool old_ec_model; |
94 | static int wlan_s, bluetooth_s, threeg_s; | 109 | static int wlan_s, bluetooth_s, threeg_s; |
95 | static int threeg_exists; | 110 | static int threeg_exists; |
@@ -432,8 +447,7 @@ static struct platform_device *msipf_device; | |||
432 | 447 | ||
433 | static int dmi_check_cb(const struct dmi_system_id *id) | 448 | static int dmi_check_cb(const struct dmi_system_id *id) |
434 | { | 449 | { |
435 | printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", | 450 | pr_info("Identified laptop model '%s'.\n", id->ident); |
436 | id->ident); | ||
437 | return 1; | 451 | return 1; |
438 | } | 452 | } |
439 | 453 | ||
@@ -605,6 +619,21 @@ static void msi_update_rfkill(struct work_struct *ignored) | |||
605 | } | 619 | } |
606 | static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); | 620 | static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); |
607 | 621 | ||
622 | static void msi_send_touchpad_key(struct work_struct *ignored) | ||
623 | { | ||
624 | u8 rdata; | ||
625 | int result; | ||
626 | |||
627 | result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata); | ||
628 | if (result < 0) | ||
629 | return; | ||
630 | |||
631 | sparse_keymap_report_event(msi_laptop_input_dev, | ||
632 | (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? | ||
633 | KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); | ||
634 | } | ||
635 | static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); | ||
636 | |||
608 | static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, | 637 | static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, |
609 | struct serio *port) | 638 | struct serio *port) |
610 | { | 639 | { |
@@ -613,12 +642,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, | |||
613 | if (str & 0x20) | 642 | if (str & 0x20) |
614 | return false; | 643 | return false; |
615 | 644 | ||
616 | /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ | 645 | /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/ |
617 | if (unlikely(data == 0xe0)) { | 646 | if (unlikely(data == 0xe0)) { |
618 | extended = true; | 647 | extended = true; |
619 | return false; | 648 | return false; |
620 | } else if (unlikely(extended)) { | 649 | } else if (unlikely(extended)) { |
650 | extended = false; | ||
621 | switch (data) { | 651 | switch (data) { |
652 | case 0xE4: | ||
653 | schedule_delayed_work(&msi_touchpad_work, | ||
654 | round_jiffies_relative(0.5 * HZ)); | ||
655 | break; | ||
622 | case 0x54: | 656 | case 0x54: |
623 | case 0x62: | 657 | case 0x62: |
624 | case 0x76: | 658 | case 0x76: |
@@ -626,7 +660,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, | |||
626 | round_jiffies_relative(0.5 * HZ)); | 660 | round_jiffies_relative(0.5 * HZ)); |
627 | break; | 661 | break; |
628 | } | 662 | } |
629 | extended = false; | ||
630 | } | 663 | } |
631 | 664 | ||
632 | return false; | 665 | return false; |
@@ -731,6 +764,42 @@ static int msi_laptop_resume(struct platform_device *device) | |||
731 | return 0; | 764 | return 0; |
732 | } | 765 | } |
733 | 766 | ||
767 | static int __init msi_laptop_input_setup(void) | ||
768 | { | ||
769 | int err; | ||
770 | |||
771 | msi_laptop_input_dev = input_allocate_device(); | ||
772 | if (!msi_laptop_input_dev) | ||
773 | return -ENOMEM; | ||
774 | |||
775 | msi_laptop_input_dev->name = "MSI Laptop hotkeys"; | ||
776 | msi_laptop_input_dev->phys = "msi-laptop/input0"; | ||
777 | msi_laptop_input_dev->id.bustype = BUS_HOST; | ||
778 | |||
779 | err = sparse_keymap_setup(msi_laptop_input_dev, | ||
780 | msi_laptop_keymap, NULL); | ||
781 | if (err) | ||
782 | goto err_free_dev; | ||
783 | |||
784 | err = input_register_device(msi_laptop_input_dev); | ||
785 | if (err) | ||
786 | goto err_free_keymap; | ||
787 | |||
788 | return 0; | ||
789 | |||
790 | err_free_keymap: | ||
791 | sparse_keymap_free(msi_laptop_input_dev); | ||
792 | err_free_dev: | ||
793 | input_free_device(msi_laptop_input_dev); | ||
794 | return err; | ||
795 | } | ||
796 | |||
797 | static void msi_laptop_input_destroy(void) | ||
798 | { | ||
799 | sparse_keymap_free(msi_laptop_input_dev); | ||
800 | input_unregister_device(msi_laptop_input_dev); | ||
801 | } | ||
802 | |||
734 | static int load_scm_model_init(struct platform_device *sdev) | 803 | static int load_scm_model_init(struct platform_device *sdev) |
735 | { | 804 | { |
736 | u8 data; | 805 | u8 data; |
@@ -759,16 +828,23 @@ static int load_scm_model_init(struct platform_device *sdev) | |||
759 | if (result < 0) | 828 | if (result < 0) |
760 | goto fail_rfkill; | 829 | goto fail_rfkill; |
761 | 830 | ||
831 | /* setup input device */ | ||
832 | result = msi_laptop_input_setup(); | ||
833 | if (result) | ||
834 | goto fail_input; | ||
835 | |||
762 | result = i8042_install_filter(msi_laptop_i8042_filter); | 836 | result = i8042_install_filter(msi_laptop_i8042_filter); |
763 | if (result) { | 837 | if (result) { |
764 | printk(KERN_ERR | 838 | pr_err("Unable to install key filter\n"); |
765 | "msi-laptop: Unable to install key filter\n"); | ||
766 | goto fail_filter; | 839 | goto fail_filter; |
767 | } | 840 | } |
768 | 841 | ||
769 | return 0; | 842 | return 0; |
770 | 843 | ||
771 | fail_filter: | 844 | fail_filter: |
845 | msi_laptop_input_destroy(); | ||
846 | |||
847 | fail_input: | ||
772 | rfkill_cleanup(); | 848 | rfkill_cleanup(); |
773 | 849 | ||
774 | fail_rfkill: | 850 | fail_rfkill: |
@@ -799,7 +875,7 @@ static int __init msi_init(void) | |||
799 | /* Register backlight stuff */ | 875 | /* Register backlight stuff */ |
800 | 876 | ||
801 | if (acpi_video_backlight_support()) { | 877 | if (acpi_video_backlight_support()) { |
802 | printk(KERN_INFO "MSI: Brightness ignored, must be controlled " | 878 | pr_info("Brightness ignored, must be controlled " |
803 | "by ACPI video driver\n"); | 879 | "by ACPI video driver\n"); |
804 | } else { | 880 | } else { |
805 | struct backlight_properties props; | 881 | struct backlight_properties props; |
@@ -854,7 +930,7 @@ static int __init msi_init(void) | |||
854 | if (auto_brightness != 2) | 930 | if (auto_brightness != 2) |
855 | set_auto_brightness(auto_brightness); | 931 | set_auto_brightness(auto_brightness); |
856 | 932 | ||
857 | printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); | 933 | pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n"); |
858 | 934 | ||
859 | return 0; | 935 | return 0; |
860 | 936 | ||
@@ -886,6 +962,7 @@ static void __exit msi_cleanup(void) | |||
886 | { | 962 | { |
887 | if (load_scm_model) { | 963 | if (load_scm_model) { |
888 | i8042_remove_filter(msi_laptop_i8042_filter); | 964 | i8042_remove_filter(msi_laptop_i8042_filter); |
965 | msi_laptop_input_destroy(); | ||
889 | cancel_delayed_work_sync(&msi_rfkill_work); | 966 | cancel_delayed_work_sync(&msi_rfkill_work); |
890 | rfkill_cleanup(); | 967 | rfkill_cleanup(); |
891 | } | 968 | } |
@@ -901,7 +978,7 @@ static void __exit msi_cleanup(void) | |||
901 | if (auto_brightness != 2) | 978 | if (auto_brightness != 2) |
902 | set_auto_brightness(1); | 979 | set_auto_brightness(1); |
903 | 980 | ||
904 | printk(KERN_INFO "msi-laptop: driver unloaded.\n"); | 981 | pr_info("driver unloaded.\n"); |
905 | } | 982 | } |
906 | 983 | ||
907 | module_init(msi_init); | 984 | module_init(msi_init); |
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c new file mode 100644 index 000000000000..de434c6dc2d6 --- /dev/null +++ b/drivers/platform/x86/samsung-laptop.c | |||
@@ -0,0 +1,832 @@ | |||
1 | /* | ||
2 | * Samsung Laptop driver | ||
3 | * | ||
4 | * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) | ||
5 | * Copyright (C) 2009,2011 Novell Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | */ | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/backlight.h> | ||
20 | #include <linux/fb.h> | ||
21 | #include <linux/dmi.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/rfkill.h> | ||
24 | |||
25 | /* | ||
26 | * This driver is needed because a number of Samsung laptops do not hook | ||
27 | * their control settings through ACPI. So we have to poke around in the | ||
28 | * BIOS to do things like brightness values, and "special" key controls. | ||
29 | */ | ||
30 | |||
31 | /* | ||
32 | * We have 0 - 8 as valid brightness levels. The specs say that level 0 should | ||
33 | * be reserved by the BIOS (which really doesn't make much sense), we tell | ||
34 | * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8 | ||
35 | */ | ||
36 | #define MAX_BRIGHT 0x07 | ||
37 | |||
38 | |||
39 | #define SABI_IFACE_MAIN 0x00 | ||
40 | #define SABI_IFACE_SUB 0x02 | ||
41 | #define SABI_IFACE_COMPLETE 0x04 | ||
42 | #define SABI_IFACE_DATA 0x05 | ||
43 | |||
44 | /* Structure to get data back to the calling function */ | ||
45 | struct sabi_retval { | ||
46 | u8 retval[20]; | ||
47 | }; | ||
48 | |||
49 | struct sabi_header_offsets { | ||
50 | u8 port; | ||
51 | u8 re_mem; | ||
52 | u8 iface_func; | ||
53 | u8 en_mem; | ||
54 | u8 data_offset; | ||
55 | u8 data_segment; | ||
56 | }; | ||
57 | |||
58 | struct sabi_commands { | ||
59 | /* | ||
60 | * Brightness is 0 - 8, as described above. | ||
61 | * Value 0 is for the BIOS to use | ||
62 | */ | ||
63 | u8 get_brightness; | ||
64 | u8 set_brightness; | ||
65 | |||
66 | /* | ||
67 | * first byte: | ||
68 | * 0x00 - wireless is off | ||
69 | * 0x01 - wireless is on | ||
70 | * second byte: | ||
71 | * 0x02 - 3G is off | ||
72 | * 0x03 - 3G is on | ||
73 | * TODO, verify 3G is correct, that doesn't seem right... | ||
74 | */ | ||
75 | u8 get_wireless_button; | ||
76 | u8 set_wireless_button; | ||
77 | |||
78 | /* 0 is off, 1 is on */ | ||
79 | u8 get_backlight; | ||
80 | u8 set_backlight; | ||
81 | |||
82 | /* | ||
83 | * 0x80 or 0x00 - no action | ||
84 | * 0x81 - recovery key pressed | ||
85 | */ | ||
86 | u8 get_recovery_mode; | ||
87 | u8 set_recovery_mode; | ||
88 | |||
89 | /* | ||
90 | * on seclinux: 0 is low, 1 is high, | ||
91 | * on swsmi: 0 is normal, 1 is silent, 2 is turbo | ||
92 | */ | ||
93 | u8 get_performance_level; | ||
94 | u8 set_performance_level; | ||
95 | |||
96 | /* | ||
97 | * Tell the BIOS that Linux is running on this machine. | ||
98 | * 81 is on, 80 is off | ||
99 | */ | ||
100 | u8 set_linux; | ||
101 | }; | ||
102 | |||
103 | struct sabi_performance_level { | ||
104 | const char *name; | ||
105 | u8 value; | ||
106 | }; | ||
107 | |||
108 | struct sabi_config { | ||
109 | const char *test_string; | ||
110 | u16 main_function; | ||
111 | const struct sabi_header_offsets header_offsets; | ||
112 | const struct sabi_commands commands; | ||
113 | const struct sabi_performance_level performance_levels[4]; | ||
114 | u8 min_brightness; | ||
115 | u8 max_brightness; | ||
116 | }; | ||
117 | |||
118 | static const struct sabi_config sabi_configs[] = { | ||
119 | { | ||
120 | .test_string = "SECLINUX", | ||
121 | |||
122 | .main_function = 0x4c49, | ||
123 | |||
124 | .header_offsets = { | ||
125 | .port = 0x00, | ||
126 | .re_mem = 0x02, | ||
127 | .iface_func = 0x03, | ||
128 | .en_mem = 0x04, | ||
129 | .data_offset = 0x05, | ||
130 | .data_segment = 0x07, | ||
131 | }, | ||
132 | |||
133 | .commands = { | ||
134 | .get_brightness = 0x00, | ||
135 | .set_brightness = 0x01, | ||
136 | |||
137 | .get_wireless_button = 0x02, | ||
138 | .set_wireless_button = 0x03, | ||
139 | |||
140 | .get_backlight = 0x04, | ||
141 | .set_backlight = 0x05, | ||
142 | |||
143 | .get_recovery_mode = 0x06, | ||
144 | .set_recovery_mode = 0x07, | ||
145 | |||
146 | .get_performance_level = 0x08, | ||
147 | .set_performance_level = 0x09, | ||
148 | |||
149 | .set_linux = 0x0a, | ||
150 | }, | ||
151 | |||
152 | .performance_levels = { | ||
153 | { | ||
154 | .name = "silent", | ||
155 | .value = 0, | ||
156 | }, | ||
157 | { | ||
158 | .name = "normal", | ||
159 | .value = 1, | ||
160 | }, | ||
161 | { }, | ||
162 | }, | ||
163 | .min_brightness = 1, | ||
164 | .max_brightness = 8, | ||
165 | }, | ||
166 | { | ||
167 | .test_string = "SwSmi@", | ||
168 | |||
169 | .main_function = 0x5843, | ||
170 | |||
171 | .header_offsets = { | ||
172 | .port = 0x00, | ||
173 | .re_mem = 0x04, | ||
174 | .iface_func = 0x02, | ||
175 | .en_mem = 0x03, | ||
176 | .data_offset = 0x05, | ||
177 | .data_segment = 0x07, | ||
178 | }, | ||
179 | |||
180 | .commands = { | ||
181 | .get_brightness = 0x10, | ||
182 | .set_brightness = 0x11, | ||
183 | |||
184 | .get_wireless_button = 0x12, | ||
185 | .set_wireless_button = 0x13, | ||
186 | |||
187 | .get_backlight = 0x2d, | ||
188 | .set_backlight = 0x2e, | ||
189 | |||
190 | .get_recovery_mode = 0xff, | ||
191 | .set_recovery_mode = 0xff, | ||
192 | |||
193 | .get_performance_level = 0x31, | ||
194 | .set_performance_level = 0x32, | ||
195 | |||
196 | .set_linux = 0xff, | ||
197 | }, | ||
198 | |||
199 | .performance_levels = { | ||
200 | { | ||
201 | .name = "normal", | ||
202 | .value = 0, | ||
203 | }, | ||
204 | { | ||
205 | .name = "silent", | ||
206 | .value = 1, | ||
207 | }, | ||
208 | { | ||
209 | .name = "overclock", | ||
210 | .value = 2, | ||
211 | }, | ||
212 | { }, | ||
213 | }, | ||
214 | .min_brightness = 0, | ||
215 | .max_brightness = 8, | ||
216 | }, | ||
217 | { }, | ||
218 | }; | ||
219 | |||
220 | static const struct sabi_config *sabi_config; | ||
221 | |||
222 | static void __iomem *sabi; | ||
223 | static void __iomem *sabi_iface; | ||
224 | static void __iomem *f0000_segment; | ||
225 | static struct backlight_device *backlight_device; | ||
226 | static struct mutex sabi_mutex; | ||
227 | static struct platform_device *sdev; | ||
228 | static struct rfkill *rfk; | ||
229 | |||
230 | static int force; | ||
231 | module_param(force, bool, 0); | ||
232 | MODULE_PARM_DESC(force, | ||
233 | "Disable the DMI check and forces the driver to be loaded"); | ||
234 | |||
235 | static int debug; | ||
236 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
237 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
238 | |||
239 | static int sabi_get_command(u8 command, struct sabi_retval *sretval) | ||
240 | { | ||
241 | int retval = 0; | ||
242 | u16 port = readw(sabi + sabi_config->header_offsets.port); | ||
243 | u8 complete, iface_data; | ||
244 | |||
245 | mutex_lock(&sabi_mutex); | ||
246 | |||
247 | /* enable memory to be able to write to it */ | ||
248 | outb(readb(sabi + sabi_config->header_offsets.en_mem), port); | ||
249 | |||
250 | /* write out the command */ | ||
251 | writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); | ||
252 | writew(command, sabi_iface + SABI_IFACE_SUB); | ||
253 | writeb(0, sabi_iface + SABI_IFACE_COMPLETE); | ||
254 | outb(readb(sabi + sabi_config->header_offsets.iface_func), port); | ||
255 | |||
256 | /* write protect memory to make it safe */ | ||
257 | outb(readb(sabi + sabi_config->header_offsets.re_mem), port); | ||
258 | |||
259 | /* see if the command actually succeeded */ | ||
260 | complete = readb(sabi_iface + SABI_IFACE_COMPLETE); | ||
261 | iface_data = readb(sabi_iface + SABI_IFACE_DATA); | ||
262 | if (complete != 0xaa || iface_data == 0xff) { | ||
263 | pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", | ||
264 | command, complete, iface_data); | ||
265 | retval = -EINVAL; | ||
266 | goto exit; | ||
267 | } | ||
268 | /* | ||
269 | * Save off the data into a structure so the caller use it. | ||
270 | * Right now we only want the first 4 bytes, | ||
271 | * There are commands that need more, but not for the ones we | ||
272 | * currently care about. | ||
273 | */ | ||
274 | sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA); | ||
275 | sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1); | ||
276 | sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2); | ||
277 | sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3); | ||
278 | |||
279 | exit: | ||
280 | mutex_unlock(&sabi_mutex); | ||
281 | return retval; | ||
282 | |||
283 | } | ||
284 | |||
285 | static int sabi_set_command(u8 command, u8 data) | ||
286 | { | ||
287 | int retval = 0; | ||
288 | u16 port = readw(sabi + sabi_config->header_offsets.port); | ||
289 | u8 complete, iface_data; | ||
290 | |||
291 | mutex_lock(&sabi_mutex); | ||
292 | |||
293 | /* enable memory to be able to write to it */ | ||
294 | outb(readb(sabi + sabi_config->header_offsets.en_mem), port); | ||
295 | |||
296 | /* write out the command */ | ||
297 | writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); | ||
298 | writew(command, sabi_iface + SABI_IFACE_SUB); | ||
299 | writeb(0, sabi_iface + SABI_IFACE_COMPLETE); | ||
300 | writeb(data, sabi_iface + SABI_IFACE_DATA); | ||
301 | outb(readb(sabi + sabi_config->header_offsets.iface_func), port); | ||
302 | |||
303 | /* write protect memory to make it safe */ | ||
304 | outb(readb(sabi + sabi_config->header_offsets.re_mem), port); | ||
305 | |||
306 | /* see if the command actually succeeded */ | ||
307 | complete = readb(sabi_iface + SABI_IFACE_COMPLETE); | ||
308 | iface_data = readb(sabi_iface + SABI_IFACE_DATA); | ||
309 | if (complete != 0xaa || iface_data == 0xff) { | ||
310 | pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", | ||
311 | command, complete, iface_data); | ||
312 | retval = -EINVAL; | ||
313 | } | ||
314 | |||
315 | mutex_unlock(&sabi_mutex); | ||
316 | return retval; | ||
317 | } | ||
318 | |||
319 | static void test_backlight(void) | ||
320 | { | ||
321 | struct sabi_retval sretval; | ||
322 | |||
323 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
324 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
325 | |||
326 | sabi_set_command(sabi_config->commands.set_backlight, 0); | ||
327 | printk(KERN_DEBUG "backlight should be off\n"); | ||
328 | |||
329 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
330 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
331 | |||
332 | msleep(1000); | ||
333 | |||
334 | sabi_set_command(sabi_config->commands.set_backlight, 1); | ||
335 | printk(KERN_DEBUG "backlight should be on\n"); | ||
336 | |||
337 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
338 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
339 | } | ||
340 | |||
341 | static void test_wireless(void) | ||
342 | { | ||
343 | struct sabi_retval sretval; | ||
344 | |||
345 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
346 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
347 | |||
348 | sabi_set_command(sabi_config->commands.set_wireless_button, 0); | ||
349 | printk(KERN_DEBUG "wireless led should be off\n"); | ||
350 | |||
351 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
352 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
353 | |||
354 | msleep(1000); | ||
355 | |||
356 | sabi_set_command(sabi_config->commands.set_wireless_button, 1); | ||
357 | printk(KERN_DEBUG "wireless led should be on\n"); | ||
358 | |||
359 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
360 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
361 | } | ||
362 | |||
363 | static u8 read_brightness(void) | ||
364 | { | ||
365 | struct sabi_retval sretval; | ||
366 | int user_brightness = 0; | ||
367 | int retval; | ||
368 | |||
369 | retval = sabi_get_command(sabi_config->commands.get_brightness, | ||
370 | &sretval); | ||
371 | if (!retval) { | ||
372 | user_brightness = sretval.retval[0]; | ||
373 | if (user_brightness != 0) | ||
374 | user_brightness -= sabi_config->min_brightness; | ||
375 | } | ||
376 | return user_brightness; | ||
377 | } | ||
378 | |||
379 | static void set_brightness(u8 user_brightness) | ||
380 | { | ||
381 | u8 user_level = user_brightness - sabi_config->min_brightness; | ||
382 | |||
383 | sabi_set_command(sabi_config->commands.set_brightness, user_level); | ||
384 | } | ||
385 | |||
386 | static int get_brightness(struct backlight_device *bd) | ||
387 | { | ||
388 | return (int)read_brightness(); | ||
389 | } | ||
390 | |||
391 | static int update_status(struct backlight_device *bd) | ||
392 | { | ||
393 | set_brightness(bd->props.brightness); | ||
394 | |||
395 | if (bd->props.power == FB_BLANK_UNBLANK) | ||
396 | sabi_set_command(sabi_config->commands.set_backlight, 1); | ||
397 | else | ||
398 | sabi_set_command(sabi_config->commands.set_backlight, 0); | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static const struct backlight_ops backlight_ops = { | ||
403 | .get_brightness = get_brightness, | ||
404 | .update_status = update_status, | ||
405 | }; | ||
406 | |||
407 | static int rfkill_set(void *data, bool blocked) | ||
408 | { | ||
409 | /* Do something with blocked...*/ | ||
410 | /* | ||
411 | * blocked == false is on | ||
412 | * blocked == true is off | ||
413 | */ | ||
414 | if (blocked) | ||
415 | sabi_set_command(sabi_config->commands.set_wireless_button, 0); | ||
416 | else | ||
417 | sabi_set_command(sabi_config->commands.set_wireless_button, 1); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static struct rfkill_ops rfkill_ops = { | ||
423 | .set_block = rfkill_set, | ||
424 | }; | ||
425 | |||
426 | static int init_wireless(struct platform_device *sdev) | ||
427 | { | ||
428 | int retval; | ||
429 | |||
430 | rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, | ||
431 | &rfkill_ops, NULL); | ||
432 | if (!rfk) | ||
433 | return -ENOMEM; | ||
434 | |||
435 | retval = rfkill_register(rfk); | ||
436 | if (retval) { | ||
437 | rfkill_destroy(rfk); | ||
438 | return -ENODEV; | ||
439 | } | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static void destroy_wireless(void) | ||
445 | { | ||
446 | rfkill_unregister(rfk); | ||
447 | rfkill_destroy(rfk); | ||
448 | } | ||
449 | |||
450 | static ssize_t get_performance_level(struct device *dev, | ||
451 | struct device_attribute *attr, char *buf) | ||
452 | { | ||
453 | struct sabi_retval sretval; | ||
454 | int retval; | ||
455 | int i; | ||
456 | |||
457 | /* Read the state */ | ||
458 | retval = sabi_get_command(sabi_config->commands.get_performance_level, | ||
459 | &sretval); | ||
460 | if (retval) | ||
461 | return retval; | ||
462 | |||
463 | /* The logic is backwards, yeah, lots of fun... */ | ||
464 | for (i = 0; sabi_config->performance_levels[i].name; ++i) { | ||
465 | if (sretval.retval[0] == sabi_config->performance_levels[i].value) | ||
466 | return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); | ||
467 | } | ||
468 | return sprintf(buf, "%s\n", "unknown"); | ||
469 | } | ||
470 | |||
471 | static ssize_t set_performance_level(struct device *dev, | ||
472 | struct device_attribute *attr, const char *buf, | ||
473 | size_t count) | ||
474 | { | ||
475 | if (count >= 1) { | ||
476 | int i; | ||
477 | for (i = 0; sabi_config->performance_levels[i].name; ++i) { | ||
478 | const struct sabi_performance_level *level = | ||
479 | &sabi_config->performance_levels[i]; | ||
480 | if (!strncasecmp(level->name, buf, strlen(level->name))) { | ||
481 | sabi_set_command(sabi_config->commands.set_performance_level, | ||
482 | level->value); | ||
483 | break; | ||
484 | } | ||
485 | } | ||
486 | if (!sabi_config->performance_levels[i].name) | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | return count; | ||
490 | } | ||
491 | static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, | ||
492 | get_performance_level, set_performance_level); | ||
493 | |||
494 | |||
495 | static int __init dmi_check_cb(const struct dmi_system_id *id) | ||
496 | { | ||
497 | pr_info("found laptop model '%s'\n", | ||
498 | id->ident); | ||
499 | return 1; | ||
500 | } | ||
501 | |||
502 | static struct dmi_system_id __initdata samsung_dmi_table[] = { | ||
503 | { | ||
504 | .ident = "N128", | ||
505 | .matches = { | ||
506 | DMI_MATCH(DMI_SYS_VENDOR, | ||
507 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
508 | DMI_MATCH(DMI_PRODUCT_NAME, "N128"), | ||
509 | DMI_MATCH(DMI_BOARD_NAME, "N128"), | ||
510 | }, | ||
511 | .callback = dmi_check_cb, | ||
512 | }, | ||
513 | { | ||
514 | .ident = "N130", | ||
515 | .matches = { | ||
516 | DMI_MATCH(DMI_SYS_VENDOR, | ||
517 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
518 | DMI_MATCH(DMI_PRODUCT_NAME, "N130"), | ||
519 | DMI_MATCH(DMI_BOARD_NAME, "N130"), | ||
520 | }, | ||
521 | .callback = dmi_check_cb, | ||
522 | }, | ||
523 | { | ||
524 | .ident = "X125", | ||
525 | .matches = { | ||
526 | DMI_MATCH(DMI_SYS_VENDOR, | ||
527 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
528 | DMI_MATCH(DMI_PRODUCT_NAME, "X125"), | ||
529 | DMI_MATCH(DMI_BOARD_NAME, "X125"), | ||
530 | }, | ||
531 | .callback = dmi_check_cb, | ||
532 | }, | ||
533 | { | ||
534 | .ident = "X120/X170", | ||
535 | .matches = { | ||
536 | DMI_MATCH(DMI_SYS_VENDOR, | ||
537 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
538 | DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), | ||
539 | DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), | ||
540 | }, | ||
541 | .callback = dmi_check_cb, | ||
542 | }, | ||
543 | { | ||
544 | .ident = "NC10", | ||
545 | .matches = { | ||
546 | DMI_MATCH(DMI_SYS_VENDOR, | ||
547 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
548 | DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), | ||
549 | DMI_MATCH(DMI_BOARD_NAME, "NC10"), | ||
550 | }, | ||
551 | .callback = dmi_check_cb, | ||
552 | }, | ||
553 | { | ||
554 | .ident = "NP-Q45", | ||
555 | .matches = { | ||
556 | DMI_MATCH(DMI_SYS_VENDOR, | ||
557 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
558 | DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), | ||
559 | DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), | ||
560 | }, | ||
561 | .callback = dmi_check_cb, | ||
562 | }, | ||
563 | { | ||
564 | .ident = "X360", | ||
565 | .matches = { | ||
566 | DMI_MATCH(DMI_SYS_VENDOR, | ||
567 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
568 | DMI_MATCH(DMI_PRODUCT_NAME, "X360"), | ||
569 | DMI_MATCH(DMI_BOARD_NAME, "X360"), | ||
570 | }, | ||
571 | .callback = dmi_check_cb, | ||
572 | }, | ||
573 | { | ||
574 | .ident = "R518", | ||
575 | .matches = { | ||
576 | DMI_MATCH(DMI_SYS_VENDOR, | ||
577 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
578 | DMI_MATCH(DMI_PRODUCT_NAME, "R518"), | ||
579 | DMI_MATCH(DMI_BOARD_NAME, "R518"), | ||
580 | }, | ||
581 | .callback = dmi_check_cb, | ||
582 | }, | ||
583 | { | ||
584 | .ident = "R519/R719", | ||
585 | .matches = { | ||
586 | DMI_MATCH(DMI_SYS_VENDOR, | ||
587 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
588 | DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), | ||
589 | DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), | ||
590 | }, | ||
591 | .callback = dmi_check_cb, | ||
592 | }, | ||
593 | { | ||
594 | .ident = "N150/N210/N220", | ||
595 | .matches = { | ||
596 | DMI_MATCH(DMI_SYS_VENDOR, | ||
597 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
598 | DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), | ||
599 | DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), | ||
600 | }, | ||
601 | .callback = dmi_check_cb, | ||
602 | }, | ||
603 | { | ||
604 | .ident = "N150P/N210P/N220P", | ||
605 | .matches = { | ||
606 | DMI_MATCH(DMI_SYS_VENDOR, | ||
607 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
608 | DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), | ||
609 | DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), | ||
610 | }, | ||
611 | .callback = dmi_check_cb, | ||
612 | }, | ||
613 | { | ||
614 | .ident = "R530/R730", | ||
615 | .matches = { | ||
616 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
617 | DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), | ||
618 | DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), | ||
619 | }, | ||
620 | .callback = dmi_check_cb, | ||
621 | }, | ||
622 | { | ||
623 | .ident = "NF110/NF210/NF310", | ||
624 | .matches = { | ||
625 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
626 | DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), | ||
627 | DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), | ||
628 | }, | ||
629 | .callback = dmi_check_cb, | ||
630 | }, | ||
631 | { | ||
632 | .ident = "N145P/N250P/N260P", | ||
633 | .matches = { | ||
634 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
635 | DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), | ||
636 | DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), | ||
637 | }, | ||
638 | .callback = dmi_check_cb, | ||
639 | }, | ||
640 | { | ||
641 | .ident = "R70/R71", | ||
642 | .matches = { | ||
643 | DMI_MATCH(DMI_SYS_VENDOR, | ||
644 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
645 | DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), | ||
646 | DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), | ||
647 | }, | ||
648 | .callback = dmi_check_cb, | ||
649 | }, | ||
650 | { | ||
651 | .ident = "P460", | ||
652 | .matches = { | ||
653 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
654 | DMI_MATCH(DMI_PRODUCT_NAME, "P460"), | ||
655 | DMI_MATCH(DMI_BOARD_NAME, "P460"), | ||
656 | }, | ||
657 | .callback = dmi_check_cb, | ||
658 | }, | ||
659 | { }, | ||
660 | }; | ||
661 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | ||
662 | |||
663 | static int find_signature(void __iomem *memcheck, const char *testStr) | ||
664 | { | ||
665 | int i = 0; | ||
666 | int loca; | ||
667 | |||
668 | for (loca = 0; loca < 0xffff; loca++) { | ||
669 | char temp = readb(memcheck + loca); | ||
670 | |||
671 | if (temp == testStr[i]) { | ||
672 | if (i == strlen(testStr)-1) | ||
673 | break; | ||
674 | ++i; | ||
675 | } else { | ||
676 | i = 0; | ||
677 | } | ||
678 | } | ||
679 | return loca; | ||
680 | } | ||
681 | |||
682 | static int __init samsung_init(void) | ||
683 | { | ||
684 | struct backlight_properties props; | ||
685 | struct sabi_retval sretval; | ||
686 | unsigned int ifaceP; | ||
687 | int i; | ||
688 | int loca; | ||
689 | int retval; | ||
690 | |||
691 | mutex_init(&sabi_mutex); | ||
692 | |||
693 | if (!force && !dmi_check_system(samsung_dmi_table)) | ||
694 | return -ENODEV; | ||
695 | |||
696 | f0000_segment = ioremap_nocache(0xf0000, 0xffff); | ||
697 | if (!f0000_segment) { | ||
698 | pr_err("Can't map the segment at 0xf0000\n"); | ||
699 | return -EINVAL; | ||
700 | } | ||
701 | |||
702 | /* Try to find one of the signatures in memory to find the header */ | ||
703 | for (i = 0; sabi_configs[i].test_string != 0; ++i) { | ||
704 | sabi_config = &sabi_configs[i]; | ||
705 | loca = find_signature(f0000_segment, sabi_config->test_string); | ||
706 | if (loca != 0xffff) | ||
707 | break; | ||
708 | } | ||
709 | |||
710 | if (loca == 0xffff) { | ||
711 | pr_err("This computer does not support SABI\n"); | ||
712 | goto error_no_signature; | ||
713 | } | ||
714 | |||
715 | /* point to the SMI port Number */ | ||
716 | loca += 1; | ||
717 | sabi = (f0000_segment + loca); | ||
718 | |||
719 | if (debug) { | ||
720 | printk(KERN_DEBUG "This computer supports SABI==%x\n", | ||
721 | loca + 0xf0000 - 6); | ||
722 | printk(KERN_DEBUG "SABI header:\n"); | ||
723 | printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", | ||
724 | readw(sabi + sabi_config->header_offsets.port)); | ||
725 | printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", | ||
726 | readb(sabi + sabi_config->header_offsets.iface_func)); | ||
727 | printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", | ||
728 | readb(sabi + sabi_config->header_offsets.en_mem)); | ||
729 | printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", | ||
730 | readb(sabi + sabi_config->header_offsets.re_mem)); | ||
731 | printk(KERN_DEBUG " SABI data offset = 0x%04x\n", | ||
732 | readw(sabi + sabi_config->header_offsets.data_offset)); | ||
733 | printk(KERN_DEBUG " SABI data segment = 0x%04x\n", | ||
734 | readw(sabi + sabi_config->header_offsets.data_segment)); | ||
735 | } | ||
736 | |||
737 | /* Get a pointer to the SABI Interface */ | ||
738 | ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; | ||
739 | ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; | ||
740 | sabi_iface = ioremap_nocache(ifaceP, 16); | ||
741 | if (!sabi_iface) { | ||
742 | pr_err("Can't remap %x\n", ifaceP); | ||
743 | goto exit; | ||
744 | } | ||
745 | if (debug) { | ||
746 | printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); | ||
747 | printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); | ||
748 | |||
749 | test_backlight(); | ||
750 | test_wireless(); | ||
751 | |||
752 | retval = sabi_get_command(sabi_config->commands.get_brightness, | ||
753 | &sretval); | ||
754 | printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); | ||
755 | } | ||
756 | |||
757 | /* Turn on "Linux" mode in the BIOS */ | ||
758 | if (sabi_config->commands.set_linux != 0xff) { | ||
759 | retval = sabi_set_command(sabi_config->commands.set_linux, | ||
760 | 0x81); | ||
761 | if (retval) { | ||
762 | pr_warn("Linux mode was not set!\n"); | ||
763 | goto error_no_platform; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | /* knock up a platform device to hang stuff off of */ | ||
768 | sdev = platform_device_register_simple("samsung", -1, NULL, 0); | ||
769 | if (IS_ERR(sdev)) | ||
770 | goto error_no_platform; | ||
771 | |||
772 | /* create a backlight device to talk to this one */ | ||
773 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
774 | props.max_brightness = sabi_config->max_brightness; | ||
775 | backlight_device = backlight_device_register("samsung", &sdev->dev, | ||
776 | NULL, &backlight_ops, | ||
777 | &props); | ||
778 | if (IS_ERR(backlight_device)) | ||
779 | goto error_no_backlight; | ||
780 | |||
781 | backlight_device->props.brightness = read_brightness(); | ||
782 | backlight_device->props.power = FB_BLANK_UNBLANK; | ||
783 | backlight_update_status(backlight_device); | ||
784 | |||
785 | retval = init_wireless(sdev); | ||
786 | if (retval) | ||
787 | goto error_no_rfk; | ||
788 | |||
789 | retval = device_create_file(&sdev->dev, &dev_attr_performance_level); | ||
790 | if (retval) | ||
791 | goto error_file_create; | ||
792 | |||
793 | exit: | ||
794 | return 0; | ||
795 | |||
796 | error_file_create: | ||
797 | destroy_wireless(); | ||
798 | |||
799 | error_no_rfk: | ||
800 | backlight_device_unregister(backlight_device); | ||
801 | |||
802 | error_no_backlight: | ||
803 | platform_device_unregister(sdev); | ||
804 | |||
805 | error_no_platform: | ||
806 | iounmap(sabi_iface); | ||
807 | |||
808 | error_no_signature: | ||
809 | iounmap(f0000_segment); | ||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
813 | static void __exit samsung_exit(void) | ||
814 | { | ||
815 | /* Turn off "Linux" mode in the BIOS */ | ||
816 | if (sabi_config->commands.set_linux != 0xff) | ||
817 | sabi_set_command(sabi_config->commands.set_linux, 0x80); | ||
818 | |||
819 | device_remove_file(&sdev->dev, &dev_attr_performance_level); | ||
820 | backlight_device_unregister(backlight_device); | ||
821 | destroy_wireless(); | ||
822 | iounmap(sabi_iface); | ||
823 | iounmap(f0000_segment); | ||
824 | platform_device_unregister(sdev); | ||
825 | } | ||
826 | |||
827 | module_init(samsung_init); | ||
828 | module_exit(samsung_exit); | ||
829 | |||
830 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>"); | ||
831 | MODULE_DESCRIPTION("Samsung Backlight driver"); | ||
832 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 13d8d63bcca9..e642f5f29504 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -71,8 +71,9 @@ | |||
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | #define DRV_PFX "sony-laptop: " | 73 | #define DRV_PFX "sony-laptop: " |
74 | #define dprintk(msg...) do { \ | 74 | #define dprintk(msg...) do { \ |
75 | if (debug) printk(KERN_WARNING DRV_PFX msg); \ | 75 | if (debug) \ |
76 | pr_warn(DRV_PFX msg); \ | ||
76 | } while (0) | 77 | } while (0) |
77 | 78 | ||
78 | #define SONY_LAPTOP_DRIVER_VERSION "0.6" | 79 | #define SONY_LAPTOP_DRIVER_VERSION "0.6" |
@@ -124,6 +125,19 @@ MODULE_PARM_DESC(minor, | |||
124 | "default is -1 (automatic)"); | 125 | "default is -1 (automatic)"); |
125 | #endif | 126 | #endif |
126 | 127 | ||
128 | static int kbd_backlight; /* = 1 */ | ||
129 | module_param(kbd_backlight, int, 0444); | ||
130 | MODULE_PARM_DESC(kbd_backlight, | ||
131 | "set this to 0 to disable keyboard backlight, " | ||
132 | "1 to enable it (default: 0)"); | ||
133 | |||
134 | static int kbd_backlight_timeout; /* = 0 */ | ||
135 | module_param(kbd_backlight_timeout, int, 0444); | ||
136 | MODULE_PARM_DESC(kbd_backlight_timeout, | ||
137 | "set this to 0 to set the default 10 seconds timeout, " | ||
138 | "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " | ||
139 | "(default: 0)"); | ||
140 | |||
127 | enum sony_nc_rfkill { | 141 | enum sony_nc_rfkill { |
128 | SONY_WIFI, | 142 | SONY_WIFI, |
129 | SONY_BLUETOOTH, | 143 | SONY_BLUETOOTH, |
@@ -402,7 +416,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device) | |||
402 | error = kfifo_alloc(&sony_laptop_input.fifo, | 416 | error = kfifo_alloc(&sony_laptop_input.fifo, |
403 | SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); | 417 | SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); |
404 | if (error) { | 418 | if (error) { |
405 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 419 | pr_err(DRV_PFX "kfifo_alloc failed\n"); |
406 | goto err_dec_users; | 420 | goto err_dec_users; |
407 | } | 421 | } |
408 | 422 | ||
@@ -591,7 +605,7 @@ struct sony_nc_value { | |||
591 | int value; /* current setting */ | 605 | int value; /* current setting */ |
592 | int valid; /* Has ever been set */ | 606 | int valid; /* Has ever been set */ |
593 | int debug; /* active only in debug mode ? */ | 607 | int debug; /* active only in debug mode ? */ |
594 | struct device_attribute devattr; /* sysfs atribute */ | 608 | struct device_attribute devattr; /* sysfs attribute */ |
595 | }; | 609 | }; |
596 | 610 | ||
597 | #define SNC_HANDLE_NAMES(_name, _values...) \ | 611 | #define SNC_HANDLE_NAMES(_name, _values...) \ |
@@ -686,7 +700,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) | |||
686 | return 0; | 700 | return 0; |
687 | } | 701 | } |
688 | 702 | ||
689 | printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); | 703 | pr_warn(DRV_PFX "acpi_callreadfunc failed\n"); |
690 | 704 | ||
691 | return -1; | 705 | return -1; |
692 | } | 706 | } |
@@ -712,7 +726,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | |||
712 | if (status == AE_OK) { | 726 | if (status == AE_OK) { |
713 | if (result != NULL) { | 727 | if (result != NULL) { |
714 | if (out_obj.type != ACPI_TYPE_INTEGER) { | 728 | if (out_obj.type != ACPI_TYPE_INTEGER) { |
715 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " | 729 | pr_warn(DRV_PFX "acpi_evaluate_object bad " |
716 | "return type\n"); | 730 | "return type\n"); |
717 | return -1; | 731 | return -1; |
718 | } | 732 | } |
@@ -721,34 +735,103 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | |||
721 | return 0; | 735 | return 0; |
722 | } | 736 | } |
723 | 737 | ||
724 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); | 738 | pr_warn(DRV_PFX "acpi_evaluate_object failed\n"); |
725 | 739 | ||
726 | return -1; | 740 | return -1; |
727 | } | 741 | } |
728 | 742 | ||
729 | static int sony_find_snc_handle(int handle) | 743 | struct sony_nc_handles { |
744 | u16 cap[0x10]; | ||
745 | struct device_attribute devattr; | ||
746 | }; | ||
747 | |||
748 | static struct sony_nc_handles *handles; | ||
749 | |||
750 | static ssize_t sony_nc_handles_show(struct device *dev, | ||
751 | struct device_attribute *attr, char *buffer) | ||
752 | { | ||
753 | ssize_t len = 0; | ||
754 | int i; | ||
755 | |||
756 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
757 | len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ", | ||
758 | handles->cap[i]); | ||
759 | } | ||
760 | len += snprintf(buffer + len, PAGE_SIZE - len, "\n"); | ||
761 | |||
762 | return len; | ||
763 | } | ||
764 | |||
765 | static int sony_nc_handles_setup(struct platform_device *pd) | ||
730 | { | 766 | { |
731 | int i; | 767 | int i; |
732 | int result; | 768 | int result; |
733 | 769 | ||
734 | for (i = 0x20; i < 0x30; i++) { | 770 | handles = kzalloc(sizeof(*handles), GFP_KERNEL); |
735 | acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); | 771 | if (!handles) |
736 | if (result == handle) | 772 | return -ENOMEM; |
737 | return i-0x20; | 773 | |
774 | sysfs_attr_init(&handles->devattr.attr); | ||
775 | handles->devattr.attr.name = "handles"; | ||
776 | handles->devattr.attr.mode = S_IRUGO; | ||
777 | handles->devattr.show = sony_nc_handles_show; | ||
778 | |||
779 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
780 | if (!acpi_callsetfunc(sony_nc_acpi_handle, | ||
781 | "SN00", i + 0x20, &result)) { | ||
782 | dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", | ||
783 | result, i); | ||
784 | handles->cap[i] = result; | ||
785 | } | ||
786 | } | ||
787 | |||
788 | /* allow reading capabilities via sysfs */ | ||
789 | if (device_create_file(&pd->dev, &handles->devattr)) { | ||
790 | kfree(handles); | ||
791 | handles = NULL; | ||
792 | return -1; | ||
793 | } | ||
794 | |||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | static int sony_nc_handles_cleanup(struct platform_device *pd) | ||
799 | { | ||
800 | if (handles) { | ||
801 | device_remove_file(&pd->dev, &handles->devattr); | ||
802 | kfree(handles); | ||
803 | handles = NULL; | ||
738 | } | 804 | } |
805 | return 0; | ||
806 | } | ||
739 | 807 | ||
808 | static int sony_find_snc_handle(int handle) | ||
809 | { | ||
810 | int i; | ||
811 | for (i = 0; i < 0x10; i++) { | ||
812 | if (handles->cap[i] == handle) { | ||
813 | dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", | ||
814 | handle, i); | ||
815 | return i; | ||
816 | } | ||
817 | } | ||
818 | dprintk("handle 0x%.4x not found\n", handle); | ||
740 | return -1; | 819 | return -1; |
741 | } | 820 | } |
742 | 821 | ||
743 | static int sony_call_snc_handle(int handle, int argument, int *result) | 822 | static int sony_call_snc_handle(int handle, int argument, int *result) |
744 | { | 823 | { |
824 | int ret = 0; | ||
745 | int offset = sony_find_snc_handle(handle); | 825 | int offset = sony_find_snc_handle(handle); |
746 | 826 | ||
747 | if (offset < 0) | 827 | if (offset < 0) |
748 | return -1; | 828 | return -1; |
749 | 829 | ||
750 | return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, | 830 | ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, |
751 | result); | 831 | result); |
832 | dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, | ||
833 | *result); | ||
834 | return ret; | ||
752 | } | 835 | } |
753 | 836 | ||
754 | /* | 837 | /* |
@@ -857,11 +940,39 @@ static int sony_backlight_get_brightness(struct backlight_device *bd) | |||
857 | return value - 1; | 940 | return value - 1; |
858 | } | 941 | } |
859 | 942 | ||
860 | static struct backlight_device *sony_backlight_device; | 943 | static int sony_nc_get_brightness_ng(struct backlight_device *bd) |
944 | { | ||
945 | int result; | ||
946 | int *handle = (int *)bl_get_data(bd); | ||
947 | |||
948 | sony_call_snc_handle(*handle, 0x0200, &result); | ||
949 | |||
950 | return result & 0xff; | ||
951 | } | ||
952 | |||
953 | static int sony_nc_update_status_ng(struct backlight_device *bd) | ||
954 | { | ||
955 | int value, result; | ||
956 | int *handle = (int *)bl_get_data(bd); | ||
957 | |||
958 | value = bd->props.brightness; | ||
959 | sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result); | ||
960 | |||
961 | return sony_nc_get_brightness_ng(bd); | ||
962 | } | ||
963 | |||
861 | static const struct backlight_ops sony_backlight_ops = { | 964 | static const struct backlight_ops sony_backlight_ops = { |
965 | .options = BL_CORE_SUSPENDRESUME, | ||
862 | .update_status = sony_backlight_update_status, | 966 | .update_status = sony_backlight_update_status, |
863 | .get_brightness = sony_backlight_get_brightness, | 967 | .get_brightness = sony_backlight_get_brightness, |
864 | }; | 968 | }; |
969 | static const struct backlight_ops sony_backlight_ng_ops = { | ||
970 | .options = BL_CORE_SUSPENDRESUME, | ||
971 | .update_status = sony_nc_update_status_ng, | ||
972 | .get_brightness = sony_nc_get_brightness_ng, | ||
973 | }; | ||
974 | static int backlight_ng_handle; | ||
975 | static struct backlight_device *sony_backlight_device; | ||
865 | 976 | ||
866 | /* | 977 | /* |
867 | * New SNC-only Vaios event mapping to driver known keys | 978 | * New SNC-only Vaios event mapping to driver known keys |
@@ -972,7 +1083,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) | |||
972 | } | 1083 | } |
973 | 1084 | ||
974 | if (!key_event->data) | 1085 | if (!key_event->data) |
975 | printk(KERN_INFO DRV_PFX | 1086 | pr_info(DRV_PFX |
976 | "Unknown event: 0x%x 0x%x\n", | 1087 | "Unknown event: 0x%x 0x%x\n", |
977 | key_handle, | 1088 | key_handle, |
978 | ev); | 1089 | ev); |
@@ -996,7 +1107,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | |||
996 | struct acpi_device_info *info; | 1107 | struct acpi_device_info *info; |
997 | 1108 | ||
998 | if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { | 1109 | if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { |
999 | printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", | 1110 | pr_warn(DRV_PFX "method: name: %4.4s, args %X\n", |
1000 | (char *)&info->name, info->param_count); | 1111 | (char *)&info->name, info->param_count); |
1001 | 1112 | ||
1002 | kfree(info); | 1113 | kfree(info); |
@@ -1037,7 +1148,7 @@ static int sony_nc_resume(struct acpi_device *device) | |||
1037 | ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, | 1148 | ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, |
1038 | item->value, NULL); | 1149 | item->value, NULL); |
1039 | if (ret < 0) { | 1150 | if (ret < 0) { |
1040 | printk("%s: %d\n", __func__, ret); | 1151 | pr_err(DRV_PFX "%s: %d\n", __func__, ret); |
1041 | break; | 1152 | break; |
1042 | } | 1153 | } |
1043 | } | 1154 | } |
@@ -1054,11 +1165,6 @@ static int sony_nc_resume(struct acpi_device *device) | |||
1054 | sony_nc_function_setup(device); | 1165 | sony_nc_function_setup(device); |
1055 | } | 1166 | } |
1056 | 1167 | ||
1057 | /* set the last requested brightness level */ | ||
1058 | if (sony_backlight_device && | ||
1059 | sony_backlight_update_status(sony_backlight_device) < 0) | ||
1060 | printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n"); | ||
1061 | |||
1062 | /* re-read rfkill state */ | 1168 | /* re-read rfkill state */ |
1063 | sony_nc_rfkill_update(); | 1169 | sony_nc_rfkill_update(); |
1064 | 1170 | ||
@@ -1206,12 +1312,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device) | |||
1206 | 1312 | ||
1207 | device_enum = (union acpi_object *) buffer.pointer; | 1313 | device_enum = (union acpi_object *) buffer.pointer; |
1208 | if (!device_enum) { | 1314 | if (!device_enum) { |
1209 | pr_err("Invalid SN06 return object\n"); | 1315 | pr_err(DRV_PFX "No SN06 return object."); |
1210 | goto out_no_enum; | 1316 | goto out_no_enum; |
1211 | } | 1317 | } |
1212 | if (device_enum->type != ACPI_TYPE_BUFFER) { | 1318 | if (device_enum->type != ACPI_TYPE_BUFFER) { |
1213 | pr_err("Invalid SN06 return object type 0x%.2x\n", | 1319 | pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n", |
1214 | device_enum->type); | 1320 | device_enum->type); |
1215 | goto out_no_enum; | 1321 | goto out_no_enum; |
1216 | } | 1322 | } |
1217 | 1323 | ||
@@ -1245,6 +1351,209 @@ out_no_enum: | |||
1245 | return; | 1351 | return; |
1246 | } | 1352 | } |
1247 | 1353 | ||
1354 | /* Keyboard backlight feature */ | ||
1355 | #define KBDBL_HANDLER 0x137 | ||
1356 | #define KBDBL_PRESENT 0xB00 | ||
1357 | #define SET_MODE 0xC00 | ||
1358 | #define SET_TIMEOUT 0xE00 | ||
1359 | |||
1360 | struct kbd_backlight { | ||
1361 | int mode; | ||
1362 | int timeout; | ||
1363 | struct device_attribute mode_attr; | ||
1364 | struct device_attribute timeout_attr; | ||
1365 | }; | ||
1366 | |||
1367 | static struct kbd_backlight *kbdbl_handle; | ||
1368 | |||
1369 | static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) | ||
1370 | { | ||
1371 | int result; | ||
1372 | |||
1373 | if (value > 1) | ||
1374 | return -EINVAL; | ||
1375 | |||
1376 | if (sony_call_snc_handle(KBDBL_HANDLER, | ||
1377 | (value << 0x10) | SET_MODE, &result)) | ||
1378 | return -EIO; | ||
1379 | |||
1380 | kbdbl_handle->mode = value; | ||
1381 | |||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev, | ||
1386 | struct device_attribute *attr, | ||
1387 | const char *buffer, size_t count) | ||
1388 | { | ||
1389 | int ret = 0; | ||
1390 | unsigned long value; | ||
1391 | |||
1392 | if (count > 31) | ||
1393 | return -EINVAL; | ||
1394 | |||
1395 | if (strict_strtoul(buffer, 10, &value)) | ||
1396 | return -EINVAL; | ||
1397 | |||
1398 | ret = __sony_nc_kbd_backlight_mode_set(value); | ||
1399 | if (ret < 0) | ||
1400 | return ret; | ||
1401 | |||
1402 | return count; | ||
1403 | } | ||
1404 | |||
1405 | static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev, | ||
1406 | struct device_attribute *attr, char *buffer) | ||
1407 | { | ||
1408 | ssize_t count = 0; | ||
1409 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); | ||
1410 | return count; | ||
1411 | } | ||
1412 | |||
1413 | static int __sony_nc_kbd_backlight_timeout_set(u8 value) | ||
1414 | { | ||
1415 | int result; | ||
1416 | |||
1417 | if (value > 3) | ||
1418 | return -EINVAL; | ||
1419 | |||
1420 | if (sony_call_snc_handle(KBDBL_HANDLER, | ||
1421 | (value << 0x10) | SET_TIMEOUT, &result)) | ||
1422 | return -EIO; | ||
1423 | |||
1424 | kbdbl_handle->timeout = value; | ||
1425 | |||
1426 | return 0; | ||
1427 | } | ||
1428 | |||
1429 | static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev, | ||
1430 | struct device_attribute *attr, | ||
1431 | const char *buffer, size_t count) | ||
1432 | { | ||
1433 | int ret = 0; | ||
1434 | unsigned long value; | ||
1435 | |||
1436 | if (count > 31) | ||
1437 | return -EINVAL; | ||
1438 | |||
1439 | if (strict_strtoul(buffer, 10, &value)) | ||
1440 | return -EINVAL; | ||
1441 | |||
1442 | ret = __sony_nc_kbd_backlight_timeout_set(value); | ||
1443 | if (ret < 0) | ||
1444 | return ret; | ||
1445 | |||
1446 | return count; | ||
1447 | } | ||
1448 | |||
1449 | static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev, | ||
1450 | struct device_attribute *attr, char *buffer) | ||
1451 | { | ||
1452 | ssize_t count = 0; | ||
1453 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); | ||
1454 | return count; | ||
1455 | } | ||
1456 | |||
1457 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd) | ||
1458 | { | ||
1459 | int result; | ||
1460 | |||
1461 | if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) | ||
1462 | return 0; | ||
1463 | if (!(result & 0x02)) | ||
1464 | return 0; | ||
1465 | |||
1466 | kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); | ||
1467 | if (!kbdbl_handle) | ||
1468 | return -ENOMEM; | ||
1469 | |||
1470 | sysfs_attr_init(&kbdbl_handle->mode_attr.attr); | ||
1471 | kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; | ||
1472 | kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
1473 | kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; | ||
1474 | kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; | ||
1475 | |||
1476 | sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); | ||
1477 | kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; | ||
1478 | kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
1479 | kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; | ||
1480 | kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; | ||
1481 | |||
1482 | if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) | ||
1483 | goto outkzalloc; | ||
1484 | |||
1485 | if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) | ||
1486 | goto outmode; | ||
1487 | |||
1488 | __sony_nc_kbd_backlight_mode_set(kbd_backlight); | ||
1489 | __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout); | ||
1490 | |||
1491 | return 0; | ||
1492 | |||
1493 | outmode: | ||
1494 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | ||
1495 | outkzalloc: | ||
1496 | kfree(kbdbl_handle); | ||
1497 | kbdbl_handle = NULL; | ||
1498 | return -1; | ||
1499 | } | ||
1500 | |||
1501 | static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) | ||
1502 | { | ||
1503 | if (kbdbl_handle) { | ||
1504 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | ||
1505 | device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); | ||
1506 | kfree(kbdbl_handle); | ||
1507 | } | ||
1508 | return 0; | ||
1509 | } | ||
1510 | |||
1511 | static void sony_nc_backlight_setup(void) | ||
1512 | { | ||
1513 | acpi_handle unused; | ||
1514 | int max_brightness = 0; | ||
1515 | const struct backlight_ops *ops = NULL; | ||
1516 | struct backlight_properties props; | ||
1517 | |||
1518 | if (sony_find_snc_handle(0x12f) != -1) { | ||
1519 | backlight_ng_handle = 0x12f; | ||
1520 | ops = &sony_backlight_ng_ops; | ||
1521 | max_brightness = 0xff; | ||
1522 | |||
1523 | } else if (sony_find_snc_handle(0x137) != -1) { | ||
1524 | backlight_ng_handle = 0x137; | ||
1525 | ops = &sony_backlight_ng_ops; | ||
1526 | max_brightness = 0xff; | ||
1527 | |||
1528 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", | ||
1529 | &unused))) { | ||
1530 | ops = &sony_backlight_ops; | ||
1531 | max_brightness = SONY_MAX_BRIGHTNESS - 1; | ||
1532 | |||
1533 | } else | ||
1534 | return; | ||
1535 | |||
1536 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
1537 | props.type = BACKLIGHT_PLATFORM; | ||
1538 | props.max_brightness = max_brightness; | ||
1539 | sony_backlight_device = backlight_device_register("sony", NULL, | ||
1540 | &backlight_ng_handle, | ||
1541 | ops, &props); | ||
1542 | |||
1543 | if (IS_ERR(sony_backlight_device)) { | ||
1544 | pr_warning(DRV_PFX "unable to register backlight device\n"); | ||
1545 | sony_backlight_device = NULL; | ||
1546 | } else | ||
1547 | sony_backlight_device->props.brightness = | ||
1548 | ops->get_brightness(sony_backlight_device); | ||
1549 | } | ||
1550 | |||
1551 | static void sony_nc_backlight_cleanup(void) | ||
1552 | { | ||
1553 | if (sony_backlight_device) | ||
1554 | backlight_device_unregister(sony_backlight_device); | ||
1555 | } | ||
1556 | |||
1248 | static int sony_nc_add(struct acpi_device *device) | 1557 | static int sony_nc_add(struct acpi_device *device) |
1249 | { | 1558 | { |
1250 | acpi_status status; | 1559 | acpi_status status; |
@@ -1252,8 +1561,8 @@ static int sony_nc_add(struct acpi_device *device) | |||
1252 | acpi_handle handle; | 1561 | acpi_handle handle; |
1253 | struct sony_nc_value *item; | 1562 | struct sony_nc_value *item; |
1254 | 1563 | ||
1255 | printk(KERN_INFO DRV_PFX "%s v%s.\n", | 1564 | pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME, |
1256 | SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); | 1565 | SONY_LAPTOP_DRIVER_VERSION); |
1257 | 1566 | ||
1258 | sony_nc_acpi_device = device; | 1567 | sony_nc_acpi_device = device; |
1259 | strcpy(acpi_device_class(device), "sony/hotkey"); | 1568 | strcpy(acpi_device_class(device), "sony/hotkey"); |
@@ -1269,13 +1578,18 @@ static int sony_nc_add(struct acpi_device *device) | |||
1269 | goto outwalk; | 1578 | goto outwalk; |
1270 | } | 1579 | } |
1271 | 1580 | ||
1581 | result = sony_pf_add(); | ||
1582 | if (result) | ||
1583 | goto outpresent; | ||
1584 | |||
1272 | if (debug) { | 1585 | if (debug) { |
1273 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, | 1586 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, |
1274 | 1, sony_walk_callback, NULL, NULL, NULL); | 1587 | sony_nc_acpi_handle, 1, sony_walk_callback, |
1588 | NULL, NULL, NULL); | ||
1275 | if (ACPI_FAILURE(status)) { | 1589 | if (ACPI_FAILURE(status)) { |
1276 | printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); | 1590 | pr_warn(DRV_PFX "unable to walk acpi resources\n"); |
1277 | result = -ENODEV; | 1591 | result = -ENODEV; |
1278 | goto outwalk; | 1592 | goto outpresent; |
1279 | } | 1593 | } |
1280 | } | 1594 | } |
1281 | 1595 | ||
@@ -1288,6 +1602,12 @@ static int sony_nc_add(struct acpi_device *device) | |||
1288 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", | 1602 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", |
1289 | &handle))) { | 1603 | &handle))) { |
1290 | dprintk("Doing SNC setup\n"); | 1604 | dprintk("Doing SNC setup\n"); |
1605 | result = sony_nc_handles_setup(sony_pf_device); | ||
1606 | if (result) | ||
1607 | goto outpresent; | ||
1608 | result = sony_nc_kbd_backlight_setup(sony_pf_device); | ||
1609 | if (result) | ||
1610 | goto outsnc; | ||
1291 | sony_nc_function_setup(device); | 1611 | sony_nc_function_setup(device); |
1292 | sony_nc_rfkill_setup(device); | 1612 | sony_nc_rfkill_setup(device); |
1293 | } | 1613 | } |
@@ -1295,40 +1615,17 @@ static int sony_nc_add(struct acpi_device *device) | |||
1295 | /* setup input devices and helper fifo */ | 1615 | /* setup input devices and helper fifo */ |
1296 | result = sony_laptop_setup_input(device); | 1616 | result = sony_laptop_setup_input(device); |
1297 | if (result) { | 1617 | if (result) { |
1298 | printk(KERN_ERR DRV_PFX | 1618 | pr_err(DRV_PFX "Unable to create input devices.\n"); |
1299 | "Unable to create input devices.\n"); | 1619 | goto outkbdbacklight; |
1300 | goto outwalk; | ||
1301 | } | 1620 | } |
1302 | 1621 | ||
1303 | if (acpi_video_backlight_support()) { | 1622 | if (acpi_video_backlight_support()) { |
1304 | printk(KERN_INFO DRV_PFX "brightness ignored, must be " | 1623 | pr_info(DRV_PFX "brightness ignored, must be " |
1305 | "controlled by ACPI video driver\n"); | 1624 | "controlled by ACPI video driver\n"); |
1306 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", | 1625 | } else { |
1307 | &handle))) { | 1626 | sony_nc_backlight_setup(); |
1308 | struct backlight_properties props; | ||
1309 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
1310 | props.type = BACKLIGHT_PLATFORM; | ||
1311 | props.max_brightness = SONY_MAX_BRIGHTNESS - 1; | ||
1312 | sony_backlight_device = backlight_device_register("sony", NULL, | ||
1313 | NULL, | ||
1314 | &sony_backlight_ops, | ||
1315 | &props); | ||
1316 | |||
1317 | if (IS_ERR(sony_backlight_device)) { | ||
1318 | printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); | ||
1319 | sony_backlight_device = NULL; | ||
1320 | } else { | ||
1321 | sony_backlight_device->props.brightness = | ||
1322 | sony_backlight_get_brightness | ||
1323 | (sony_backlight_device); | ||
1324 | } | ||
1325 | |||
1326 | } | 1627 | } |
1327 | 1628 | ||
1328 | result = sony_pf_add(); | ||
1329 | if (result) | ||
1330 | goto outbacklight; | ||
1331 | |||
1332 | /* create sony_pf sysfs attributes related to the SNC device */ | 1629 | /* create sony_pf sysfs attributes related to the SNC device */ |
1333 | for (item = sony_nc_values; item->name; ++item) { | 1630 | for (item = sony_nc_values; item->name; ++item) { |
1334 | 1631 | ||
@@ -1374,14 +1671,19 @@ static int sony_nc_add(struct acpi_device *device) | |||
1374 | for (item = sony_nc_values; item->name; ++item) { | 1671 | for (item = sony_nc_values; item->name; ++item) { |
1375 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1672 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
1376 | } | 1673 | } |
1377 | sony_pf_remove(); | 1674 | sony_nc_backlight_cleanup(); |
1378 | |||
1379 | outbacklight: | ||
1380 | if (sony_backlight_device) | ||
1381 | backlight_device_unregister(sony_backlight_device); | ||
1382 | 1675 | ||
1383 | sony_laptop_remove_input(); | 1676 | sony_laptop_remove_input(); |
1384 | 1677 | ||
1678 | outkbdbacklight: | ||
1679 | sony_nc_kbd_backlight_cleanup(sony_pf_device); | ||
1680 | |||
1681 | outsnc: | ||
1682 | sony_nc_handles_cleanup(sony_pf_device); | ||
1683 | |||
1684 | outpresent: | ||
1685 | sony_pf_remove(); | ||
1686 | |||
1385 | outwalk: | 1687 | outwalk: |
1386 | sony_nc_rfkill_cleanup(); | 1688 | sony_nc_rfkill_cleanup(); |
1387 | return result; | 1689 | return result; |
@@ -1391,8 +1693,7 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
1391 | { | 1693 | { |
1392 | struct sony_nc_value *item; | 1694 | struct sony_nc_value *item; |
1393 | 1695 | ||
1394 | if (sony_backlight_device) | 1696 | sony_nc_backlight_cleanup(); |
1395 | backlight_device_unregister(sony_backlight_device); | ||
1396 | 1697 | ||
1397 | sony_nc_acpi_device = NULL; | 1698 | sony_nc_acpi_device = NULL; |
1398 | 1699 | ||
@@ -1400,6 +1701,8 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
1400 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1701 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
1401 | } | 1702 | } |
1402 | 1703 | ||
1704 | sony_nc_kbd_backlight_cleanup(sony_pf_device); | ||
1705 | sony_nc_handles_cleanup(sony_pf_device); | ||
1403 | sony_pf_remove(); | 1706 | sony_pf_remove(); |
1404 | sony_laptop_remove_input(); | 1707 | sony_laptop_remove_input(); |
1405 | sony_nc_rfkill_cleanup(); | 1708 | sony_nc_rfkill_cleanup(); |
@@ -1438,7 +1741,6 @@ static struct acpi_driver sony_nc_driver = { | |||
1438 | #define SONYPI_DEVICE_TYPE1 0x00000001 | 1741 | #define SONYPI_DEVICE_TYPE1 0x00000001 |
1439 | #define SONYPI_DEVICE_TYPE2 0x00000002 | 1742 | #define SONYPI_DEVICE_TYPE2 0x00000002 |
1440 | #define SONYPI_DEVICE_TYPE3 0x00000004 | 1743 | #define SONYPI_DEVICE_TYPE3 0x00000004 |
1441 | #define SONYPI_DEVICE_TYPE4 0x00000008 | ||
1442 | 1744 | ||
1443 | #define SONYPI_TYPE1_OFFSET 0x04 | 1745 | #define SONYPI_TYPE1_OFFSET 0x04 |
1444 | #define SONYPI_TYPE2_OFFSET 0x12 | 1746 | #define SONYPI_TYPE2_OFFSET 0x12 |
@@ -1584,8 +1886,8 @@ static struct sonypi_event sonypi_blueev[] = { | |||
1584 | 1886 | ||
1585 | /* The set of possible wireless events */ | 1887 | /* The set of possible wireless events */ |
1586 | static struct sonypi_event sonypi_wlessev[] = { | 1888 | static struct sonypi_event sonypi_wlessev[] = { |
1587 | { 0x59, SONYPI_EVENT_WIRELESS_ON }, | 1889 | { 0x59, SONYPI_EVENT_IGNORE }, |
1588 | { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, | 1890 | { 0x5a, SONYPI_EVENT_IGNORE }, |
1589 | { 0, 0 } | 1891 | { 0, 0 } |
1590 | }; | 1892 | }; |
1591 | 1893 | ||
@@ -1842,7 +2144,7 @@ out: | |||
1842 | if (pcidev) | 2144 | if (pcidev) |
1843 | pci_dev_put(pcidev); | 2145 | pci_dev_put(pcidev); |
1844 | 2146 | ||
1845 | printk(KERN_INFO DRV_PFX "detected Type%d model\n", | 2147 | pr_info(DRV_PFX "detected Type%d model\n", |
1846 | dev->model == SONYPI_DEVICE_TYPE1 ? 1 : | 2148 | dev->model == SONYPI_DEVICE_TYPE1 ? 1 : |
1847 | dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); | 2149 | dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); |
1848 | } | 2150 | } |
@@ -1890,7 +2192,7 @@ static int __sony_pic_camera_ready(void) | |||
1890 | static int __sony_pic_camera_off(void) | 2192 | static int __sony_pic_camera_off(void) |
1891 | { | 2193 | { |
1892 | if (!camera) { | 2194 | if (!camera) { |
1893 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); | 2195 | pr_warn(DRV_PFX "camera control not enabled\n"); |
1894 | return -ENODEV; | 2196 | return -ENODEV; |
1895 | } | 2197 | } |
1896 | 2198 | ||
@@ -1910,7 +2212,7 @@ static int __sony_pic_camera_on(void) | |||
1910 | int i, j, x; | 2212 | int i, j, x; |
1911 | 2213 | ||
1912 | if (!camera) { | 2214 | if (!camera) { |
1913 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); | 2215 | pr_warn(DRV_PFX "camera control not enabled\n"); |
1914 | return -ENODEV; | 2216 | return -ENODEV; |
1915 | } | 2217 | } |
1916 | 2218 | ||
@@ -1933,7 +2235,7 @@ static int __sony_pic_camera_on(void) | |||
1933 | } | 2235 | } |
1934 | 2236 | ||
1935 | if (j == 0) { | 2237 | if (j == 0) { |
1936 | printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); | 2238 | pr_warn(DRV_PFX "failed to power on camera\n"); |
1937 | return -ENODEV; | 2239 | return -ENODEV; |
1938 | } | 2240 | } |
1939 | 2241 | ||
@@ -1989,7 +2291,7 @@ int sony_pic_camera_command(int command, u8 value) | |||
1989 | ITERATIONS_SHORT); | 2291 | ITERATIONS_SHORT); |
1990 | break; | 2292 | break; |
1991 | default: | 2293 | default: |
1992 | printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", | 2294 | pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n", |
1993 | command); | 2295 | command); |
1994 | break; | 2296 | break; |
1995 | } | 2297 | } |
@@ -2396,7 +2698,7 @@ static int sonypi_compat_init(void) | |||
2396 | error = | 2698 | error = |
2397 | kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); | 2699 | kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); |
2398 | if (error) { | 2700 | if (error) { |
2399 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 2701 | pr_err(DRV_PFX "kfifo_alloc failed\n"); |
2400 | return error; | 2702 | return error; |
2401 | } | 2703 | } |
2402 | 2704 | ||
@@ -2406,11 +2708,11 @@ static int sonypi_compat_init(void) | |||
2406 | sonypi_misc_device.minor = minor; | 2708 | sonypi_misc_device.minor = minor; |
2407 | error = misc_register(&sonypi_misc_device); | 2709 | error = misc_register(&sonypi_misc_device); |
2408 | if (error) { | 2710 | if (error) { |
2409 | printk(KERN_ERR DRV_PFX "misc_register failed\n"); | 2711 | pr_err(DRV_PFX "misc_register failed\n"); |
2410 | goto err_free_kfifo; | 2712 | goto err_free_kfifo; |
2411 | } | 2713 | } |
2412 | if (minor == -1) | 2714 | if (minor == -1) |
2413 | printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", | 2715 | pr_info(DRV_PFX "device allocated minor is %d\n", |
2414 | sonypi_misc_device.minor); | 2716 | sonypi_misc_device.minor); |
2415 | 2717 | ||
2416 | return 0; | 2718 | return 0; |
@@ -2470,8 +2772,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2470 | } | 2772 | } |
2471 | for (i = 0; i < p->interrupt_count; i++) { | 2773 | for (i = 0; i < p->interrupt_count; i++) { |
2472 | if (!p->interrupts[i]) { | 2774 | if (!p->interrupts[i]) { |
2473 | printk(KERN_WARNING DRV_PFX | 2775 | pr_warn(DRV_PFX "Invalid IRQ %d\n", |
2474 | "Invalid IRQ %d\n", | ||
2475 | p->interrupts[i]); | 2776 | p->interrupts[i]); |
2476 | continue; | 2777 | continue; |
2477 | } | 2778 | } |
@@ -2510,7 +2811,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2510 | ioport->io2.address_length); | 2811 | ioport->io2.address_length); |
2511 | } | 2812 | } |
2512 | else { | 2813 | else { |
2513 | printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); | 2814 | pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); |
2514 | return AE_ERROR; | 2815 | return AE_ERROR; |
2515 | } | 2816 | } |
2516 | return AE_OK; | 2817 | return AE_OK; |
@@ -2538,7 +2839,7 @@ static int sony_pic_possible_resources(struct acpi_device *device) | |||
2538 | dprintk("Evaluating _STA\n"); | 2839 | dprintk("Evaluating _STA\n"); |
2539 | result = acpi_bus_get_status(device); | 2840 | result = acpi_bus_get_status(device); |
2540 | if (result) { | 2841 | if (result) { |
2541 | printk(KERN_WARNING DRV_PFX "Unable to read status\n"); | 2842 | pr_warn(DRV_PFX "Unable to read status\n"); |
2542 | goto end; | 2843 | goto end; |
2543 | } | 2844 | } |
2544 | 2845 | ||
@@ -2554,8 +2855,7 @@ static int sony_pic_possible_resources(struct acpi_device *device) | |||
2554 | status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, | 2855 | status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, |
2555 | sony_pic_read_possible_resource, &spic_dev); | 2856 | sony_pic_read_possible_resource, &spic_dev); |
2556 | if (ACPI_FAILURE(status)) { | 2857 | if (ACPI_FAILURE(status)) { |
2557 | printk(KERN_WARNING DRV_PFX | 2858 | pr_warn(DRV_PFX "Failure evaluating %s\n", |
2558 | "Failure evaluating %s\n", | ||
2559 | METHOD_NAME__PRS); | 2859 | METHOD_NAME__PRS); |
2560 | result = -ENODEV; | 2860 | result = -ENODEV; |
2561 | } | 2861 | } |
@@ -2669,7 +2969,7 @@ static int sony_pic_enable(struct acpi_device *device, | |||
2669 | 2969 | ||
2670 | /* check for total failure */ | 2970 | /* check for total failure */ |
2671 | if (ACPI_FAILURE(status)) { | 2971 | if (ACPI_FAILURE(status)) { |
2672 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); | 2972 | pr_err(DRV_PFX "Error evaluating _SRS\n"); |
2673 | result = -ENODEV; | 2973 | result = -ENODEV; |
2674 | goto end; | 2974 | goto end; |
2675 | } | 2975 | } |
@@ -2725,6 +3025,9 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) | |||
2725 | if (ev == dev->event_types[i].events[j].data) { | 3025 | if (ev == dev->event_types[i].events[j].data) { |
2726 | device_event = | 3026 | device_event = |
2727 | dev->event_types[i].events[j].event; | 3027 | dev->event_types[i].events[j].event; |
3028 | /* some events may require ignoring */ | ||
3029 | if (!device_event) | ||
3030 | return IRQ_HANDLED; | ||
2728 | goto found; | 3031 | goto found; |
2729 | } | 3032 | } |
2730 | } | 3033 | } |
@@ -2744,7 +3047,6 @@ found: | |||
2744 | sony_laptop_report_input_event(device_event); | 3047 | sony_laptop_report_input_event(device_event); |
2745 | acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); | 3048 | acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); |
2746 | sonypi_compat_report_event(device_event); | 3049 | sonypi_compat_report_event(device_event); |
2747 | |||
2748 | return IRQ_HANDLED; | 3050 | return IRQ_HANDLED; |
2749 | } | 3051 | } |
2750 | 3052 | ||
@@ -2759,7 +3061,7 @@ static int sony_pic_remove(struct acpi_device *device, int type) | |||
2759 | struct sony_pic_irq *irq, *tmp_irq; | 3061 | struct sony_pic_irq *irq, *tmp_irq; |
2760 | 3062 | ||
2761 | if (sony_pic_disable(device)) { | 3063 | if (sony_pic_disable(device)) { |
2762 | printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); | 3064 | pr_err(DRV_PFX "Couldn't disable device.\n"); |
2763 | return -ENXIO; | 3065 | return -ENXIO; |
2764 | } | 3066 | } |
2765 | 3067 | ||
@@ -2799,8 +3101,8 @@ static int sony_pic_add(struct acpi_device *device) | |||
2799 | struct sony_pic_ioport *io, *tmp_io; | 3101 | struct sony_pic_ioport *io, *tmp_io; |
2800 | struct sony_pic_irq *irq, *tmp_irq; | 3102 | struct sony_pic_irq *irq, *tmp_irq; |
2801 | 3103 | ||
2802 | printk(KERN_INFO DRV_PFX "%s v%s.\n", | 3104 | pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME, |
2803 | SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); | 3105 | SONY_LAPTOP_DRIVER_VERSION); |
2804 | 3106 | ||
2805 | spic_dev.acpi_dev = device; | 3107 | spic_dev.acpi_dev = device; |
2806 | strcpy(acpi_device_class(device), "sony/hotkey"); | 3108 | strcpy(acpi_device_class(device), "sony/hotkey"); |
@@ -2810,16 +3112,14 @@ static int sony_pic_add(struct acpi_device *device) | |||
2810 | /* read _PRS resources */ | 3112 | /* read _PRS resources */ |
2811 | result = sony_pic_possible_resources(device); | 3113 | result = sony_pic_possible_resources(device); |
2812 | if (result) { | 3114 | if (result) { |
2813 | printk(KERN_ERR DRV_PFX | 3115 | pr_err(DRV_PFX "Unable to read possible resources.\n"); |
2814 | "Unable to read possible resources.\n"); | ||
2815 | goto err_free_resources; | 3116 | goto err_free_resources; |
2816 | } | 3117 | } |
2817 | 3118 | ||
2818 | /* setup input devices and helper fifo */ | 3119 | /* setup input devices and helper fifo */ |
2819 | result = sony_laptop_setup_input(device); | 3120 | result = sony_laptop_setup_input(device); |
2820 | if (result) { | 3121 | if (result) { |
2821 | printk(KERN_ERR DRV_PFX | 3122 | pr_err(DRV_PFX "Unable to create input devices.\n"); |
2822 | "Unable to create input devices.\n"); | ||
2823 | goto err_free_resources; | 3123 | goto err_free_resources; |
2824 | } | 3124 | } |
2825 | 3125 | ||
@@ -2829,7 +3129,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
2829 | /* request io port */ | 3129 | /* request io port */ |
2830 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { | 3130 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { |
2831 | if (request_region(io->io1.minimum, io->io1.address_length, | 3131 | if (request_region(io->io1.minimum, io->io1.address_length, |
2832 | "Sony Programable I/O Device")) { | 3132 | "Sony Programmable I/O Device")) { |
2833 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", | 3133 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", |
2834 | io->io1.minimum, io->io1.maximum, | 3134 | io->io1.minimum, io->io1.maximum, |
2835 | io->io1.address_length); | 3135 | io->io1.address_length); |
@@ -2837,7 +3137,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
2837 | if (io->io2.minimum) { | 3137 | if (io->io2.minimum) { |
2838 | if (request_region(io->io2.minimum, | 3138 | if (request_region(io->io2.minimum, |
2839 | io->io2.address_length, | 3139 | io->io2.address_length, |
2840 | "Sony Programable I/O Device")) { | 3140 | "Sony Programmable I/O Device")) { |
2841 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", | 3141 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", |
2842 | io->io2.minimum, io->io2.maximum, | 3142 | io->io2.minimum, io->io2.maximum, |
2843 | io->io2.address_length); | 3143 | io->io2.address_length); |
@@ -2860,7 +3160,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
2860 | } | 3160 | } |
2861 | } | 3161 | } |
2862 | if (!spic_dev.cur_ioport) { | 3162 | if (!spic_dev.cur_ioport) { |
2863 | printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); | 3163 | pr_err(DRV_PFX "Failed to request_region.\n"); |
2864 | result = -ENODEV; | 3164 | result = -ENODEV; |
2865 | goto err_remove_compat; | 3165 | goto err_remove_compat; |
2866 | } | 3166 | } |
@@ -2880,7 +3180,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
2880 | } | 3180 | } |
2881 | } | 3181 | } |
2882 | if (!spic_dev.cur_irq) { | 3182 | if (!spic_dev.cur_irq) { |
2883 | printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); | 3183 | pr_err(DRV_PFX "Failed to request_irq.\n"); |
2884 | result = -ENODEV; | 3184 | result = -ENODEV; |
2885 | goto err_release_region; | 3185 | goto err_release_region; |
2886 | } | 3186 | } |
@@ -2888,7 +3188,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
2888 | /* set resource status _SRS */ | 3188 | /* set resource status _SRS */ |
2889 | result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); | 3189 | result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); |
2890 | if (result) { | 3190 | if (result) { |
2891 | printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); | 3191 | pr_err(DRV_PFX "Couldn't enable device.\n"); |
2892 | goto err_free_irq; | 3192 | goto err_free_irq; |
2893 | } | 3193 | } |
2894 | 3194 | ||
@@ -2997,8 +3297,7 @@ static int __init sony_laptop_init(void) | |||
2997 | if (!no_spic && dmi_check_system(sonypi_dmi_table)) { | 3297 | if (!no_spic && dmi_check_system(sonypi_dmi_table)) { |
2998 | result = acpi_bus_register_driver(&sony_pic_driver); | 3298 | result = acpi_bus_register_driver(&sony_pic_driver); |
2999 | if (result) { | 3299 | if (result) { |
3000 | printk(KERN_ERR DRV_PFX | 3300 | pr_err(DRV_PFX "Unable to register SPIC driver."); |
3001 | "Unable to register SPIC driver."); | ||
3002 | goto out; | 3301 | goto out; |
3003 | } | 3302 | } |
3004 | spic_drv_registered = 1; | 3303 | spic_drv_registered = 1; |
@@ -3006,7 +3305,7 @@ static int __init sony_laptop_init(void) | |||
3006 | 3305 | ||
3007 | result = acpi_bus_register_driver(&sony_nc_driver); | 3306 | result = acpi_bus_register_driver(&sony_nc_driver); |
3008 | if (result) { | 3307 | if (result) { |
3009 | printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); | 3308 | pr_err(DRV_PFX "Unable to register SNC driver."); |
3010 | goto out_unregister_pic; | 3309 | goto out_unregister_pic; |
3011 | } | 3310 | } |
3012 | 3311 | ||
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 947bdcaa0ce9..a08561f5349e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -2407,7 +2407,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2407 | * This code is supposed to duplicate the IBM firmware behaviour: | 2407 | * This code is supposed to duplicate the IBM firmware behaviour: |
2408 | * - Pressing MUTE issues mute hotkey message, even when already mute | 2408 | * - Pressing MUTE issues mute hotkey message, even when already mute |
2409 | * - Pressing Volume up/down issues volume up/down hotkey messages, | 2409 | * - Pressing Volume up/down issues volume up/down hotkey messages, |
2410 | * even when already at maximum or minumum volume | 2410 | * even when already at maximum or minimum volume |
2411 | * - The act of unmuting issues volume up/down notification, | 2411 | * - The act of unmuting issues volume up/down notification, |
2412 | * depending which key was used to unmute | 2412 | * depending which key was used to unmute |
2413 | * | 2413 | * |
@@ -2990,7 +2990,7 @@ static void tpacpi_send_radiosw_update(void) | |||
2990 | * rfkill input events, or we will race the rfkill core input | 2990 | * rfkill input events, or we will race the rfkill core input |
2991 | * handler. | 2991 | * handler. |
2992 | * | 2992 | * |
2993 | * tpacpi_inputdev_send_mutex works as a syncronization point | 2993 | * tpacpi_inputdev_send_mutex works as a synchronization point |
2994 | * for the above. | 2994 | * for the above. |
2995 | * | 2995 | * |
2996 | * We optimize to avoid numerous calls to hotkey_get_wlsw. | 2996 | * We optimize to avoid numerous calls to hotkey_get_wlsw. |
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c new file mode 100644 index 000000000000..c1372ed9d2e9 --- /dev/null +++ b/drivers/platform/x86/xo15-ebook.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * OLPC XO-1.5 ebook switch driver | ||
3 | * (based on generic ACPI button driver) | ||
4 | * | ||
5 | * Copyright (C) 2009 Paul Fox <pgf@laptop.org> | ||
6 | * Copyright (C) 2010 One Laptop per Child | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
11 | * your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <acpi/acpi_bus.h> | ||
20 | #include <acpi/acpi_drivers.h> | ||
21 | |||
22 | #define MODULE_NAME "xo15-ebook" | ||
23 | #define PREFIX MODULE_NAME ": " | ||
24 | |||
25 | #define XO15_EBOOK_CLASS MODULE_NAME | ||
26 | #define XO15_EBOOK_TYPE_UNKNOWN 0x00 | ||
27 | #define XO15_EBOOK_NOTIFY_STATUS 0x80 | ||
28 | |||
29 | #define XO15_EBOOK_SUBCLASS "ebook" | ||
30 | #define XO15_EBOOK_HID "XO15EBK" | ||
31 | #define XO15_EBOOK_DEVICE_NAME "EBook Switch" | ||
32 | |||
33 | ACPI_MODULE_NAME(MODULE_NAME); | ||
34 | |||
35 | MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | static const struct acpi_device_id ebook_device_ids[] = { | ||
39 | { XO15_EBOOK_HID, 0 }, | ||
40 | { "", 0 }, | ||
41 | }; | ||
42 | MODULE_DEVICE_TABLE(acpi, ebook_device_ids); | ||
43 | |||
44 | struct ebook_switch { | ||
45 | struct input_dev *input; | ||
46 | char phys[32]; /* for input device */ | ||
47 | }; | ||
48 | |||
49 | static int ebook_send_state(struct acpi_device *device) | ||
50 | { | ||
51 | struct ebook_switch *button = acpi_driver_data(device); | ||
52 | unsigned long long state; | ||
53 | acpi_status status; | ||
54 | |||
55 | status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state); | ||
56 | if (ACPI_FAILURE(status)) | ||
57 | return -EIO; | ||
58 | |||
59 | /* input layer checks if event is redundant */ | ||
60 | input_report_switch(button->input, SW_TABLET_MODE, !state); | ||
61 | input_sync(button->input); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void ebook_switch_notify(struct acpi_device *device, u32 event) | ||
66 | { | ||
67 | switch (event) { | ||
68 | case ACPI_FIXED_HARDWARE_EVENT: | ||
69 | case XO15_EBOOK_NOTIFY_STATUS: | ||
70 | ebook_send_state(device); | ||
71 | break; | ||
72 | default: | ||
73 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
74 | "Unsupported event [0x%x]\n", event)); | ||
75 | break; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static int ebook_switch_resume(struct acpi_device *device) | ||
80 | { | ||
81 | return ebook_send_state(device); | ||
82 | } | ||
83 | |||
84 | static int ebook_switch_add(struct acpi_device *device) | ||
85 | { | ||
86 | struct ebook_switch *button; | ||
87 | struct input_dev *input; | ||
88 | const char *hid = acpi_device_hid(device); | ||
89 | char *name, *class; | ||
90 | int error; | ||
91 | |||
92 | button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL); | ||
93 | if (!button) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | device->driver_data = button; | ||
97 | |||
98 | button->input = input = input_allocate_device(); | ||
99 | if (!input) { | ||
100 | error = -ENOMEM; | ||
101 | goto err_free_button; | ||
102 | } | ||
103 | |||
104 | name = acpi_device_name(device); | ||
105 | class = acpi_device_class(device); | ||
106 | |||
107 | if (strcmp(hid, XO15_EBOOK_HID)) { | ||
108 | printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); | ||
109 | error = -ENODEV; | ||
110 | goto err_free_input; | ||
111 | } | ||
112 | |||
113 | strcpy(name, XO15_EBOOK_DEVICE_NAME); | ||
114 | sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS); | ||
115 | |||
116 | snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); | ||
117 | |||
118 | input->name = name; | ||
119 | input->phys = button->phys; | ||
120 | input->id.bustype = BUS_HOST; | ||
121 | input->dev.parent = &device->dev; | ||
122 | |||
123 | input->evbit[0] = BIT_MASK(EV_SW); | ||
124 | set_bit(SW_TABLET_MODE, input->swbit); | ||
125 | |||
126 | error = input_register_device(input); | ||
127 | if (error) | ||
128 | goto err_free_input; | ||
129 | |||
130 | ebook_send_state(device); | ||
131 | |||
132 | if (device->wakeup.flags.valid) { | ||
133 | /* Button's GPE is run-wake GPE */ | ||
134 | acpi_enable_gpe(device->wakeup.gpe_device, | ||
135 | device->wakeup.gpe_number); | ||
136 | device_set_wakeup_enable(&device->dev, true); | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | |||
141 | err_free_input: | ||
142 | input_free_device(input); | ||
143 | err_free_button: | ||
144 | kfree(button); | ||
145 | return error; | ||
146 | } | ||
147 | |||
148 | static int ebook_switch_remove(struct acpi_device *device, int type) | ||
149 | { | ||
150 | struct ebook_switch *button = acpi_driver_data(device); | ||
151 | |||
152 | input_unregister_device(button->input); | ||
153 | kfree(button); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static struct acpi_driver xo15_ebook_driver = { | ||
158 | .name = MODULE_NAME, | ||
159 | .class = XO15_EBOOK_CLASS, | ||
160 | .ids = ebook_device_ids, | ||
161 | .ops = { | ||
162 | .add = ebook_switch_add, | ||
163 | .resume = ebook_switch_resume, | ||
164 | .remove = ebook_switch_remove, | ||
165 | .notify = ebook_switch_notify, | ||
166 | }, | ||
167 | }; | ||
168 | |||
169 | static int __init xo15_ebook_init(void) | ||
170 | { | ||
171 | return acpi_bus_register_driver(&xo15_ebook_driver); | ||
172 | } | ||
173 | |||
174 | static void __exit xo15_ebook_exit(void) | ||
175 | { | ||
176 | acpi_bus_unregister_driver(&xo15_ebook_driver); | ||
177 | } | ||
178 | |||
179 | module_init(xo15_ebook_init); | ||
180 | module_exit(xo15_ebook_exit); | ||
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index 2a9ab89f83b8..e5ced3a4c1ed 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c | |||
@@ -215,8 +215,8 @@ static int __devinit z2_batt_probe(struct i2c_client *client, | |||
215 | if (ret) | 215 | if (ret) |
216 | goto err2; | 216 | goto err2; |
217 | 217 | ||
218 | set_irq_type(gpio_to_irq(info->charge_gpio), | 218 | irq_set_irq_type(gpio_to_irq(info->charge_gpio), |
219 | IRQ_TYPE_EDGE_BOTH); | 219 | IRQ_TYPE_EDGE_BOTH); |
220 | ret = request_irq(gpio_to_irq(info->charge_gpio), | 220 | ret = request_irq(gpio_to_irq(info->charge_gpio), |
221 | z2_charge_switch_irq, IRQF_DISABLED, | 221 | z2_charge_switch_irq, IRQF_DISABLED, |
222 | "AC Detect", charger); | 222 | "AC Detect", charger); |
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index e55dc1ac83ab..6ac55fd48413 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c | |||
@@ -782,11 +782,11 @@ static void sh_rtc_set_irq_wake(struct device *dev, int enabled) | |||
782 | struct platform_device *pdev = to_platform_device(dev); | 782 | struct platform_device *pdev = to_platform_device(dev); |
783 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | 783 | struct sh_rtc *rtc = platform_get_drvdata(pdev); |
784 | 784 | ||
785 | set_irq_wake(rtc->periodic_irq, enabled); | 785 | irq_set_irq_wake(rtc->periodic_irq, enabled); |
786 | 786 | ||
787 | if (rtc->carry_irq > 0) { | 787 | if (rtc->carry_irq > 0) { |
788 | set_irq_wake(rtc->carry_irq, enabled); | 788 | irq_set_irq_wake(rtc->carry_irq, enabled); |
789 | set_irq_wake(rtc->alarm_irq, enabled); | 789 | irq_set_irq_wake(rtc->alarm_irq, enabled); |
790 | } | 790 | } |
791 | } | 791 | } |
792 | 792 | ||
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 5833afbf08d7..c6ca115c71df 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c | |||
@@ -63,7 +63,7 @@ void intc_set_prio_level(unsigned int irq, unsigned int level) | |||
63 | 63 | ||
64 | static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) | 64 | static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) |
65 | { | 65 | { |
66 | generic_handle_irq((unsigned int)get_irq_data(irq)); | 66 | generic_handle_irq((unsigned int)irq_get_handler_data(irq)); |
67 | } | 67 | } |
68 | 68 | ||
69 | static void __init intc_register_irq(struct intc_desc *desc, | 69 | static void __init intc_register_irq(struct intc_desc *desc, |
@@ -116,9 +116,9 @@ static void __init intc_register_irq(struct intc_desc *desc, | |||
116 | irq_data = irq_get_irq_data(irq); | 116 | irq_data = irq_get_irq_data(irq); |
117 | 117 | ||
118 | disable_irq_nosync(irq); | 118 | disable_irq_nosync(irq); |
119 | set_irq_chip_and_handler_name(irq, &d->chip, | 119 | irq_set_chip_and_handler_name(irq, &d->chip, handle_level_irq, |
120 | handle_level_irq, "level"); | 120 | "level"); |
121 | set_irq_chip_data(irq, (void *)data[primary]); | 121 | irq_set_chip_data(irq, (void *)data[primary]); |
122 | 122 | ||
123 | /* | 123 | /* |
124 | * set priority level | 124 | * set priority level |
@@ -340,9 +340,9 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
340 | vect2->enum_id = 0; | 340 | vect2->enum_id = 0; |
341 | 341 | ||
342 | /* redirect this interrupts to the first one */ | 342 | /* redirect this interrupts to the first one */ |
343 | set_irq_chip(irq2, &dummy_irq_chip); | 343 | irq_set_chip(irq2, &dummy_irq_chip); |
344 | set_irq_chained_handler(irq2, intc_redirect_irq); | 344 | irq_set_chained_handler(irq2, intc_redirect_irq); |
345 | set_irq_data(irq2, (void *)irq); | 345 | irq_set_handler_data(irq2, (void *)irq); |
346 | } | 346 | } |
347 | } | 347 | } |
348 | 348 | ||
@@ -387,19 +387,16 @@ static int intc_suspend(void) | |||
387 | /* enable wakeup irqs belonging to this intc controller */ | 387 | /* enable wakeup irqs belonging to this intc controller */ |
388 | for_each_active_irq(irq) { | 388 | for_each_active_irq(irq) { |
389 | struct irq_data *data; | 389 | struct irq_data *data; |
390 | struct irq_desc *desc; | ||
391 | struct irq_chip *chip; | 390 | struct irq_chip *chip; |
392 | 391 | ||
393 | data = irq_get_irq_data(irq); | 392 | data = irq_get_irq_data(irq); |
394 | chip = irq_data_get_irq_chip(data); | 393 | chip = irq_data_get_irq_chip(data); |
395 | if (chip != &d->chip) | 394 | if (chip != &d->chip) |
396 | continue; | 395 | continue; |
397 | desc = irq_to_desc(irq); | 396 | if (irqd_is_wakeup_set(data)) |
398 | if ((desc->status & IRQ_WAKEUP)) | ||
399 | chip->irq_enable(data); | 397 | chip->irq_enable(data); |
400 | } | 398 | } |
401 | } | 399 | } |
402 | |||
403 | return 0; | 400 | return 0; |
404 | } | 401 | } |
405 | 402 | ||
@@ -412,7 +409,6 @@ static void intc_resume(void) | |||
412 | 409 | ||
413 | for_each_active_irq(irq) { | 410 | for_each_active_irq(irq) { |
414 | struct irq_data *data; | 411 | struct irq_data *data; |
415 | struct irq_desc *desc; | ||
416 | struct irq_chip *chip; | 412 | struct irq_chip *chip; |
417 | 413 | ||
418 | data = irq_get_irq_data(irq); | 414 | data = irq_get_irq_data(irq); |
@@ -423,8 +419,7 @@ static void intc_resume(void) | |||
423 | */ | 419 | */ |
424 | if (chip != &d->chip) | 420 | if (chip != &d->chip) |
425 | continue; | 421 | continue; |
426 | desc = irq_to_desc(irq); | 422 | if (irqd_irq_disabled(data)) |
427 | if (desc->status & IRQ_DISABLED) | ||
428 | chip->irq_disable(data); | 423 | chip->irq_disable(data); |
429 | else | 424 | else |
430 | chip->irq_enable(data); | 425 | chip->irq_enable(data); |
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index 4e0ff7181164..ce5f81d7cc6b 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c | |||
@@ -110,7 +110,7 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) | |||
110 | { | 110 | { |
111 | struct irq_data *data = irq_get_irq_data(irq); | 111 | struct irq_data *data = irq_get_irq_data(irq); |
112 | struct irq_chip *chip = irq_data_get_irq_chip(data); | 112 | struct irq_chip *chip = irq_data_get_irq_chip(data); |
113 | struct intc_virq_list *entry, *vlist = irq_data_get_irq_data(data); | 113 | struct intc_virq_list *entry, *vlist = irq_data_get_irq_handler_data(data); |
114 | struct intc_desc_int *d = get_intc_desc(irq); | 114 | struct intc_desc_int *d = get_intc_desc(irq); |
115 | 115 | ||
116 | chip->irq_mask_ack(data); | 116 | chip->irq_mask_ack(data); |
@@ -118,7 +118,7 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) | |||
118 | for_each_virq(entry, vlist) { | 118 | for_each_virq(entry, vlist) { |
119 | unsigned long addr, handle; | 119 | unsigned long addr, handle; |
120 | 120 | ||
121 | handle = (unsigned long)get_irq_data(entry->irq); | 121 | handle = (unsigned long)irq_get_handler_data(entry->irq); |
122 | addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); | 122 | addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); |
123 | 123 | ||
124 | if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) | 124 | if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) |
@@ -229,13 +229,13 @@ restart: | |||
229 | 229 | ||
230 | intc_irq_xlate_set(irq, entry->enum_id, d); | 230 | intc_irq_xlate_set(irq, entry->enum_id, d); |
231 | 231 | ||
232 | set_irq_chip_and_handler_name(irq, get_irq_chip(entry->pirq), | 232 | irq_set_chip_and_handler_name(irq, irq_get_chip(entry->pirq), |
233 | handle_simple_irq, "virq"); | 233 | handle_simple_irq, "virq"); |
234 | set_irq_chip_data(irq, get_irq_chip_data(entry->pirq)); | 234 | irq_set_chip_data(irq, irq_get_chip_data(entry->pirq)); |
235 | 235 | ||
236 | set_irq_data(irq, (void *)entry->handle); | 236 | irq_set_handler_data(irq, (void *)entry->handle); |
237 | 237 | ||
238 | set_irq_chained_handler(entry->pirq, intc_virq_handler); | 238 | irq_set_chained_handler(entry->pirq, intc_virq_handler); |
239 | add_virq_to_pirq(entry->pirq, irq); | 239 | add_virq_to_pirq(entry->pirq, irq); |
240 | 240 | ||
241 | radix_tree_tag_clear(&d->tree, entry->enum_id, | 241 | radix_tree_tag_clear(&d->tree, entry->enum_id, |
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index e3556ff43bb9..ac5bbc8722e5 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | |||
@@ -341,7 +341,7 @@ int bcmsdh_register_oob_intr(void *dhdp) | |||
341 | if (error) | 341 | if (error) |
342 | return -ENODEV; | 342 | return -ENODEV; |
343 | 343 | ||
344 | set_irq_wake(sdhcinfo->oob_irq, 1); | 344 | irq_set_irq_wake(sdhcinfo->oob_irq, 1); |
345 | sdhcinfo->oob_irq_registered = true; | 345 | sdhcinfo->oob_irq_registered = true; |
346 | } | 346 | } |
347 | 347 | ||
@@ -352,7 +352,7 @@ void bcmsdh_unregister_oob_intr(void) | |||
352 | { | 352 | { |
353 | SDLX_MSG(("%s: Enter\n", __func__)); | 353 | SDLX_MSG(("%s: Enter\n", __func__)); |
354 | 354 | ||
355 | set_irq_wake(sdhcinfo->oob_irq, 0); | 355 | irq_set_irq_wake(sdhcinfo->oob_irq, 0); |
356 | disable_irq(sdhcinfo->oob_irq); /* just in case.. */ | 356 | disable_irq(sdhcinfo->oob_irq); /* just in case.. */ |
357 | free_irq(sdhcinfo->oob_irq, NULL); | 357 | free_irq(sdhcinfo->oob_irq, NULL); |
358 | sdhcinfo->oob_irq_registered = false; | 358 | sdhcinfo->oob_irq_registered = false; |
diff --git a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c index ea9b733c3926..21cdb0637beb 100644 --- a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c +++ b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c | |||
@@ -597,7 +597,7 @@ static int cy_as_hal_configure_interrupts(void *dev_p) | |||
597 | int result; | 597 | int result; |
598 | int irq_pin = AST_INT; | 598 | int irq_pin = AST_INT; |
599 | 599 | ||
600 | set_irq_type(OMAP_GPIO_IRQ(irq_pin), IRQ_TYPE_LEVEL_LOW); | 600 | irq_set_irq_type(OMAP_GPIO_IRQ(irq_pin), IRQ_TYPE_LEVEL_LOW); |
601 | 601 | ||
602 | /* | 602 | /* |
603 | * for shared IRQS must provide non NULL device ptr | 603 | * for shared IRQS must provide non NULL device ptr |
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index c35f1a73bc8b..52fdf60bdbe2 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c | |||
@@ -178,7 +178,7 @@ static int __init xen_hvc_init(void) | |||
178 | if (xencons_irq < 0) | 178 | if (xencons_irq < 0) |
179 | xencons_irq = 0; /* NO_IRQ */ | 179 | xencons_irq = 0; /* NO_IRQ */ |
180 | else | 180 | else |
181 | set_irq_noprobe(xencons_irq); | 181 | irq_set_noprobe(xencons_irq); |
182 | 182 | ||
183 | hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); | 183 | hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); |
184 | if (IS_ERR(hp)) | 184 | if (IS_ERR(hp)) |
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 2e7fc9cee9cc..b906f11f7c1a 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c | |||
@@ -1644,7 +1644,7 @@ static int __devinit msm_hs_probe(struct platform_device *pdev) | |||
1644 | if (unlikely(uport->irq < 0)) | 1644 | if (unlikely(uport->irq < 0)) |
1645 | return -ENXIO; | 1645 | return -ENXIO; |
1646 | 1646 | ||
1647 | if (unlikely(set_irq_wake(uport->irq, 1))) | 1647 | if (unlikely(irq_set_irq_wake(uport->irq, 1))) |
1648 | return -ENXIO; | 1648 | return -ENXIO; |
1649 | 1649 | ||
1650 | if (pdata == NULL || pdata->rx_wakeup_irq < 0) | 1650 | if (pdata == NULL || pdata->rx_wakeup_irq < 0) |
@@ -1658,7 +1658,7 @@ static int __devinit msm_hs_probe(struct platform_device *pdev) | |||
1658 | if (unlikely(msm_uport->rx_wakeup.irq < 0)) | 1658 | if (unlikely(msm_uport->rx_wakeup.irq < 0)) |
1659 | return -ENXIO; | 1659 | return -ENXIO; |
1660 | 1660 | ||
1661 | if (unlikely(set_irq_wake(msm_uport->rx_wakeup.irq, 1))) | 1661 | if (unlikely(irq_set_irq_wake(msm_uport->rx_wakeup.irq, 1))) |
1662 | return -ENXIO; | 1662 | return -ENXIO; |
1663 | } | 1663 | } |
1664 | 1664 | ||
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 38193f4e980e..44e4deb362e1 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c | |||
@@ -3832,7 +3832,7 @@ static int oxu_drv_probe(struct platform_device *pdev) | |||
3832 | return -EBUSY; | 3832 | return -EBUSY; |
3833 | } | 3833 | } |
3834 | 3834 | ||
3835 | ret = set_irq_type(irq, IRQF_TRIGGER_FALLING); | 3835 | ret = irq_set_irq_type(irq, IRQF_TRIGGER_FALLING); |
3836 | if (ret) { | 3836 | if (ret) { |
3837 | dev_err(&pdev->dev, "error setting irq type\n"); | 3837 | dev_err(&pdev->dev, "error setting irq type\n"); |
3838 | ret = -EFAULT; | 3838 | ret = -EFAULT; |
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2ba3b070ed0b..c47aac4a1f98 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c | |||
@@ -943,7 +943,7 @@ static void tusb_musb_enable(struct musb *musb) | |||
943 | musb_writel(tbase, TUSB_INT_CTRL_CONF, | 943 | musb_writel(tbase, TUSB_INT_CTRL_CONF, |
944 | TUSB_INT_CTRL_CONF_INT_RELCYC(0)); | 944 | TUSB_INT_CTRL_CONF_INT_RELCYC(0)); |
945 | 945 | ||
946 | set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW); | 946 | irq_set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW); |
947 | 947 | ||
948 | /* maybe force into the Default-A OTG state machine */ | 948 | /* maybe force into the Default-A OTG state machine */ |
949 | if (!(musb_readl(tbase, TUSB_DEV_OTG_STAT) | 949 | if (!(musb_readl(tbase, TUSB_DEV_OTG_STAT) |
diff --git a/drivers/vlynq/vlynq.c b/drivers/vlynq/vlynq.c index f885c868a04d..aa250cebecd2 100644 --- a/drivers/vlynq/vlynq.c +++ b/drivers/vlynq/vlynq.c | |||
@@ -135,40 +135,40 @@ static void vlynq_reset(struct vlynq_device *dev) | |||
135 | msleep(5); | 135 | msleep(5); |
136 | } | 136 | } |
137 | 137 | ||
138 | static void vlynq_irq_unmask(unsigned int irq) | 138 | static void vlynq_irq_unmask(struct irq_data *d) |
139 | { | 139 | { |
140 | u32 val; | 140 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
141 | struct vlynq_device *dev = get_irq_chip_data(irq); | ||
142 | int virq; | 141 | int virq; |
142 | u32 val; | ||
143 | 143 | ||
144 | BUG_ON(!dev); | 144 | BUG_ON(!dev); |
145 | virq = irq - dev->irq_start; | 145 | virq = d->irq - dev->irq_start; |
146 | val = readl(&dev->remote->int_device[virq >> 2]); | 146 | val = readl(&dev->remote->int_device[virq >> 2]); |
147 | val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq); | 147 | val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq); |
148 | writel(val, &dev->remote->int_device[virq >> 2]); | 148 | writel(val, &dev->remote->int_device[virq >> 2]); |
149 | } | 149 | } |
150 | 150 | ||
151 | static void vlynq_irq_mask(unsigned int irq) | 151 | static void vlynq_irq_mask(struct irq_data *d) |
152 | { | 152 | { |
153 | u32 val; | 153 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
154 | struct vlynq_device *dev = get_irq_chip_data(irq); | ||
155 | int virq; | 154 | int virq; |
155 | u32 val; | ||
156 | 156 | ||
157 | BUG_ON(!dev); | 157 | BUG_ON(!dev); |
158 | virq = irq - dev->irq_start; | 158 | virq = d->irq - dev->irq_start; |
159 | val = readl(&dev->remote->int_device[virq >> 2]); | 159 | val = readl(&dev->remote->int_device[virq >> 2]); |
160 | val &= ~(VINT_ENABLE << VINT_OFFSET(virq)); | 160 | val &= ~(VINT_ENABLE << VINT_OFFSET(virq)); |
161 | writel(val, &dev->remote->int_device[virq >> 2]); | 161 | writel(val, &dev->remote->int_device[virq >> 2]); |
162 | } | 162 | } |
163 | 163 | ||
164 | static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) | 164 | static int vlynq_irq_type(struct irq_data *d, unsigned int flow_type) |
165 | { | 165 | { |
166 | u32 val; | 166 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
167 | struct vlynq_device *dev = get_irq_chip_data(irq); | ||
168 | int virq; | 167 | int virq; |
168 | u32 val; | ||
169 | 169 | ||
170 | BUG_ON(!dev); | 170 | BUG_ON(!dev); |
171 | virq = irq - dev->irq_start; | 171 | virq = d->irq - dev->irq_start; |
172 | val = readl(&dev->remote->int_device[virq >> 2]); | 172 | val = readl(&dev->remote->int_device[virq >> 2]); |
173 | switch (flow_type & IRQ_TYPE_SENSE_MASK) { | 173 | switch (flow_type & IRQ_TYPE_SENSE_MASK) { |
174 | case IRQ_TYPE_EDGE_RISING: | 174 | case IRQ_TYPE_EDGE_RISING: |
@@ -192,10 +192,9 @@ static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) | |||
192 | return 0; | 192 | return 0; |
193 | } | 193 | } |
194 | 194 | ||
195 | static void vlynq_local_ack(unsigned int irq) | 195 | static void vlynq_local_ack(struct irq_data *d) |
196 | { | 196 | { |
197 | struct vlynq_device *dev = get_irq_chip_data(irq); | 197 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
198 | |||
199 | u32 status = readl(&dev->local->status); | 198 | u32 status = readl(&dev->local->status); |
200 | 199 | ||
201 | pr_debug("%s: local status: 0x%08x\n", | 200 | pr_debug("%s: local status: 0x%08x\n", |
@@ -203,10 +202,9 @@ static void vlynq_local_ack(unsigned int irq) | |||
203 | writel(status, &dev->local->status); | 202 | writel(status, &dev->local->status); |
204 | } | 203 | } |
205 | 204 | ||
206 | static void vlynq_remote_ack(unsigned int irq) | 205 | static void vlynq_remote_ack(struct irq_data *d) |
207 | { | 206 | { |
208 | struct vlynq_device *dev = get_irq_chip_data(irq); | 207 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
209 | |||
210 | u32 status = readl(&dev->remote->status); | 208 | u32 status = readl(&dev->remote->status); |
211 | 209 | ||
212 | pr_debug("%s: remote status: 0x%08x\n", | 210 | pr_debug("%s: remote status: 0x%08x\n", |
@@ -238,23 +236,23 @@ static irqreturn_t vlynq_irq(int irq, void *dev_id) | |||
238 | 236 | ||
239 | static struct irq_chip vlynq_irq_chip = { | 237 | static struct irq_chip vlynq_irq_chip = { |
240 | .name = "vlynq", | 238 | .name = "vlynq", |
241 | .unmask = vlynq_irq_unmask, | 239 | .irq_unmask = vlynq_irq_unmask, |
242 | .mask = vlynq_irq_mask, | 240 | .irq_mask = vlynq_irq_mask, |
243 | .set_type = vlynq_irq_type, | 241 | .irq_set_type = vlynq_irq_type, |
244 | }; | 242 | }; |
245 | 243 | ||
246 | static struct irq_chip vlynq_local_chip = { | 244 | static struct irq_chip vlynq_local_chip = { |
247 | .name = "vlynq local error", | 245 | .name = "vlynq local error", |
248 | .unmask = vlynq_irq_unmask, | 246 | .irq_unmask = vlynq_irq_unmask, |
249 | .mask = vlynq_irq_mask, | 247 | .irq_mask = vlynq_irq_mask, |
250 | .ack = vlynq_local_ack, | 248 | .irq_ack = vlynq_local_ack, |
251 | }; | 249 | }; |
252 | 250 | ||
253 | static struct irq_chip vlynq_remote_chip = { | 251 | static struct irq_chip vlynq_remote_chip = { |
254 | .name = "vlynq local error", | 252 | .name = "vlynq local error", |
255 | .unmask = vlynq_irq_unmask, | 253 | .irq_unmask = vlynq_irq_unmask, |
256 | .mask = vlynq_irq_mask, | 254 | .irq_mask = vlynq_irq_mask, |
257 | .ack = vlynq_remote_ack, | 255 | .irq_ack = vlynq_remote_ack, |
258 | }; | 256 | }; |
259 | 257 | ||
260 | static int vlynq_setup_irq(struct vlynq_device *dev) | 258 | static int vlynq_setup_irq(struct vlynq_device *dev) |
@@ -291,17 +289,17 @@ static int vlynq_setup_irq(struct vlynq_device *dev) | |||
291 | for (i = dev->irq_start; i <= dev->irq_end; i++) { | 289 | for (i = dev->irq_start; i <= dev->irq_end; i++) { |
292 | virq = i - dev->irq_start; | 290 | virq = i - dev->irq_start; |
293 | if (virq == dev->local_irq) { | 291 | if (virq == dev->local_irq) { |
294 | set_irq_chip_and_handler(i, &vlynq_local_chip, | 292 | irq_set_chip_and_handler(i, &vlynq_local_chip, |
295 | handle_level_irq); | 293 | handle_level_irq); |
296 | set_irq_chip_data(i, dev); | 294 | irq_set_chip_data(i, dev); |
297 | } else if (virq == dev->remote_irq) { | 295 | } else if (virq == dev->remote_irq) { |
298 | set_irq_chip_and_handler(i, &vlynq_remote_chip, | 296 | irq_set_chip_and_handler(i, &vlynq_remote_chip, |
299 | handle_level_irq); | 297 | handle_level_irq); |
300 | set_irq_chip_data(i, dev); | 298 | irq_set_chip_data(i, dev); |
301 | } else { | 299 | } else { |
302 | set_irq_chip_and_handler(i, &vlynq_irq_chip, | 300 | irq_set_chip_and_handler(i, &vlynq_irq_chip, |
303 | handle_simple_irq); | 301 | handle_simple_irq); |
304 | set_irq_chip_data(i, dev); | 302 | irq_set_chip_data(i, dev); |
305 | writel(0, &dev->remote->int_device[virq >> 2]); | 303 | writel(0, &dev->remote->int_device[virq >> 2]); |
306 | } | 304 | } |
307 | } | 305 | } |
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 95921b77cf86..2f4fa02744a5 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c | |||
@@ -368,9 +368,9 @@ static int ds1wm_probe(struct platform_device *pdev) | |||
368 | ds1wm_data->active_high = plat->active_high; | 368 | ds1wm_data->active_high = plat->active_high; |
369 | 369 | ||
370 | if (res->flags & IORESOURCE_IRQ_HIGHEDGE) | 370 | if (res->flags & IORESOURCE_IRQ_HIGHEDGE) |
371 | set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); | 371 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); |
372 | if (res->flags & IORESOURCE_IRQ_LOWEDGE) | 372 | if (res->flags & IORESOURCE_IRQ_LOWEDGE) |
373 | set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); | 373 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); |
374 | 374 | ||
375 | ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED, | 375 | ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED, |
376 | "ds1wm", ds1wm_data); | 376 | "ds1wm", ds1wm_data); |
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 596ba604e78d..51b5551b4e3f 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c | |||
@@ -202,7 +202,6 @@ static struct miscdevice davinci_wdt_miscdev = { | |||
202 | static int __devinit davinci_wdt_probe(struct platform_device *pdev) | 202 | static int __devinit davinci_wdt_probe(struct platform_device *pdev) |
203 | { | 203 | { |
204 | int ret = 0, size; | 204 | int ret = 0, size; |
205 | struct resource *res; | ||
206 | struct device *dev = &pdev->dev; | 205 | struct device *dev = &pdev->dev; |
207 | 206 | ||
208 | wdt_clk = clk_get(dev, NULL); | 207 | wdt_clk = clk_get(dev, NULL); |
@@ -216,31 +215,31 @@ static int __devinit davinci_wdt_probe(struct platform_device *pdev) | |||
216 | 215 | ||
217 | dev_info(dev, "heartbeat %d sec\n", heartbeat); | 216 | dev_info(dev, "heartbeat %d sec\n", heartbeat); |
218 | 217 | ||
219 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 218 | wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
220 | if (res == NULL) { | 219 | if (wdt_mem == NULL) { |
221 | dev_err(dev, "failed to get memory region resource\n"); | 220 | dev_err(dev, "failed to get memory region resource\n"); |
222 | return -ENOENT; | 221 | return -ENOENT; |
223 | } | 222 | } |
224 | 223 | ||
225 | size = resource_size(res); | 224 | size = resource_size(wdt_mem); |
226 | wdt_mem = request_mem_region(res->start, size, pdev->name); | 225 | if (!request_mem_region(wdt_mem->start, size, pdev->name)) { |
227 | |||
228 | if (wdt_mem == NULL) { | ||
229 | dev_err(dev, "failed to get memory region\n"); | 226 | dev_err(dev, "failed to get memory region\n"); |
230 | return -ENOENT; | 227 | return -ENOENT; |
231 | } | 228 | } |
232 | 229 | ||
233 | wdt_base = ioremap(res->start, size); | 230 | wdt_base = ioremap(wdt_mem->start, size); |
234 | if (!wdt_base) { | 231 | if (!wdt_base) { |
235 | dev_err(dev, "failed to map memory region\n"); | 232 | dev_err(dev, "failed to map memory region\n"); |
233 | release_mem_region(wdt_mem->start, size); | ||
234 | wdt_mem = NULL; | ||
236 | return -ENOMEM; | 235 | return -ENOMEM; |
237 | } | 236 | } |
238 | 237 | ||
239 | ret = misc_register(&davinci_wdt_miscdev); | 238 | ret = misc_register(&davinci_wdt_miscdev); |
240 | if (ret < 0) { | 239 | if (ret < 0) { |
241 | dev_err(dev, "cannot register misc device\n"); | 240 | dev_err(dev, "cannot register misc device\n"); |
242 | release_resource(wdt_mem); | 241 | release_mem_region(wdt_mem->start, size); |
243 | kfree(wdt_mem); | 242 | wdt_mem = NULL; |
244 | } else { | 243 | } else { |
245 | set_bit(WDT_DEVICE_INITED, &wdt_status); | 244 | set_bit(WDT_DEVICE_INITED, &wdt_status); |
246 | } | 245 | } |
@@ -253,8 +252,7 @@ static int __devexit davinci_wdt_remove(struct platform_device *pdev) | |||
253 | { | 252 | { |
254 | misc_deregister(&davinci_wdt_miscdev); | 253 | misc_deregister(&davinci_wdt_miscdev); |
255 | if (wdt_mem) { | 254 | if (wdt_mem) { |
256 | release_resource(wdt_mem); | 255 | release_mem_region(wdt_mem->start, resource_size(wdt_mem)); |
257 | kfree(wdt_mem); | ||
258 | wdt_mem = NULL; | 256 | wdt_mem = NULL; |
259 | } | 257 | } |
260 | 258 | ||
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c index 7a82ce5a6337..73ba2fd8e591 100644 --- a/drivers/watchdog/max63xx_wdt.c +++ b/drivers/watchdog/max63xx_wdt.c | |||
@@ -270,7 +270,6 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev) | |||
270 | { | 270 | { |
271 | int ret = 0; | 271 | int ret = 0; |
272 | int size; | 272 | int size; |
273 | struct resource *res; | ||
274 | struct device *dev = &pdev->dev; | 273 | struct device *dev = &pdev->dev; |
275 | struct max63xx_timeout *table; | 274 | struct max63xx_timeout *table; |
276 | 275 | ||
@@ -294,21 +293,19 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev) | |||
294 | 293 | ||
295 | max63xx_pdev = pdev; | 294 | max63xx_pdev = pdev; |
296 | 295 | ||
297 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 296 | wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
298 | if (res == NULL) { | 297 | if (wdt_mem == NULL) { |
299 | dev_err(dev, "failed to get memory region resource\n"); | 298 | dev_err(dev, "failed to get memory region resource\n"); |
300 | return -ENOENT; | 299 | return -ENOENT; |
301 | } | 300 | } |
302 | 301 | ||
303 | size = resource_size(res); | 302 | size = resource_size(wdt_mem); |
304 | wdt_mem = request_mem_region(res->start, size, pdev->name); | 303 | if (!request_mem_region(wdt_mem->start, size, pdev->name)) { |
305 | |||
306 | if (wdt_mem == NULL) { | ||
307 | dev_err(dev, "failed to get memory region\n"); | 304 | dev_err(dev, "failed to get memory region\n"); |
308 | return -ENOENT; | 305 | return -ENOENT; |
309 | } | 306 | } |
310 | 307 | ||
311 | wdt_base = ioremap(res->start, size); | 308 | wdt_base = ioremap(wdt_mem->start, size); |
312 | if (!wdt_base) { | 309 | if (!wdt_base) { |
313 | dev_err(dev, "failed to map memory region\n"); | 310 | dev_err(dev, "failed to map memory region\n"); |
314 | ret = -ENOMEM; | 311 | ret = -ENOMEM; |
@@ -326,8 +323,8 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev) | |||
326 | out_unmap: | 323 | out_unmap: |
327 | iounmap(wdt_base); | 324 | iounmap(wdt_base); |
328 | out_request: | 325 | out_request: |
329 | release_resource(wdt_mem); | 326 | release_mem_region(wdt_mem->start, size); |
330 | kfree(wdt_mem); | 327 | wdt_mem = NULL; |
331 | 328 | ||
332 | return ret; | 329 | return ret; |
333 | } | 330 | } |
@@ -336,8 +333,7 @@ static int __devexit max63xx_wdt_remove(struct platform_device *pdev) | |||
336 | { | 333 | { |
337 | misc_deregister(&max63xx_wdt_miscdev); | 334 | misc_deregister(&max63xx_wdt_miscdev); |
338 | if (wdt_mem) { | 335 | if (wdt_mem) { |
339 | release_resource(wdt_mem); | 336 | release_mem_region(wdt_mem->start, resource_size(wdt_mem)); |
340 | kfree(wdt_mem); | ||
341 | wdt_mem = NULL; | 337 | wdt_mem = NULL; |
342 | } | 338 | } |
343 | 339 | ||
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c index 267377a5a83e..afa78a54711e 100644 --- a/drivers/watchdog/nv_tco.c +++ b/drivers/watchdog/nv_tco.c | |||
@@ -302,7 +302,7 @@ MODULE_DEVICE_TABLE(pci, tco_pci_tbl); | |||
302 | * Init & exit routines | 302 | * Init & exit routines |
303 | */ | 303 | */ |
304 | 304 | ||
305 | static unsigned char __init nv_tco_getdevice(void) | 305 | static unsigned char __devinit nv_tco_getdevice(void) |
306 | { | 306 | { |
307 | struct pci_dev *dev = NULL; | 307 | struct pci_dev *dev = NULL; |
308 | u32 val; | 308 | u32 val; |
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index c7cf4cbf8ab3..614933225560 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c | |||
@@ -254,7 +254,6 @@ static struct miscdevice pnx4008_wdt_miscdev = { | |||
254 | static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) | 254 | static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) |
255 | { | 255 | { |
256 | int ret = 0, size; | 256 | int ret = 0, size; |
257 | struct resource *res; | ||
258 | 257 | ||
259 | if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) | 258 | if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) |
260 | heartbeat = DEFAULT_HEARTBEAT; | 259 | heartbeat = DEFAULT_HEARTBEAT; |
@@ -262,42 +261,42 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) | |||
262 | printk(KERN_INFO MODULE_NAME | 261 | printk(KERN_INFO MODULE_NAME |
263 | "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat); | 262 | "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat); |
264 | 263 | ||
265 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 264 | wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
266 | if (res == NULL) { | 265 | if (wdt_mem == NULL) { |
267 | printk(KERN_INFO MODULE_NAME | 266 | printk(KERN_INFO MODULE_NAME |
268 | "failed to get memory region resouce\n"); | 267 | "failed to get memory region resouce\n"); |
269 | return -ENOENT; | 268 | return -ENOENT; |
270 | } | 269 | } |
271 | 270 | ||
272 | size = resource_size(res); | 271 | size = resource_size(wdt_mem); |
273 | wdt_mem = request_mem_region(res->start, size, pdev->name); | ||
274 | 272 | ||
275 | if (wdt_mem == NULL) { | 273 | if (!request_mem_region(wdt_mem->start, size, pdev->name)) { |
276 | printk(KERN_INFO MODULE_NAME "failed to get memory region\n"); | 274 | printk(KERN_INFO MODULE_NAME "failed to get memory region\n"); |
277 | return -ENOENT; | 275 | return -ENOENT; |
278 | } | 276 | } |
279 | wdt_base = (void __iomem *)IO_ADDRESS(res->start); | 277 | wdt_base = (void __iomem *)IO_ADDRESS(wdt_mem->start); |
280 | 278 | ||
281 | wdt_clk = clk_get(&pdev->dev, NULL); | 279 | wdt_clk = clk_get(&pdev->dev, NULL); |
282 | if (IS_ERR(wdt_clk)) { | 280 | if (IS_ERR(wdt_clk)) { |
283 | ret = PTR_ERR(wdt_clk); | 281 | ret = PTR_ERR(wdt_clk); |
284 | release_resource(wdt_mem); | 282 | release_mem_region(wdt_mem->start, size); |
285 | kfree(wdt_mem); | 283 | wdt_mem = NULL; |
286 | goto out; | 284 | goto out; |
287 | } | 285 | } |
288 | 286 | ||
289 | ret = clk_enable(wdt_clk); | 287 | ret = clk_enable(wdt_clk); |
290 | if (ret) { | 288 | if (ret) { |
291 | release_resource(wdt_mem); | 289 | release_mem_region(wdt_mem->start, size); |
292 | kfree(wdt_mem); | 290 | wdt_mem = NULL; |
291 | clk_put(wdt_clk); | ||
293 | goto out; | 292 | goto out; |
294 | } | 293 | } |
295 | 294 | ||
296 | ret = misc_register(&pnx4008_wdt_miscdev); | 295 | ret = misc_register(&pnx4008_wdt_miscdev); |
297 | if (ret < 0) { | 296 | if (ret < 0) { |
298 | printk(KERN_ERR MODULE_NAME "cannot register misc device\n"); | 297 | printk(KERN_ERR MODULE_NAME "cannot register misc device\n"); |
299 | release_resource(wdt_mem); | 298 | release_mem_region(wdt_mem->start, size); |
300 | kfree(wdt_mem); | 299 | wdt_mem = NULL; |
301 | clk_disable(wdt_clk); | 300 | clk_disable(wdt_clk); |
302 | clk_put(wdt_clk); | 301 | clk_put(wdt_clk); |
303 | } else { | 302 | } else { |
@@ -320,8 +319,7 @@ static int __devexit pnx4008_wdt_remove(struct platform_device *pdev) | |||
320 | clk_put(wdt_clk); | 319 | clk_put(wdt_clk); |
321 | 320 | ||
322 | if (wdt_mem) { | 321 | if (wdt_mem) { |
323 | release_resource(wdt_mem); | 322 | release_mem_region(wdt_mem->start, resource_size(wdt_mem)); |
324 | kfree(wdt_mem); | ||
325 | wdt_mem = NULL; | 323 | wdt_mem = NULL; |
326 | } | 324 | } |
327 | return 0; | 325 | return 0; |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 25b39bf35925..f7f5aa00df60 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
@@ -402,7 +402,6 @@ static inline void s3c2410wdt_cpufreq_deregister(void) | |||
402 | 402 | ||
403 | static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | 403 | static int __devinit s3c2410wdt_probe(struct platform_device *pdev) |
404 | { | 404 | { |
405 | struct resource *res; | ||
406 | struct device *dev; | 405 | struct device *dev; |
407 | unsigned int wtcon; | 406 | unsigned int wtcon; |
408 | int started = 0; | 407 | int started = 0; |
@@ -416,20 +415,19 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
416 | 415 | ||
417 | /* get the memory region for the watchdog timer */ | 416 | /* get the memory region for the watchdog timer */ |
418 | 417 | ||
419 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 418 | wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
420 | if (res == NULL) { | 419 | if (wdt_mem == NULL) { |
421 | dev_err(dev, "no memory resource specified\n"); | 420 | dev_err(dev, "no memory resource specified\n"); |
422 | return -ENOENT; | 421 | return -ENOENT; |
423 | } | 422 | } |
424 | 423 | ||
425 | size = resource_size(res); | 424 | size = resource_size(wdt_mem); |
426 | wdt_mem = request_mem_region(res->start, size, pdev->name); | 425 | if (!request_mem_region(wdt_mem->start, size, pdev->name)) { |
427 | if (wdt_mem == NULL) { | ||
428 | dev_err(dev, "failed to get memory region\n"); | 426 | dev_err(dev, "failed to get memory region\n"); |
429 | return -EBUSY; | 427 | return -EBUSY; |
430 | } | 428 | } |
431 | 429 | ||
432 | wdt_base = ioremap(res->start, size); | 430 | wdt_base = ioremap(wdt_mem->start, size); |
433 | if (wdt_base == NULL) { | 431 | if (wdt_base == NULL) { |
434 | dev_err(dev, "failed to ioremap() region\n"); | 432 | dev_err(dev, "failed to ioremap() region\n"); |
435 | ret = -EINVAL; | 433 | ret = -EINVAL; |
@@ -524,8 +522,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
524 | iounmap(wdt_base); | 522 | iounmap(wdt_base); |
525 | 523 | ||
526 | err_req: | 524 | err_req: |
527 | release_resource(wdt_mem); | 525 | release_mem_region(wdt_mem->start, size); |
528 | kfree(wdt_mem); | 526 | wdt_mem = NULL; |
529 | 527 | ||
530 | return ret; | 528 | return ret; |
531 | } | 529 | } |
@@ -545,8 +543,7 @@ static int __devexit s3c2410wdt_remove(struct platform_device *dev) | |||
545 | 543 | ||
546 | iounmap(wdt_base); | 544 | iounmap(wdt_base); |
547 | 545 | ||
548 | release_resource(wdt_mem); | 546 | release_mem_region(wdt_mem->start, resource_size(wdt_mem)); |
549 | kfree(wdt_mem); | ||
550 | wdt_mem = NULL; | 547 | wdt_mem = NULL; |
551 | return 0; | 548 | return 0; |
552 | } | 549 | } |
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index 100b114e3c3c..bf16ffb4d21e 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/jiffies.h> | 49 | #include <linux/jiffies.h> |
50 | #include <linux/uaccess.h> | 50 | #include <linux/uaccess.h> |
51 | #include <linux/kernel.h> | ||
51 | 52 | ||
52 | #define PFX "SoftDog: " | 53 | #define PFX "SoftDog: " |
53 | 54 | ||
@@ -75,6 +76,11 @@ MODULE_PARM_DESC(soft_noboot, | |||
75 | "Softdog action, set to 1 to ignore reboots, 0 to reboot " | 76 | "Softdog action, set to 1 to ignore reboots, 0 to reboot " |
76 | "(default depends on ONLY_TESTING)"); | 77 | "(default depends on ONLY_TESTING)"); |
77 | 78 | ||
79 | static int soft_panic; | ||
80 | module_param(soft_panic, int, 0); | ||
81 | MODULE_PARM_DESC(soft_panic, | ||
82 | "Softdog action, set to 1 to panic, 0 to reboot (default=0)"); | ||
83 | |||
78 | /* | 84 | /* |
79 | * Our timer | 85 | * Our timer |
80 | */ | 86 | */ |
@@ -98,7 +104,10 @@ static void watchdog_fire(unsigned long data) | |||
98 | 104 | ||
99 | if (soft_noboot) | 105 | if (soft_noboot) |
100 | printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); | 106 | printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); |
101 | else { | 107 | else if (soft_panic) { |
108 | printk(KERN_CRIT PFX "Initiating panic.\n"); | ||
109 | panic("Software Watchdog Timer expired."); | ||
110 | } else { | ||
102 | printk(KERN_CRIT PFX "Initiating system reboot.\n"); | 111 | printk(KERN_CRIT PFX "Initiating system reboot.\n"); |
103 | emergency_restart(); | 112 | emergency_restart(); |
104 | printk(KERN_CRIT PFX "Reboot didn't ?????\n"); | 113 | printk(KERN_CRIT PFX "Reboot didn't ?????\n"); |
@@ -267,7 +276,8 @@ static struct notifier_block softdog_notifier = { | |||
267 | }; | 276 | }; |
268 | 277 | ||
269 | static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 " | 278 | static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 " |
270 | "initialized. soft_noboot=%d soft_margin=%d sec (nowayout= %d)\n"; | 279 | "initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d " |
280 | "(nowayout= %d)\n"; | ||
271 | 281 | ||
272 | static int __init watchdog_init(void) | 282 | static int __init watchdog_init(void) |
273 | { | 283 | { |
@@ -298,7 +308,7 @@ static int __init watchdog_init(void) | |||
298 | return ret; | 308 | return ret; |
299 | } | 309 | } |
300 | 310 | ||
301 | printk(banner, soft_noboot, soft_margin, nowayout); | 311 | printk(banner, soft_noboot, soft_margin, soft_panic, nowayout); |
302 | 312 | ||
303 | return 0; | 313 | return 0; |
304 | } | 314 | } |
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index 1bc493848ed4..87e0527669d8 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #define PFX TCO_MODULE_NAME ": " | 42 | #define PFX TCO_MODULE_NAME ": " |
43 | 43 | ||
44 | /* internal variables */ | 44 | /* internal variables */ |
45 | static u32 tcobase_phys; | ||
45 | static void __iomem *tcobase; | 46 | static void __iomem *tcobase; |
46 | static unsigned int pm_iobase; | 47 | static unsigned int pm_iobase; |
47 | static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ | 48 | static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ |
@@ -305,10 +306,18 @@ static unsigned char __devinit sp5100_tco_setupdevice(void) | |||
305 | /* Low three bits of BASE0 are reserved. */ | 306 | /* Low three bits of BASE0 are reserved. */ |
306 | val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); | 307 | val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); |
307 | 308 | ||
309 | if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, | ||
310 | "SP5100 TCO")) { | ||
311 | printk(KERN_ERR PFX "mmio address 0x%04x already in use\n", | ||
312 | val); | ||
313 | goto unreg_region; | ||
314 | } | ||
315 | tcobase_phys = val; | ||
316 | |||
308 | tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); | 317 | tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); |
309 | if (tcobase == 0) { | 318 | if (tcobase == 0) { |
310 | printk(KERN_ERR PFX "failed to get tcobase address\n"); | 319 | printk(KERN_ERR PFX "failed to get tcobase address\n"); |
311 | goto unreg_region; | 320 | goto unreg_mem_region; |
312 | } | 321 | } |
313 | 322 | ||
314 | /* Enable watchdog decode bit */ | 323 | /* Enable watchdog decode bit */ |
@@ -346,7 +355,8 @@ static unsigned char __devinit sp5100_tco_setupdevice(void) | |||
346 | /* Done */ | 355 | /* Done */ |
347 | return 1; | 356 | return 1; |
348 | 357 | ||
349 | iounmap(tcobase); | 358 | unreg_mem_region: |
359 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | ||
350 | unreg_region: | 360 | unreg_region: |
351 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | 361 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); |
352 | exit: | 362 | exit: |
@@ -401,6 +411,7 @@ static int __devinit sp5100_tco_init(struct platform_device *dev) | |||
401 | 411 | ||
402 | exit: | 412 | exit: |
403 | iounmap(tcobase); | 413 | iounmap(tcobase); |
414 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | ||
404 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | 415 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); |
405 | return ret; | 416 | return ret; |
406 | } | 417 | } |
@@ -414,6 +425,7 @@ static void __devexit sp5100_tco_cleanup(void) | |||
414 | /* Deregister */ | 425 | /* Deregister */ |
415 | misc_deregister(&sp5100_tco_miscdev); | 426 | misc_deregister(&sp5100_tco_miscdev); |
416 | iounmap(tcobase); | 427 | iounmap(tcobase); |
428 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | ||
417 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | 429 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); |
418 | } | 430 | } |
419 | 431 | ||
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 02b5a9c05cfa..036343ba204e 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -122,7 +122,7 @@ static struct irq_chip xen_pirq_chip; | |||
122 | /* Get info for IRQ */ | 122 | /* Get info for IRQ */ |
123 | static struct irq_info *info_for_irq(unsigned irq) | 123 | static struct irq_info *info_for_irq(unsigned irq) |
124 | { | 124 | { |
125 | return get_irq_data(irq); | 125 | return irq_get_handler_data(irq); |
126 | } | 126 | } |
127 | 127 | ||
128 | /* Constructors for packed IRQ information. */ | 128 | /* Constructors for packed IRQ information. */ |
@@ -403,7 +403,7 @@ static void xen_irq_init(unsigned irq) | |||
403 | 403 | ||
404 | info->type = IRQT_UNBOUND; | 404 | info->type = IRQT_UNBOUND; |
405 | 405 | ||
406 | set_irq_data(irq, info); | 406 | irq_set_handler_data(irq, info); |
407 | 407 | ||
408 | list_add_tail(&info->list, &xen_irq_list_head); | 408 | list_add_tail(&info->list, &xen_irq_list_head); |
409 | } | 409 | } |
@@ -458,11 +458,11 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi) | |||
458 | 458 | ||
459 | static void xen_free_irq(unsigned irq) | 459 | static void xen_free_irq(unsigned irq) |
460 | { | 460 | { |
461 | struct irq_info *info = get_irq_data(irq); | 461 | struct irq_info *info = irq_get_handler_data(irq); |
462 | 462 | ||
463 | list_del(&info->list); | 463 | list_del(&info->list); |
464 | 464 | ||
465 | set_irq_data(irq, NULL); | 465 | irq_set_handler_data(irq, NULL); |
466 | 466 | ||
467 | kfree(info); | 467 | kfree(info); |
468 | 468 | ||
@@ -585,7 +585,7 @@ static void ack_pirq(struct irq_data *data) | |||
585 | { | 585 | { |
586 | int evtchn = evtchn_from_irq(data->irq); | 586 | int evtchn = evtchn_from_irq(data->irq); |
587 | 587 | ||
588 | move_native_irq(data->irq); | 588 | irq_move_irq(data); |
589 | 589 | ||
590 | if (VALID_EVTCHN(evtchn)) { | 590 | if (VALID_EVTCHN(evtchn)) { |
591 | mask_evtchn(evtchn); | 591 | mask_evtchn(evtchn); |
@@ -639,8 +639,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, | |||
639 | if (irq < 0) | 639 | if (irq < 0) |
640 | goto out; | 640 | goto out; |
641 | 641 | ||
642 | set_irq_chip_and_handler_name(irq, &xen_pirq_chip, | 642 | irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, |
643 | handle_level_irq, name); | 643 | name); |
644 | 644 | ||
645 | irq_op.irq = irq; | 645 | irq_op.irq = irq; |
646 | irq_op.vector = 0; | 646 | irq_op.vector = 0; |
@@ -690,8 +690,8 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, | |||
690 | if (irq == -1) | 690 | if (irq == -1) |
691 | goto out; | 691 | goto out; |
692 | 692 | ||
693 | set_irq_chip_and_handler_name(irq, &xen_pirq_chip, | 693 | irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, |
694 | handle_level_irq, name); | 694 | name); |
695 | 695 | ||
696 | xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); | 696 | xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); |
697 | ret = irq_set_msi_desc(irq, msidesc); | 697 | ret = irq_set_msi_desc(irq, msidesc); |
@@ -772,7 +772,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) | |||
772 | if (irq == -1) | 772 | if (irq == -1) |
773 | goto out; | 773 | goto out; |
774 | 774 | ||
775 | set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, | 775 | irq_set_chip_and_handler_name(irq, &xen_dynamic_chip, |
776 | handle_fasteoi_irq, "event"); | 776 | handle_fasteoi_irq, "event"); |
777 | 777 | ||
778 | xen_irq_info_evtchn_init(irq, evtchn); | 778 | xen_irq_info_evtchn_init(irq, evtchn); |
@@ -799,7 +799,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) | |||
799 | if (irq < 0) | 799 | if (irq < 0) |
800 | goto out; | 800 | goto out; |
801 | 801 | ||
802 | set_irq_chip_and_handler_name(irq, &xen_percpu_chip, | 802 | irq_set_chip_and_handler_name(irq, &xen_percpu_chip, |
803 | handle_percpu_irq, "ipi"); | 803 | handle_percpu_irq, "ipi"); |
804 | 804 | ||
805 | bind_ipi.vcpu = cpu; | 805 | bind_ipi.vcpu = cpu; |
@@ -848,7 +848,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) | |||
848 | if (irq == -1) | 848 | if (irq == -1) |
849 | goto out; | 849 | goto out; |
850 | 850 | ||
851 | set_irq_chip_and_handler_name(irq, &xen_percpu_chip, | 851 | irq_set_chip_and_handler_name(irq, &xen_percpu_chip, |
852 | handle_percpu_irq, "virq"); | 852 | handle_percpu_irq, "virq"); |
853 | 853 | ||
854 | bind_virq.virq = virq; | 854 | bind_virq.virq = virq; |
@@ -1339,7 +1339,7 @@ static void ack_dynirq(struct irq_data *data) | |||
1339 | { | 1339 | { |
1340 | int evtchn = evtchn_from_irq(data->irq); | 1340 | int evtchn = evtchn_from_irq(data->irq); |
1341 | 1341 | ||
1342 | move_masked_irq(data->irq); | 1342 | irq_move_masked_irq(data); |
1343 | 1343 | ||
1344 | if (VALID_EVTCHN(evtchn)) | 1344 | if (VALID_EVTCHN(evtchn)) |
1345 | unmask_evtchn(evtchn); | 1345 | unmask_evtchn(evtchn); |
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 017ce600fbc6..b0f9e8fb0052 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c | |||
@@ -273,7 +273,7 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) | |||
273 | map->vma->vm_start + map->notify.addr; | 273 | map->vma->vm_start + map->notify.addr; |
274 | err = copy_to_user(tmp, &err, 1); | 274 | err = copy_to_user(tmp, &err, 1); |
275 | if (err) | 275 | if (err) |
276 | return err; | 276 | return -EFAULT; |
277 | map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; | 277 | map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; |
278 | } else if (pgno >= offset && pgno < offset + pages) { | 278 | } else if (pgno >= offset && pgno < offset + pages) { |
279 | uint8_t *tmp = kmap(map->pages[pgno]); | 279 | uint8_t *tmp = kmap(map->pages[pgno]); |
@@ -662,7 +662,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) | |||
662 | if (map->flags) { | 662 | if (map->flags) { |
663 | if ((vma->vm_flags & VM_WRITE) && | 663 | if ((vma->vm_flags & VM_WRITE) && |
664 | (map->flags & GNTMAP_readonly)) | 664 | (map->flags & GNTMAP_readonly)) |
665 | return -EINVAL; | 665 | goto out_unlock_put; |
666 | } else { | 666 | } else { |
667 | map->flags = GNTMAP_host_map; | 667 | map->flags = GNTMAP_host_map; |
668 | if (!(vma->vm_flags & VM_WRITE)) | 668 | if (!(vma->vm_flags & VM_WRITE)) |
@@ -700,6 +700,8 @@ unlock_out: | |||
700 | spin_unlock(&priv->lock); | 700 | spin_unlock(&priv->lock); |
701 | return err; | 701 | return err; |
702 | 702 | ||
703 | out_unlock_put: | ||
704 | spin_unlock(&priv->lock); | ||
703 | out_put_map: | 705 | out_put_map: |
704 | if (use_ptemod) | 706 | if (use_ptemod) |
705 | map->vma = NULL; | 707 | map->vma = NULL; |