at v5.2 151 lines 3.4 kB view raw
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 16static 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 28static 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 42static const unsigned short sgi_map[] = { 43 KEY_VOLUMEDOWN, 44 KEY_VOLUMEUP 45}; 46 47struct 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 53static 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 80static 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 131static 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 142static struct platform_driver sgi_buttons_driver = { 143 .probe = sgi_buttons_probe, 144 .remove = sgi_buttons_remove, 145 .driver = { 146 .name = "sgibtns", 147 }, 148}; 149module_platform_driver(sgi_buttons_driver); 150 151MODULE_LICENSE("GPL");