16f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland/* 26f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * Copyright (C) 2007 Google, Inc. 36f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * Copyright (C) 2012 Intel, Inc. 46f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * 56f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * This software is licensed under the terms of the GNU General Public 66f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * License version 2, as published by the Free Software Foundation, and 76f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * may be copied, distributed, and modified under those terms. 86f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * 96f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * This program is distributed in the hope that it will be useful, 106f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * but WITHOUT ANY WARRANTY; without even the implied warranty of 116f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 126f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * GNU General Public License for more details. 136f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland * 146f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland */ 156f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 166f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/module.h> 176f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/interrupt.h> 186f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/types.h> 196f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/input.h> 206f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/kernel.h> 216f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/platform_device.h> 226f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/slab.h> 236f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/irq.h> 246f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland#include <linux/io.h> 256f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 266f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandenum { 276f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland REG_READ = 0x00, 286f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland REG_SET_PAGE = 0x00, 296f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland REG_LEN = 0x04, 306f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland REG_DATA = 0x08, 316f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 326f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland PAGE_NAME = 0x00000, 336f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland PAGE_EVBITS = 0x10000, 346f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland PAGE_ABSDATA = 0x20000 | EV_ABS, 356f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland}; 366f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 376f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandstruct event_dev { 386f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland struct input_dev *input; 396f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int irq; 406f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland void __iomem *addr; 416f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland char name[0]; 426f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland}; 436f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 446f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandstatic irqreturn_t events_interrupt(int irq, void *dev_id) 456f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland{ 466f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland struct event_dev *edev = dev_id; 476f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland unsigned type, code, value; 486f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 496f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland type = __raw_readl(edev->addr + REG_READ); 506f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland code = __raw_readl(edev->addr + REG_READ); 516f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland value = __raw_readl(edev->addr + REG_READ); 526f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 536f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland input_event(edev->input, type, code, value); 546f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland input_sync(edev->input); 556f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return IRQ_HANDLED; 566f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland} 576f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 586f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandstatic void events_import_bits(struct event_dev *edev, 596f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland unsigned long bits[], unsigned type, size_t count) 606f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland{ 616f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland void __iomem *addr = edev->addr; 626f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int i, j; 636f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland size_t size; 646f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland uint8_t val; 656f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 666f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland __raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE); 676f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 686f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland size = __raw_readl(addr + REG_LEN) * 8; 696f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (size < count) 706f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland count = size; 716f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 726f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland addr += REG_DATA; 736f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland for (i = 0; i < count; i += 8) { 746f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland val = __raw_readb(addr++); 756f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland for (j = 0; j < 8; j++) 766f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (val & 1 << j) 776f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland set_bit(i + j, bits); 786f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland } 796f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland} 806f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 816f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandstatic void events_import_abs_params(struct event_dev *edev) 826f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland{ 836f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland struct input_dev *input_dev = edev->input; 846f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland void __iomem *addr = edev->addr; 856f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland u32 val[4]; 866f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int count; 876f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int i, j; 886f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 896f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland __raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE); 906f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 916f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland count = __raw_readl(addr + REG_LEN) / sizeof(val); 926f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (count > ABS_MAX) 936f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland count = ABS_MAX; 946f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 956f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland for (i = 0; i < count; i++) { 966f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (!test_bit(i, input_dev->absbit)) 976f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland continue; 986f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 996f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland for (j = 0; j < ARRAY_SIZE(val); j++) { 1006f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int offset = (i * ARRAY_SIZE(val) + j) * sizeof(u32); 1016f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland val[j] = __raw_readl(edev->addr + REG_DATA + offset); 1026f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland } 1036f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1046f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland input_set_abs_params(input_dev, i, 1056f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland val[0], val[1], val[2], val[3]); 1066f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland } 1076f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland} 1086f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1096f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandstatic int events_probe(struct platform_device *pdev) 1106f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland{ 1116f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland struct input_dev *input_dev; 1126f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland struct event_dev *edev; 1136f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland struct resource *res; 1146f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland unsigned keymapnamelen; 1156f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland void __iomem *addr; 1166f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int irq; 1176f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int i; 1186f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland int error; 1196f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1206f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland irq = platform_get_irq(pdev, 0); 1216f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (irq < 0) 1226f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return -EINVAL; 1236f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1246f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1256f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (!res) 1266f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return -EINVAL; 1276f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1286f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland addr = devm_ioremap(&pdev->dev, res->start, 4096); 1296f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (!addr) 1306f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return -ENOMEM; 1316f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1326f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland __raw_writel(PAGE_NAME, addr + REG_SET_PAGE); 1336f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland keymapnamelen = __raw_readl(addr + REG_LEN); 1346f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1356f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland edev = devm_kzalloc(&pdev->dev, 1366f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland sizeof(struct event_dev) + keymapnamelen + 1, 1376f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland GFP_KERNEL); 1386f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (!edev) 1396f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return -ENOMEM; 1406f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1416f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland input_dev = devm_input_allocate_device(&pdev->dev); 1426f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (!input_dev) 1436f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return -ENOMEM; 1446f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1456f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland edev->input = input_dev; 1466f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland edev->addr = addr; 1476f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland edev->irq = irq; 1486f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1496f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland for (i = 0; i < keymapnamelen; i++) 1506f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland edev->name[i] = __raw_readb(edev->addr + REG_DATA + i); 1516f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1526f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland pr_debug("events_probe() keymap=%s\n", edev->name); 1536f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1546f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland input_dev->name = edev->name; 1556f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland input_dev->id.bustype = BUS_HOST; 1566f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1576f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX); 1586f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX); 1596f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX); 1606f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX); 1616f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX); 1626f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX); 1636f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX); 1646f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX); 1656f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX); 1666f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1676f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland events_import_abs_params(edev); 1686f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1696f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland error = devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0, 1706f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland "goldfish-events-keypad", edev); 1716f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (error) 1726f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return error; 1736f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1746f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland error = input_register_device(input_dev); 1756f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland if (error) 1766f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return error; 1776f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1786f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland return 0; 1796f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland} 1806f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1816f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandstatic struct platform_driver events_driver = { 1826f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland .probe = events_probe, 1836f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland .driver = { 1846f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland .owner = THIS_MODULE, 1856f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland .name = "goldfish_events", 1866f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland }, 1876f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland}; 1886f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1896f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetlandmodule_platform_driver(events_driver); 1906f2ac009f29bcbd468a7a2017912dd090abd1348Brian Swetland 1916f2ac009f29bcbd468a7a2017912dd090abd1348Brian SwetlandMODULE_AUTHOR("Brian Swetland"); 1926f2ac009f29bcbd468a7a2017912dd090abd1348Brian SwetlandMODULE_DESCRIPTION("Goldfish Event Device"); 1936f2ac009f29bcbd468a7a2017912dd090abd1348Brian SwetlandMODULE_LICENSE("GPL"); 194