1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * SGI Volume Button interface driver 4 * 5 * Copyright (C) 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de> 6 */ 7 #include <linux/input-polldev.h> 8 #include <linux/ioport.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/slab.h> 12 13 #ifdef CONFIG_SGI_IP22 14 #include <asm/sgi/ioc.h> 15 16 static inline u8 button_status(void) 17 { 18 u8 status; 19 20 status = readb(&sgioc->panel) ^ 0xa0; 21 return ((status & 0x80) >> 6) | ((status & 0x20) >> 5); 22 } 23 #endif 24 25 #ifdef CONFIG_SGI_IP32 26 #include <asm/ip32/mace.h> 27 28 static inline u8 button_status(void) 29 { 30 u64 status; 31 32 status = readq(&mace->perif.audio.control); 33 writeq(status & ~(3U << 23), &mace->perif.audio.control); 34 35 return (status >> 23) & 3; 36 } 37 #endif 38 39 #define BUTTONS_POLL_INTERVAL 30 /* msec */ 40 #define BUTTONS_COUNT_THRESHOLD 3 41 42 static const unsigned short sgi_map[] = { 43 KEY_VOLUMEDOWN, 44 KEY_VOLUMEUP 45 }; 46 47 struct buttons_dev { 48 struct input_polled_dev *poll_dev; 49 unsigned short keymap[ARRAY_SIZE(sgi_map)]; 50 int count[ARRAY_SIZE(sgi_map)]; 51 }; 52 53 static void handle_buttons(struct input_polled_dev *dev) 54 { 55 struct buttons_dev *bdev = dev->private; 56 struct input_dev *input = dev->input; 57 u8 status; 58 int i; 59 60 status = button_status(); 61 62 for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) { 63 if (status & (1U << i)) { 64 if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) { 65 input_event(input, EV_MSC, MSC_SCAN, i); 66 input_report_key(input, bdev->keymap[i], 1); 67 input_sync(input); 68 } 69 } else { 70 if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) { 71 input_event(input, EV_MSC, MSC_SCAN, i); 72 input_report_key(input, bdev->keymap[i], 0); 73 input_sync(input); 74 } 75 bdev->count[i] = 0; 76 } 77 } 78 } 79 80 static int sgi_buttons_probe(struct platform_device *pdev) 81 { 82 struct buttons_dev *bdev; 83 struct input_polled_dev *poll_dev; 84 struct input_dev *input; 85 int error, i; 86 87 bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL); 88 poll_dev = input_allocate_polled_device(); 89 if (!bdev || !poll_dev) { 90 error = -ENOMEM; 91 goto err_free_mem; 92 } 93 94 memcpy(bdev->keymap, sgi_map, sizeof(bdev->keymap)); 95 96 poll_dev->private = bdev; 97 poll_dev->poll = handle_buttons; 98 poll_dev->poll_interval = BUTTONS_POLL_INTERVAL; 99 100 input = poll_dev->input; 101 input->name = "SGI buttons"; 102 input->phys = "sgi/input0"; 103 input->id.bustype = BUS_HOST; 104 input->dev.parent = &pdev->dev; 105 106 input->keycode = bdev->keymap; 107 input->keycodemax = ARRAY_SIZE(bdev->keymap); 108 input->keycodesize = sizeof(unsigned short); 109 110 input_set_capability(input, EV_MSC, MSC_SCAN); 111 __set_bit(EV_KEY, input->evbit); 112 for (i = 0; i < ARRAY_SIZE(sgi_map); i++) 113 __set_bit(bdev->keymap[i], input->keybit); 114 __clear_bit(KEY_RESERVED, input->keybit); 115 116 bdev->poll_dev = poll_dev; 117 platform_set_drvdata(pdev, bdev); 118 119 error = input_register_polled_device(poll_dev); 120 if (error) 121 goto err_free_mem; 122 123 return 0; 124 125 err_free_mem: 126 input_free_polled_device(poll_dev); 127 kfree(bdev); 128 return error; 129 } 130 131 static int sgi_buttons_remove(struct platform_device *pdev) 132 { 133 struct buttons_dev *bdev = platform_get_drvdata(pdev); 134 135 input_unregister_polled_device(bdev->poll_dev); 136 input_free_polled_device(bdev->poll_dev); 137 kfree(bdev); 138 139 return 0; 140 } 141 142 static struct platform_driver sgi_buttons_driver = { 143 .probe = sgi_buttons_probe, 144 .remove = sgi_buttons_remove, 145 .driver = { 146 .name = "sgibtns", 147 }, 148 }; 149 module_platform_driver(sgi_buttons_driver); 150 151 MODULE_LICENSE("GPL"); 152