From 334955ef964bee9d3b1e20966847eee28cfd05f6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 1 Jun 2011 19:04:57 +0100 Subject: i8253: Create linux/i8253.h and use it in all 8253 related files Signed-off-by: Ralf Baechle Cc: linux-mips@linux-mips.org Link: http://lkml.kernel.org/r/20110601180610.054254048@duck.linux-mips.net Signed-off-by: Thomas Gleixner arch/arm/mach-footbridge/isa-timer.c | 2 +- arch/mips/cobalt/time.c | 2 +- arch/mips/jazz/irq.c | 2 +- arch/mips/kernel/i8253.c | 2 +- arch/mips/mti-malta/malta-time.c | 2 +- arch/mips/sgi-ip22/ip22-time.c | 2 +- arch/mips/sni/time.c | 2 +- arch/x86/kernel/apic/apic.c | 2 +- arch/x86/kernel/apm_32.c | 2 +- arch/x86/kernel/hpet.c | 2 +- arch/x86/kernel/i8253.c | 2 +- arch/x86/kernel/time.c | 2 +- drivers/block/hd.c | 2 +- drivers/clocksource/i8253.c | 2 +- drivers/input/gameport/gameport.c | 2 +- drivers/input/joystick/analog.c | 2 +- drivers/input/misc/pcspkr.c | 2 +- include/linux/i8253.h | 11 +++++++++++ sound/drivers/pcsp/pcsp.h | 2 +- 19 files changed, 29 insertions(+), 18 deletions(-) --- drivers/input/gameport/gameport.c | 2 +- drivers/input/joystick/analog.c | 2 +- drivers/input/misc/pcspkr.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 5b8f59d6c3e..c351aa421f8 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -47,7 +47,7 @@ static void gameport_disconnect_port(struct gameport *gameport); #if defined(__i386__) -#include +#include #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0)) #define GET_TIME(x) do { x = get_time_pit(); } while (0) diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 4afe0a3b488..9882971827e 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -136,7 +136,7 @@ struct analog_port { #ifdef __i386__ -#include +#include #define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0) #define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0))) diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index f080dd31499..2aa9d902017 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -27,7 +27,7 @@ MODULE_ALIAS("platform:pcspkr"); #if defined(CONFIG_MIPS) || defined(CONFIG_X86) /* Use the global PIT lock ! */ -#include +#include #else #include static DEFINE_RAW_SPINLOCK(i8253_lock); -- cgit v1.2.3-70-g09d2 From 16ba9b061223c8a58b9b2e0dd01435111c4e902a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 1 Jun 2011 19:05:02 +0100 Subject: i8253: Make pcspkr input driver use the shared i8253_lock Signed-off-by: Ralf Baechle Cc: Dmitry Torokhov Cc: linux-input@vger.kernel.org Link: http://lkml.kernel.org/r/20110601180610.453577265@duck.linux-mips.net Signed-off-by: Thomas Gleixner --- drivers/input/misc/pcspkr.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 2aa9d902017..34f4d2e0f50 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -25,14 +26,6 @@ MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pcspkr"); -#if defined(CONFIG_MIPS) || defined(CONFIG_X86) -/* Use the global PIT lock ! */ -#include -#else -#include -static DEFINE_RAW_SPINLOCK(i8253_lock); -#endif - static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { unsigned int count = 0; -- cgit v1.2.3-70-g09d2 From 28f65c11f2ffb3957259dece647a24f8ad2e241b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 9 Jun 2011 09:13:32 -0700 Subject: treewide: Convert uses of struct resource to resource_size(ptr) Several fixes as well where the +1 was missing. Done via coccinelle scripts like: @@ struct resource *ptr; @@ - ptr->end - ptr->start + 1 + resource_size(ptr) and some grep and typing. Mostly uncompiled, no cross-compilers. Signed-off-by: Joe Perches Signed-off-by: Jiri Kosina --- arch/arm/common/scoop.c | 2 +- arch/arm/mach-at91/at91sam9261_devices.c | 2 +- arch/arm/mach-mv78xx0/pcie.c | 8 ++++---- arch/arm/mach-u300/core.c | 2 +- arch/arm/plat-mxc/pwm.c | 8 ++++---- arch/arm/plat-s5p/sysmmu.c | 6 +++--- arch/arm/plat-samsung/pm-check.c | 2 +- arch/avr32/kernel/setup.c | 10 +++++----- arch/avr32/mach-at32ap/extint.c | 2 +- arch/avr32/mach-at32ap/hsmc.c | 2 +- arch/avr32/mach-at32ap/intc.c | 2 +- arch/avr32/mach-at32ap/pio.c | 2 +- arch/microblaze/pci/pci-common.c | 2 +- arch/mips/pci/pci-rc32434.c | 2 +- arch/mips/pci/pci-vr41xx.c | 2 +- arch/mips/powertv/asic/asic_devices.c | 10 ++++------ arch/powerpc/include/asm/macio.h | 2 +- arch/powerpc/kernel/machine_kexec.c | 4 ++-- arch/powerpc/kernel/pci-common.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 8 ++++---- arch/powerpc/platforms/83xx/km83xx.c | 2 +- arch/powerpc/platforms/83xx/mpc832x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc834x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc836x_mds.c | 2 +- arch/powerpc/platforms/83xx/usb.c | 2 +- arch/powerpc/platforms/85xx/sbc8560.c | 2 +- arch/powerpc/platforms/85xx/xes_mpc85xx.c | 2 +- arch/powerpc/platforms/cell/celleb_scc_epci.c | 8 ++++---- arch/powerpc/platforms/cell/celleb_scc_pciex.c | 2 +- arch/powerpc/platforms/cell/spu_manage.c | 2 +- arch/powerpc/platforms/chrp/pci.c | 2 +- arch/powerpc/platforms/pasemi/dma_lib.c | 2 +- arch/powerpc/platforms/powermac/nvram.c | 4 ++-- arch/powerpc/platforms/powermac/pci.c | 6 ++---- arch/powerpc/platforms/powermac/time.c | 2 +- arch/powerpc/sysdev/axonram.c | 2 +- arch/powerpc/sysdev/cpm1.c | 2 +- arch/powerpc/sysdev/cpm_common.c | 2 +- arch/powerpc/sysdev/dart_iommu.c | 2 +- arch/powerpc/sysdev/fsl_msi.c | 2 +- arch/powerpc/sysdev/fsl_pci.c | 12 ++++++------ arch/powerpc/sysdev/fsl_rio.c | 2 +- arch/powerpc/sysdev/ipic.c | 2 +- arch/powerpc/sysdev/mmio_nvram.c | 2 +- arch/powerpc/sysdev/mpc8xx_pic.c | 2 +- arch/powerpc/sysdev/mv64x60_udbg.c | 4 ++-- arch/powerpc/sysdev/ppc4xx_pci.c | 16 ++++++++-------- arch/powerpc/sysdev/qe_lib/qe_ic.c | 2 +- arch/powerpc/sysdev/qe_lib/qe_io.c | 2 +- arch/powerpc/sysdev/xics/icp-native.c | 2 +- arch/sh/kernel/io_trapped.c | 8 ++++---- arch/sh/kernel/machine_kexec.c | 2 +- arch/sparc/kernel/ioport.c | 12 ++++++------ arch/sparc/kernel/pci.c | 6 ++---- arch/tile/kernel/setup.c | 3 +-- arch/x86/kernel/pci-calgary_64.c | 2 +- arch/x86/kernel/probe_roms.c | 2 +- drivers/char/bsr.c | 2 +- drivers/char/xilinx_hwicap/xilinx_hwicap.c | 2 +- drivers/dma/mv_xor.c | 5 ++--- drivers/edac/cell_edac.c | 2 +- drivers/edac/mpc85xx_edac.c | 12 ++++++------ drivers/gpio/gpio-u300.c | 8 ++++---- drivers/ide/palm_bk3710.c | 2 +- drivers/ide/tx4939ide.c | 4 ++-- drivers/input/serio/sa1111ps2.c | 6 ++---- drivers/media/video/davinci/vpif.c | 2 +- drivers/media/video/omap24xxcam.c | 5 ++--- drivers/message/i2o/iop.c | 8 ++++---- drivers/mfd/tc6387xb.c | 2 +- drivers/misc/atmel-ssc.c | 2 +- drivers/misc/atmel_pwm.c | 2 +- drivers/mmc/host/dw_mmc.c | 2 +- drivers/mtd/maps/bfin-async-flash.c | 2 +- drivers/mtd/maps/ixp2000.c | 11 ++++++----- drivers/mtd/maps/pxa2xx-flash.c | 2 +- drivers/mtd/nand/atmel_nand.c | 4 ++-- drivers/mtd/nand/bcm_umi_nand.c | 2 +- drivers/mtd/nand/mpc5121_nfc.c | 2 +- drivers/net/bcm63xx_enet.c | 8 ++++---- drivers/net/can/softing/softing_main.c | 2 +- drivers/net/davinci_emac.c | 6 +++--- drivers/net/ethoc.c | 2 +- drivers/net/fec_mpc52xx.c | 7 ++++--- drivers/net/fs_enet/mii-bitbang.c | 4 ++-- drivers/net/fs_enet/mii-fec.c | 2 +- drivers/net/gianfar_ptp.c | 2 +- drivers/net/ibm_newemac/core.c | 2 +- drivers/net/macb.c | 2 +- drivers/net/mv643xx_eth.c | 2 +- drivers/net/pxa168_eth.c | 2 +- drivers/net/sb1250-mac.c | 2 +- drivers/parport/parport_ax88796.c | 2 +- drivers/pci/hotplug/shpchp_sysfs.c | 21 +++++++++------------ drivers/pcmcia/at91_cf.c | 7 +++---- drivers/pcmcia/electra_cf.c | 4 ++-- drivers/pcmcia/rsrc_iodyn.c | 6 +++--- drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- drivers/pnp/pnpacpi/rsparser.c | 10 +++++----- drivers/pnp/pnpbios/rsparser.c | 12 ++++++------ drivers/rtc/rtc-at32ap700x.c | 2 +- drivers/rtc/rtc-cmos.c | 6 +++--- drivers/rtc/rtc-ds1286.c | 2 +- drivers/rtc/rtc-ds1511.c | 2 +- drivers/rtc/rtc-ds1742.c | 2 +- drivers/rtc/rtc-m48t35.c | 2 +- drivers/rtc/rtc-m48t59.c | 2 +- drivers/rtc/rtc-mrst.c | 5 ++--- drivers/rtc/rtc-puv3.c | 5 ++--- drivers/rtc/rtc-s3c.c | 5 ++--- drivers/staging/generic_serial/ser_a2232.c | 3 ++- drivers/staging/gma500/psb_gtt.c | 8 ++++---- drivers/tty/serial/bfin_5xx.c | 5 ++--- drivers/tty/serial/imx.c | 5 ++--- drivers/tty/serial/m32r_sio.c | 2 +- drivers/tty/serial/omap-serial.c | 6 +++--- drivers/tty/serial/pxa.c | 2 +- drivers/tty/serial/sunsu.c | 2 +- drivers/tty/serial/vt8500_serial.c | 3 +-- drivers/uio/uio_pdrv.c | 2 +- drivers/uio/uio_pdrv_genirq.c | 2 +- drivers/usb/gadget/atmel_usba_udc.c | 2 +- drivers/usb/gadget/fsl_udc_core.c | 6 +++--- drivers/usb/host/ehci-ath79.c | 2 +- drivers/usb/host/ehci-cns3xxx.c | 2 +- drivers/usb/host/ehci-fsl.c | 2 +- drivers/usb/host/ehci-grlib.c | 2 +- drivers/usb/host/ehci-ixp4xx.c | 2 +- drivers/usb/host/ehci-octeon.c | 2 +- drivers/usb/host/ehci-pmcmsp.c | 10 +++++----- drivers/usb/host/ehci-ppc-of.c | 2 +- drivers/usb/host/ehci-w90x900.c | 2 +- drivers/usb/host/ehci-xilinx-of.c | 2 +- drivers/usb/host/fhci-hcd.c | 2 +- drivers/usb/host/ohci-ath79.c | 4 ++-- drivers/usb/host/ohci-cns3xxx.c | 2 +- drivers/usb/host/ohci-da8xx.c | 2 +- drivers/usb/host/ohci-octeon.c | 2 +- drivers/usb/host/ohci-ppc-of.c | 2 +- drivers/usb/host/ohci-ppc-soc.c | 2 +- drivers/usb/host/ohci-sa1111.c | 2 +- drivers/usb/host/ohci-sm501.c | 11 +++++------ drivers/usb/host/ohci-tmio.c | 6 +++--- drivers/usb/host/oxu210hp-hcd.c | 2 +- drivers/usb/host/uhci-grlib.c | 2 +- drivers/usb/host/whci/init.c | 2 +- drivers/uwb/whc-rc.c | 2 +- drivers/video/atmel_lcdfb.c | 4 ++-- drivers/video/aty/atyfb_base.c | 7 ++++--- drivers/video/au1100fb.c | 2 +- drivers/video/cobalt_lcdfb.c | 2 +- drivers/video/controlfb.c | 4 ++-- drivers/video/mb862xx/mb862xxfbdrv.c | 4 ++-- drivers/video/msm/mdp.c | 3 +-- drivers/video/msm/msm_fb.c | 7 +++---- drivers/video/nuc900fb.c | 2 +- drivers/video/platinumfb.c | 5 ++--- drivers/video/pxa168fb.c | 2 +- include/linux/dio.h | 2 +- include/linux/pnp.h | 2 +- include/linux/zorro.h | 2 +- kernel/kexec.c | 2 +- sound/aoa/soundbus/i2sbus/core.c | 9 ++++----- sound/atmel/abdac.c | 2 +- sound/atmel/ac97c.c | 2 +- sound/ppc/pmac.c | 9 +++------ sound/soc/fsl/fsl_ssi.c | 2 +- sound/soc/fsl/mpc5200_dma.c | 2 +- 168 files changed, 308 insertions(+), 333 deletions(-) (limited to 'drivers/input') diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index c11af1e4bad..a07b0e763a8 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -193,7 +193,7 @@ static int __devinit scoop_probe(struct platform_device *pdev) spin_lock_init(&devptr->scoop_lock); inf = pdev->dev.platform_data; - devptr->base = ioremap(mem->start, mem->end - mem->start + 1); + devptr->base = ioremap(mem->start, resource_size(mem)); if (!devptr->base) { ret = -ENOMEM; diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 3eb4538fcee..14dd666850b 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -525,7 +525,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) if (ARRAY_SIZE(lcdc_resources) > 2) { void __iomem *fb; struct resource *fb_res = &lcdc_resources[2]; - size_t fb_len = fb_res->end - fb_res->start + 1; + size_t fb_len = resource_size(fb_res); fb = ioremap(fb_res->start, fb_len); if (fb) { diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c index a560439dcc3..f27c7d2fa9f 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -129,12 +129,12 @@ static void __init mv78xx0_pcie_preinit(void) struct pcie_port *pp = pcie_port + i; mv78xx0_setup_pcie_io_win(win++, pp->res[0].start, - pp->res[0].end - pp->res[0].start + 1, - pp->maj, pp->min); + resource_size(&pp->res[0]), + pp->maj, pp->min); mv78xx0_setup_pcie_mem_win(win++, pp->res[1].start, - pp->res[1].end - pp->res[1].start + 1, - pp->maj, pp->min); + resource_size(&pp->res[1]), + pp->maj, pp->min); } } diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 513d6abec1f..399c89f14df 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -1791,7 +1791,7 @@ static void __init u300_assign_physmem(void) 0 == res->start) { res->start = curr_start; res->end += curr_start; - curr_start += (res->end - res->start + 1); + curr_start += resource_size(res); printk(KERN_INFO "core.c: Mapping RAM " \ "%#x-%#x to device %s:%s\n", diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c index 7a61ef8f471..761c3c940a6 100644 --- a/arch/arm/plat-mxc/pwm.c +++ b/arch/arm/plat-mxc/pwm.c @@ -214,14 +214,14 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev) goto err_free_clk; } - r = request_mem_region(r->start, r->end - r->start + 1, pdev->name); + r = request_mem_region(r->start, resource_size(r), pdev->name); if (r == NULL) { dev_err(&pdev->dev, "failed to request memory resource\n"); ret = -EBUSY; goto err_free_clk; } - pwm->mmio_base = ioremap(r->start, r->end - r->start + 1); + pwm->mmio_base = ioremap(r->start, resource_size(r)); if (pwm->mmio_base == NULL) { dev_err(&pdev->dev, "failed to ioremap() registers\n"); ret = -ENODEV; @@ -236,7 +236,7 @@ static int __devinit mxc_pwm_probe(struct platform_device *pdev) return 0; err_free_mem: - release_mem_region(r->start, r->end - r->start + 1); + release_mem_region(r->start, resource_size(r)); err_free_clk: clk_put(pwm->clk); err_free: @@ -260,7 +260,7 @@ static int __devexit mxc_pwm_remove(struct platform_device *pdev) iounmap(pwm->mmio_base); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, r->end - r->start + 1); + release_mem_region(r->start, resource_size(r)); clk_put(pwm->clk); diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c index 54f5eddc921..e1cbc728c77 100644 --- a/arch/arm/plat-s5p/sysmmu.c +++ b/arch/arm/plat-s5p/sysmmu.c @@ -232,8 +232,8 @@ static int s5p_sysmmu_probe(struct platform_device *pdev) goto err_res; } - mem = request_mem_region(res->start, - ((res->end) - (res->start)) + 1, pdev->name); + mem = request_mem_region(res->start, resource_size(res), + pdev->name); if (!mem) { dev_err(dev, "Failed to request the memory region of %s.\n", sysmmu_ips_name[i]); @@ -241,7 +241,7 @@ static int s5p_sysmmu_probe(struct platform_device *pdev) goto err_res; } - sysmmusfrs[i] = ioremap(res->start, res->end - res->start + 1); + sysmmusfrs[i] = ioremap(res->start, resource_size(res)); if (!sysmmusfrs[i]) { dev_err(dev, "Failed to ioremap() for %s.\n", sysmmu_ips_name[i]); diff --git a/arch/arm/plat-samsung/pm-check.c b/arch/arm/plat-samsung/pm-check.c index 6b733fafe7c..3cbd62666b1 100644 --- a/arch/arm/plat-samsung/pm-check.c +++ b/arch/arm/plat-samsung/pm-check.c @@ -72,7 +72,7 @@ static void s3c_pm_run_sysram(run_fn_t fn, u32 *arg) static u32 *s3c_pm_countram(struct resource *res, u32 *val) { - u32 size = (u32)(res->end - res->start)+1; + u32 size = (u32)resource_size(res); size += CHECK_CHUNKSIZE-1; size /= CHECK_CHUNKSIZE; diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index bb0974cce4a..b4247f47806 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -444,7 +444,7 @@ static unsigned long __init find_bootmap_pfn(const struct resource *mem) { unsigned long bootmap_pages, bootmap_len; - unsigned long node_pages = PFN_UP(mem->end - mem->start + 1); + unsigned long node_pages = PFN_UP(resource_size(mem)); unsigned long bootmap_start; bootmap_pages = bootmem_bootmap_pages(node_pages); @@ -541,10 +541,10 @@ static void __init setup_bootmem(void) */ if (res->start >= PFN_PHYS(first_pfn) && res->end < PFN_PHYS(max_pfn)) - reserve_bootmem_node( - NODE_DATA(node), res->start, - res->end - res->start + 1, - BOOTMEM_DEFAULT); + reserve_bootmem_node(NODE_DATA(node), + res->start, + resource_size(res), + BOOTMEM_DEFAULT); } node_set_online(node); diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index fbc2aeaebdd..cfb298d6630 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c @@ -204,7 +204,7 @@ static int __init eic_probe(struct platform_device *pdev) } eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id; - eic->regs = ioremap(regs->start, regs->end - regs->start + 1); + eic->regs = ioremap(regs->start, resource_size(regs)); if (!eic->regs) { dev_dbg(&pdev->dev, "failed to map regs\n"); goto err_ioremap; diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c index f7672d3e86b..f66245e6e63 100644 --- a/arch/avr32/mach-at32ap/hsmc.c +++ b/arch/avr32/mach-at32ap/hsmc.c @@ -245,7 +245,7 @@ static int hsmc_probe(struct platform_device *pdev) hsmc->pclk = pclk; hsmc->mck = mck; - hsmc->regs = ioremap(regs->start, regs->end - regs->start + 1); + hsmc->regs = ioremap(regs->start, resource_size(regs)); if (!hsmc->regs) goto out_disable_clocks; diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c index 3e3646186c9..6c700431e34 100644 --- a/arch/avr32/mach-at32ap/intc.c +++ b/arch/avr32/mach-at32ap/intc.c @@ -107,7 +107,7 @@ void __init init_IRQ(void) clk_enable(pclk); - intc0.regs = ioremap(regs->start, regs->end - regs->start + 1); + intc0.regs = ioremap(regs->start, resource_size(regs)); if (!intc0.regs) { printk(KERN_EMERG "intc: failed to map registers (0x%08lx)\n", (unsigned long)regs->start); diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index 2e0aa853a4b..9b39dea6682 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -461,7 +461,7 @@ void __init at32_init_pio(struct platform_device *pdev) clk_enable(pio->clk); pio->pdev = pdev; - pio->regs = ioremap(regs->start, regs->end - regs->start + 1); + pio->regs = ioremap(regs->start, resource_size(regs)); /* start with irqs disabled and acked */ pio_writel(pio, IDR, ~0UL); diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 53599067d2f..dd3fae06ece 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -89,7 +89,7 @@ void pcibios_free_controller(struct pci_controller *phb) static resource_size_t pcibios_io_size(const struct pci_controller *hose) { - return hose->io_resource.end - hose->io_resource.start + 1; + return resource_size(&hose->io_resource); } int pcibios_vaddr_is_ioport(void __iomem *address) diff --git a/arch/mips/pci/pci-rc32434.c b/arch/mips/pci/pci-rc32434.c index f31218e17d3..764362ce5e4 100644 --- a/arch/mips/pci/pci-rc32434.c +++ b/arch/mips/pci/pci-rc32434.c @@ -215,7 +215,7 @@ static int __init rc32434_pci_init(void) rc32434_pcibridge_init(); io_map_base = ioremap(rc32434_res_pci_io1.start, - rc32434_res_pci_io1.end - rc32434_res_pci_io1.start + 1); + resource_size(&rcrc32434_res_pci_io1)); if (!io_map_base) return -ENOMEM; diff --git a/arch/mips/pci/pci-vr41xx.c b/arch/mips/pci/pci-vr41xx.c index 56525711f8b..444b8d8004a 100644 --- a/arch/mips/pci/pci-vr41xx.c +++ b/arch/mips/pci/pci-vr41xx.c @@ -305,7 +305,7 @@ static int __init vr41xx_pciu_init(void) struct resource *res = vr41xx_pci_controller.io_resource; master = setup->master_io; io_map_base = ioremap(master->bus_base_address, - res->end - res->start + 1); + resource_size(res)); if (!io_map_base) return -EBUSY; diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index e56fa61b399..bce1872249b 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c @@ -394,23 +394,21 @@ void __init platform_alloc_bootmem(void) /* Loop through looking for resources that want a particular address */ for (i = 0; gp_resources[i].flags != 0; i++) { - int size = gp_resources[i].end - gp_resources[i].start + 1; + int size = resource_size(&gp_resources[i]); if ((gp_resources[i].start != 0) && ((gp_resources[i].flags & IORESOURCE_MEM) != 0)) { reserve_bootmem(dma_to_phys(gp_resources[i].start), size, 0); - total += gp_resources[i].end - - gp_resources[i].start + 1; + total += resource_size(&gp_resources[i]); pr_info("reserve resource %s at %08x (%u bytes)\n", gp_resources[i].name, gp_resources[i].start, - gp_resources[i].end - - gp_resources[i].start + 1); + resource_size(&gp_resources[i])); } } /* Loop through assigning addresses for those that are left */ for (i = 0; gp_resources[i].flags != 0; i++) { - int size = gp_resources[i].end - gp_resources[i].start + 1; + int size = resource_size(&gp_resources[i]); if ((gp_resources[i].start == 0) && ((gp_resources[i].flags & IORESOURCE_MEM) != 0)) { void *mem = alloc_bootmem_pages(size); diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h index 7ab82c825a0..27af7f8bbb8 100644 --- a/arch/powerpc/include/asm/macio.h +++ b/arch/powerpc/include/asm/macio.h @@ -76,7 +76,7 @@ static inline unsigned long macio_resource_len(struct macio_dev *dev, int resour struct resource *res = &dev->resource[resource_no]; if (res->start == 0 || res->end == 0 || res->end < res->start) return 0; - return res->end - res->start + 1; + return resource_size(res); } extern int macio_enable_devres(struct macio_dev *dev); diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index 7ee50f0547c..6658a158995 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -126,7 +126,7 @@ void __init reserve_crashkernel(void) /* We might have got these values via the command line or the * device tree, either way sanitise them now. */ - crash_size = crashk_res.end - crashk_res.start + 1; + crash_size = resource_size(&crashk_res); #ifndef CONFIG_RELOCATABLE if (crashk_res.start != KDUMP_KERNELBASE) @@ -222,7 +222,7 @@ static void __init export_crashk_values(struct device_node *node) if (crashk_res.start != 0) { prom_add_property(node, &crashk_base_prop); - crashk_size = crashk_res.end - crashk_res.start + 1; + crashk_size = resource_size(&crashk_res); prom_add_property(node, &crashk_size_prop); } } diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 893af2a9cd0..3764e37205f 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -107,7 +107,7 @@ static resource_size_t pcibios_io_size(const struct pci_controller *hose) #ifdef CONFIG_PPC64 return hose->pci_io_size; #else - return hose->io_resource.end - hose->io_resource.start + 1; + return resource_size(&hose->io_resource); #endif } diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index da110bd8834..5f5e6930908 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -264,7 +264,7 @@ mpc52xx_pci_setup(struct pci_controller *hose, (unsigned long long)res->flags); out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, - res->end - res->start + 1)); + resource_size(res))); iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; if (res->flags & IORESOURCE_PREFETCH) iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; @@ -278,7 +278,7 @@ mpc52xx_pci_setup(struct pci_controller *hose, res->start, res->end, res->flags); out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, - res->end - res->start + 1)); + resource_size(res))); iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; if (res->flags & IORESOURCE_PREFETCH) iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; @@ -300,7 +300,7 @@ mpc52xx_pci_setup(struct pci_controller *hose, out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, res->start, - res->end - res->start + 1)); + resource_size(res))); iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; /* Set all the IWCR fields at once; they're in the same reg */ @@ -402,7 +402,7 @@ mpc52xx_add_bridge(struct device_node *node) hose->ops = &mpc52xx_pci_ops; - pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); + pci_regs = ioremap(rsrc.start, resource_size(&rsrc)); if (!pci_regs) return -ENOMEM; diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c index a2b9b9ef124..f8fa2fc3129 100644 --- a/arch/powerpc/platforms/83xx/km83xx.c +++ b/arch/powerpc/platforms/83xx/km83xx.c @@ -101,7 +101,7 @@ static void __init mpc83xx_km_setup_arch(void) __func__); return; } - base = ioremap(res.start, res.end - res.start + 1); + base = ioremap(res.start, resource_size(&res)); /* * IMMR + 0x14A8[4:5] = 11 (clk delay for UCC 2) diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index ec0b401bc9c..93e60f1f21a 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -68,7 +68,7 @@ static void __init mpc832x_sys_setup_arch(void) struct resource res; of_address_to_resource(np, 0, &res); - bcsr_regs = ioremap(res.start, res.end - res.start +1); + bcsr_regs = ioremap(res.start, resource_size(&res)); of_node_put(np); } diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index d0a634b056c..c1b1dc50b32 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -53,7 +53,7 @@ static int mpc834xemds_usb_cfg(void) struct resource res; of_address_to_resource(np, 0, &res); - bcsr_regs = ioremap(res.start, res.end - res.start + 1); + bcsr_regs = ioremap(res.start, resource_size(&res)); of_node_put(np); } if (!bcsr_regs) diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 09e9d6fb741..81c052b1353 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -76,7 +76,7 @@ static void __init mpc836x_mds_setup_arch(void) struct resource res; of_address_to_resource(np, 0, &res); - bcsr_regs = ioremap(res.start, res.end - res.start +1); + bcsr_regs = ioremap(res.start, resource_size(&res)); of_node_put(np); } diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index 2c64164722d..1ad748bb39b 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c @@ -171,7 +171,7 @@ int mpc831x_usb_cfg(void) of_node_put(np); return ret; } - usb_regs = ioremap(res.start, res.end - res.start + 1); + usb_regs = ioremap(res.start, resource_size(&res)); /* Using on-chip PHY */ if (prop && (!strcmp(prop, "utmi_wide") || diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index d2dfd465fbf..09ced722175 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c @@ -285,7 +285,7 @@ static int __init sbc8560_bdrstcr_init(void) printk(KERN_INFO "sbc8560: Found BRSTCR at i/o 0x%x\n", res.start); - brstcr = ioremap(res.start, res.end - res.start); + brstcr = ioremap(res.start, resource_size(&res)); if(!brstcr) printk(KERN_WARNING "sbc8560: ioremap of brstcr failed.\n"); diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 0125604d096..a9dc5e79512 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -123,7 +123,7 @@ static void xes_mpc85xx_fixups(void) continue; } - l2_base = ioremap(r[0].start, r[0].end - r[0].start + 1); + l2_base = ioremap(r[0].start, resource_size(&r[0])); xes_mpc85xx_configure_l2(l2_base); } diff --git a/arch/powerpc/platforms/cell/celleb_scc_epci.c b/arch/powerpc/platforms/cell/celleb_scc_epci.c index 05b0db3ef63..844c0facb4f 100644 --- a/arch/powerpc/platforms/cell/celleb_scc_epci.c +++ b/arch/powerpc/platforms/cell/celleb_scc_epci.c @@ -393,19 +393,19 @@ static int __init celleb_setup_epci(struct device_node *node, if (of_address_to_resource(node, 0, &r)) goto error; - hose->cfg_addr = ioremap(r.start, (r.end - r.start + 1)); + hose->cfg_addr = ioremap(r.start, resource_size(&r)); if (!hose->cfg_addr) goto error; pr_debug("EPCI: cfg_addr map 0x%016llx->0x%016lx + 0x%016llx\n", - r.start, (unsigned long)hose->cfg_addr, (r.end - r.start + 1)); + r.start, (unsigned long)hose->cfg_addr, resource_size(&r)); if (of_address_to_resource(node, 2, &r)) goto error; - hose->cfg_data = ioremap(r.start, (r.end - r.start + 1)); + hose->cfg_data = ioremap(r.start, resource_size(&r)); if (!hose->cfg_data) goto error; pr_debug("EPCI: cfg_data map 0x%016llx->0x%016lx + 0x%016llx\n", - r.start, (unsigned long)hose->cfg_data, (r.end - r.start + 1)); + r.start, (unsigned long)hose->cfg_data, resource_size(&r)); hose->ops = &celleb_epci_ops; celleb_epci_init(hose); diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c index a881bbee8de..ae790ac4a58 100644 --- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c +++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c @@ -494,7 +494,7 @@ static __init int celleb_setup_pciex(struct device_node *node, pr_err("PCIEXC:Failed to get config resource.\n"); return 1; } - phb->cfg_addr = ioremap(r.start, r.end - r.start + 1); + phb->cfg_addr = ioremap(r.start, resource_size(&r)); if (!phb->cfg_addr) { pr_err("PCIEXC:Failed to remap SMMIO region.\n"); return 1; diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index f465d474ad9..4e5c91489c0 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -222,7 +222,7 @@ static int spu_map_resource(struct spu *spu, int nr, return ret; if (phys) *phys = resource.start; - len = resource.end - resource.start + 1; + len = resource_size(&resource); *virt = ioremap(resource.start, len); if (!*virt) return -EINVAL; diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 8f67a394b2d..3f65443f171 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -142,7 +142,7 @@ hydra_init(void) return 0; } of_node_put(np); - Hydra = ioremap(r.start, r.end-r.start); + Hydra = ioremap(r.start, resource_size(&r)); printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start); printk("Hydra Feature_Control was %x", in_le32(&Hydra->Feature_Control)); diff --git a/arch/powerpc/platforms/pasemi/dma_lib.c b/arch/powerpc/platforms/pasemi/dma_lib.c index 321a9b3a2d0..756123bf06a 100644 --- a/arch/powerpc/platforms/pasemi/dma_lib.c +++ b/arch/powerpc/platforms/pasemi/dma_lib.c @@ -576,7 +576,7 @@ int pasemi_dma_init(void) res.start = 0xfd800000; res.end = res.start + 0x1000; } - dma_status = __ioremap(res.start, res.end-res.start, 0); + dma_status = __ioremap(res.start, resource_size(&res), 0); pci_dev_put(iob_pdev); for (i = 0; i < MAX_TXCH; i++) diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index b1cdcf94aa8..695443bfdb0 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c @@ -580,10 +580,10 @@ int __init pmac_nvram_init(void) /* Try to obtain an address */ if (of_address_to_resource(dp, 0, &r1) == 0) { nvram_naddrs = 1; - s1 = (r1.end - r1.start) + 1; + s1 = resource_size(&r1); if (of_address_to_resource(dp, 1, &r2) == 0) { nvram_naddrs = 2; - s2 = (r2.end - r2.start) + 1; + s2 = resource_size(&r2); } } diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index f33e08d573c..4d4eba32483 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -838,8 +838,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) * into cfg_addr */ hose->cfg_data = ioremap(cfg_res.start, 0x02000000); - hose->cfg_addr = ioremap(self_res.start, - self_res.end - self_res.start + 1); + hose->cfg_addr = ioremap(self_res.start, resource_size(&self_res)); /* * /ht node doesn't expose a "ranges" property, we read the register @@ -1323,8 +1322,7 @@ static void fixup_u4_pcie(struct pci_dev* dev) */ if (r->start >= 0xf0000000 && r->start < 0xf3000000) continue; - if (!region || (r->end - r->start) > - (region->end - region->start)) + if (!region || resource_size(r) > resource_size(region)) region = r; } /* Nothing found, bail */ diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index 48211ca134c..11c9fce43b5 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -274,7 +274,7 @@ int __init via_calibrate_decr(void) return 0; } of_node_put(vias); - via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); + via = ioremap(rsrc.start, resource_size(&rsrc)); if (via == NULL) { printk(KERN_ERR "Failed to map VIA for timer calibration !\n"); return 0; diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index bd0d54060b9..265f0f09395 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -203,7 +203,7 @@ static int axon_ram_probe(struct platform_device *device) goto failed; } - bank->size = resource.end - resource.start + 1; + bank->size = resource_size(&resource); if (bank->size == 0) { dev_err(&device->dev, "No DDR2 memory found for %s%d\n", diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 350787c83e2..5d7d59a43c4 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -148,7 +148,7 @@ unsigned int cpm_pic_init(void) if (ret) goto end; - cpic_reg = ioremap(res.start, res.end - res.start + 1); + cpic_reg = ioremap(res.start, resource_size(&res)); if (cpic_reg == NULL) goto end; diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 2b69aa0315b..d55d0ad0dea 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -115,7 +115,7 @@ int cpm_muram_init(void) max = r.end; rh_attach_region(&cpm_muram_info, r.start - muram_pbase, - r.end - r.start + 1); + resource_size(&r)); } muram_vbase = ioremap(muram_pbase, max - muram_pbase + 1); diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 8e9e06a7ca5..4f2680f431b 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -239,7 +239,7 @@ static int __init dart_init(struct device_node *dart_node) DARTMAP_RPNMASK); /* Map in DART registers */ - dart = ioremap(r.start, r.end - r.start + 1); + dart = ioremap(r.start, resource_size(&r)); if (dart == NULL) panic("DART: Cannot map registers!"); diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 92e78333c47..419a77239bd 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -349,7 +349,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) goto error_out; } - msi->msi_regs = ioremap(res.start, res.end - res.start + 1); + msi->msi_regs = ioremap(res.start, resource_size(&res)); if (!msi->msi_regs) { dev_err(&dev->dev, "ioremap problem failed\n"); goto error_out; diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 68ca9290df9..ba5cb3fa707 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -64,7 +64,7 @@ static int __init setup_one_atmu(struct ccsr_pci __iomem *pci, { resource_size_t pci_addr = res->start - offset; resource_size_t phys_addr = res->start; - resource_size_t size = res->end - res->start + 1; + resource_size_t size = resource_size(res); u32 flags = 0x80044000; /* enable & mem R/W */ unsigned int i; @@ -108,7 +108,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose, char *name = hose->dn->full_name; pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", - (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); + (u64)rsrc->start, (u64)resource_size(rsrc)); if (of_device_is_compatible(hose->dn, "fsl,qoriq-pcie-v2.2")) { win_idx = 2; @@ -116,7 +116,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose, end_idx = 3; } - pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); + pci = ioremap(rsrc->start, resource_size(rsrc)); if (!pci) { dev_err(hose->parent, "Unable to map ATMU registers\n"); return; @@ -153,9 +153,9 @@ static void __init setup_pci_atmu(struct pci_controller *hose, } else { pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, " "phy base 0x%016llx.\n", - (u64)hose->io_resource.start, - (u64)hose->io_resource.end - (u64)hose->io_resource.start + 1, - (u64)hose->io_base_phys); + (u64)hose->io_resource.start, + (u64)resource_size(&hose->io_resource), + (u64)hose->io_base_phys); out_be32(&pci->pow[j].potar, (hose->io_resource.start >> 12)); out_be32(&pci->pow[j].potear, 0); out_be32(&pci->pow[j].powbar, (hose->io_base_phys >> 12)); diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 5b206a2fe17..95853386a66 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -1523,7 +1523,7 @@ int fsl_rio_setup(struct platform_device *dev) port->priv = priv; port->phys_efptr = 0x100; - priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); + priv->regs_win = ioremap(regs.start, resource_size(®s)); rio_regs_win = priv->regs_win; /* Probe the master port phy type */ diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 7367d17364c..95da897f05a 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -736,7 +736,7 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) return NULL; } - ipic->regs = ioremap(res.start, res.end - res.start + 1); + ipic->regs = ioremap(res.start, resource_size(&res)); ipic->irqhost->host_data = ipic; diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c index ddc877a3a23..69f5814ae6d 100644 --- a/arch/powerpc/sysdev/mmio_nvram.c +++ b/arch/powerpc/sysdev/mmio_nvram.c @@ -129,7 +129,7 @@ int __init mmio_nvram_init(void) goto out; } nvram_addr = r.start; - mmio_nvram_len = r.end - r.start + 1; + mmio_nvram_len = resource_size(&r); if ( (!mmio_nvram_len) || (!nvram_addr) ) { printk(KERN_WARNING "nvram: address or length is 0\n"); ret = -EIO; diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 20924f2246f..22e48e2d71f 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -166,7 +166,7 @@ int mpc8xx_pic_init(void) if (ret) goto out; - siu_reg = ioremap(res.start, res.end - res.start + 1); + siu_reg = ioremap(res.start, resource_size(&res)); if (siu_reg == NULL) { ret = -EINVAL; goto out; diff --git a/arch/powerpc/sysdev/mv64x60_udbg.c b/arch/powerpc/sysdev/mv64x60_udbg.c index 2792dc8b038..50a81387e9b 100644 --- a/arch/powerpc/sysdev/mv64x60_udbg.c +++ b/arch/powerpc/sysdev/mv64x60_udbg.c @@ -125,11 +125,11 @@ static void mv64x60_udbg_init(void) of_node_put(np); - mpsc_base = ioremap(r[0].start, r[0].end - r[0].start + 1); + mpsc_base = ioremap(r[0].start, resource_size(&r[0])); if (!mpsc_base) return; - mpsc_intr_cause = ioremap(r[1].start, r[1].end - r[1].start + 1); + mpsc_intr_cause = ioremap(r[1].start, resource_size(&r[1])); if (!mpsc_intr_cause) { iounmap(mpsc_base); return; diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 156aa7d3625..deda60a7f99 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -265,7 +265,7 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, if (ppc4xx_setup_one_pci_PMM(hose, reg, res->start, res->start - hose->pci_mem_offset, - res->end + 1 - res->start, + resource_size(res), res->flags, j) == 0) { j++; @@ -290,7 +290,7 @@ static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, void __iomem *reg, const struct resource *res) { - resource_size_t size = res->end - res->start + 1; + resource_size_t size = resource_size(res); u32 sa; /* Calculate window size */ @@ -349,7 +349,7 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) bus_range = of_get_property(np, "bus-range", NULL); /* Map registers */ - reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start); + reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg)); if (reg == NULL) { printk(KERN_ERR "%s: Can't map registers !", np->full_name); goto fail; @@ -465,7 +465,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, if (ppc4xx_setup_one_pcix_POM(hose, reg, res->start, res->start - hose->pci_mem_offset, - res->end + 1 - res->start, + resource_size(res), res->flags, j) == 0) { j++; @@ -492,7 +492,7 @@ static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, int big_pim, int enable_msi_hole) { - resource_size_t size = res->end - res->start + 1; + resource_size_t size = resource_size(res); u32 sa; /* RAM is always at 0 */ @@ -555,7 +555,7 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np) bus_range = of_get_property(np, "bus-range", NULL); /* Map registers */ - reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start); + reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg)); if (reg == NULL) { printk(KERN_ERR "%s: Can't map registers !", np->full_name); goto fail; @@ -1604,7 +1604,7 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, res->start, res->start - hose->pci_mem_offset, - res->end + 1 - res->start, + resource_size(res), res->flags, j) == 0) { j++; @@ -1639,7 +1639,7 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, void __iomem *mbase, struct resource *res) { - resource_size_t size = res->end - res->start + 1; + resource_size_t size = resource_size(res); u64 sa; if (port->endpoint) { diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index b2acda07220..18e75ca19fe 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -347,7 +347,7 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, return; } - qe_ic->regs = ioremap(res.start, res.end - res.start + 1); + qe_ic->regs = ioremap(res.start, resource_size(&res)); qe_ic->irqhost->host_data = qe_ic; qe_ic->hc_irq = qe_ic_irq_chip; diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index 77e4934b88c..fd1a6c3b172 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -41,7 +41,7 @@ int par_io_init(struct device_node *np) ret = of_address_to_resource(np, 0, &res); if (ret) return ret; - par_io = ioremap(res.start, res.end - res.start + 1); + par_io = ioremap(res.start, resource_size(&res)); num_ports = of_get_property(np, "num-ports", NULL); if (num_ports) diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index 1f15ad43614..039a7820ba7 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -247,7 +247,7 @@ static int __init icp_native_init_one_node(struct device_node *np, return -1; } - if (icp_native_map_one_cpu(*indx, r.start, r.end - r.start)) + if (icp_native_map_one_cpu(*indx, r.start, resource_size(&r))) return -1; (*indx)++; diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index 32c385ef101..0f62f467275 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c @@ -58,7 +58,7 @@ int register_trapped_io(struct trapped_io *tiop) for (k = 0; k < tiop->num_resources; k++) { res = tiop->resource + k; - len += roundup((res->end - res->start) + 1, PAGE_SIZE); + len += roundup(resource_size(res), PAGE_SIZE); flags |= res->flags; } @@ -85,7 +85,7 @@ int register_trapped_io(struct trapped_io *tiop) (unsigned long)(tiop->virt_base + len), res->flags & IORESOURCE_IO ? "io" : "mmio", (unsigned long)res->start); - len += roundup((res->end - res->start) + 1, PAGE_SIZE); + len += roundup(resource_size(res), PAGE_SIZE); } tiop->magic = IO_TRAPPED_MAGIC; @@ -128,7 +128,7 @@ void __iomem *match_trapped_io_handler(struct list_head *list, return tiop->virt_base + voffs; } - len = (res->end - res->start) + 1; + len = resource_size(res); voffs += roundup(len, PAGE_SIZE); } } @@ -173,7 +173,7 @@ static unsigned long lookup_address(struct trapped_io *tiop, for (k = 0; k < tiop->num_resources; k++) { res = tiop->resource + k; - len = roundup((res->end - res->start) + 1, PAGE_SIZE); + len = roundup(resource_size(res), PAGE_SIZE); if (address < (vaddr + len)) return res->start + (address - vaddr); vaddr += len; diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index e2a3af31ff9..c5a33f007f8 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c @@ -170,7 +170,7 @@ void __init reserve_crashkernel(void) if (crashk_res.end == crashk_res.start) goto disable; - crash_size = PAGE_ALIGN(crashk_res.end - crashk_res.start + 1); + crash_size = PAGE_ALIGN(resource_size(&crashk_res)); if (!crashk_res.start) { unsigned long max = memblock_end_of_DRAM() - memory_limit; crashk_res.start = __memblock_alloc_base(crash_size, PAGE_SIZE, max); diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 1c9c80a1a86..6ffccd6e015 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -228,7 +228,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) } pa &= PAGE_MASK; - sparc_mapiorange(bus, pa, res->start, res->end - res->start + 1); + sparc_mapiorange(bus, pa, res->start, resource_size(res)); return (void __iomem *)(unsigned long)(res->start + offset); } @@ -240,7 +240,7 @@ static void _sparc_free_io(struct resource *res) { unsigned long plen; - plen = res->end - res->start + 1; + plen = resource_size(res); BUG_ON((plen & (PAGE_SIZE-1)) != 0); sparc_unmapiorange(res->start, plen); release_resource(res); @@ -331,9 +331,9 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p, } n = PAGE_ALIGN(n); - if ((res->end-res->start)+1 != n) { + if (resource_size(res) != n) { printk("sbus_free_consistent: region 0x%lx asked 0x%zx\n", - (long)((res->end-res->start)+1), n); + (long)resource_size(res), n); return; } @@ -504,9 +504,9 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p, } n = PAGE_ALIGN(n); - if ((res->end-res->start)+1 != n) { + if (resource_size(res) != n) { printk("pci_free_consistent: region 0x%lx asked 0x%lx\n", - (long)((res->end-res->start)+1), (long)n); + (long)resource_size(res), (long)n); return; } diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 713dc91020a..2d1453dd93d 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -820,11 +820,9 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc unsigned long space_size, user_offset, user_size; if (mmap_state == pci_mmap_io) { - space_size = (pbm->io_space.end - - pbm->io_space.start) + 1; + space_size = resource_size(&pbm->io_space); } else { - space_size = (pbm->mem_space.end - - pbm->mem_space.start) + 1; + space_size = resource_size(&pbm->mem_space); } /* Make sure the request is in range. */ diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index 6cdc9ba55fe..5f85d8b34db 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -553,8 +553,7 @@ static void __init setup_bootmem_allocator(void) #ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) - reserve_bootmem(crashk_res.start, - crashk_res.end - crashk_res.start + 1, 0); + reserve_bootmem(crashk_res.start, resource_size(&crashk_res), 0); #endif } diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index e8c33a30200..726494b5834 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -1553,7 +1553,7 @@ static void __init calgary_fixup_one_tce_space(struct pci_dev *dev) continue; /* cover the whole region */ - npages = (r->end - r->start) >> PAGE_SHIFT; + npages = resource_size(r) >> PAGE_SHIFT; npages++; iommu_range_reserve(tbl, r->start, npages); diff --git a/arch/x86/kernel/probe_roms.c b/arch/x86/kernel/probe_roms.c index ba0a4cce53b..63228035f9d 100644 --- a/arch/x86/kernel/probe_roms.c +++ b/arch/x86/kernel/probe_roms.c @@ -234,7 +234,7 @@ void __init probe_roms(void) /* check for extension rom (ignore length byte!) */ rom = isa_bus_to_virt(extension_rom_resource.start); if (romsignature(rom)) { - length = extension_rom_resource.end - extension_rom_resource.start + 1; + length = resource_size(&extension_rom_resource); if (romchecksum(rom, length)) { request_resource(&iomem_resource, &extension_rom_resource); upper = extension_rom_resource.start; diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index cf39bc08ce0..0c688232aab 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -212,7 +212,7 @@ static int bsr_add_node(struct device_node *bn) cur->bsr_minor = i + total_bsr_devs; cur->bsr_addr = res.start; - cur->bsr_len = res.end - res.start + 1; + cur->bsr_len = resource_size(&res); cur->bsr_bytes = bsr_bytes[i]; cur->bsr_stride = bsr_stride[i]; cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 39ccdeada79..e90e1c74fd4 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -621,7 +621,7 @@ static int __devinit hwicap_setup(struct device *dev, int id, drvdata->mem_start = regs_res->start; drvdata->mem_end = regs_res->end; - drvdata->mem_size = regs_res->end - regs_res->start + 1; + drvdata->mem_size = resource_size(regs_res); if (!request_mem_region(drvdata->mem_start, drvdata->mem_size, DRIVER_NAME)) { diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 954e334e01b..06f9f27dbe7 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1304,8 +1304,7 @@ static int mv_xor_shared_probe(struct platform_device *pdev) if (!res) return -ENODEV; - msp->xor_base = devm_ioremap(&pdev->dev, res->start, - res->end - res->start + 1); + msp->xor_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!msp->xor_base) return -EBUSY; @@ -1314,7 +1313,7 @@ static int mv_xor_shared_probe(struct platform_device *pdev) return -ENODEV; msp->xor_high_base = devm_ioremap(&pdev->dev, res->start, - res->end - res->start + 1); + resource_size(res)); if (!msp->xor_high_base) return -EBUSY; diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index db1df59ae2b..9a6a274e692 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -140,7 +140,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci) if (of_node_to_nid(np) != priv->node) continue; csrow->first_page = r.start >> PAGE_SHIFT; - csrow->nr_pages = (r.end - r.start + 1) >> PAGE_SHIFT; + csrow->nr_pages = resource_size(&r) >> PAGE_SHIFT; csrow->last_page = csrow->first_page + csrow->nr_pages - 1; csrow->mtype = MEM_XDR; csrow->edac_mode = EDAC_SECDED; diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 38ab8e2cd7f..11e1a5dad96 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -538,15 +538,15 @@ static int __devinit mpc85xx_l2_err_probe(struct platform_device *op) /* we only need the error registers */ r.start += 0xe00; - if (!devm_request_mem_region(&op->dev, r.start, - r.end - r.start + 1, pdata->name)) { + if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), + pdata->name)) { printk(KERN_ERR "%s: Error while requesting mem region\n", __func__); res = -EBUSY; goto err; } - pdata->l2_vbase = devm_ioremap(&op->dev, r.start, r.end - r.start + 1); + pdata->l2_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->l2_vbase) { printk(KERN_ERR "%s: Unable to setup L2 err regs\n", __func__); res = -ENOMEM; @@ -987,15 +987,15 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op) goto err; } - if (!devm_request_mem_region(&op->dev, r.start, - r.end - r.start + 1, pdata->name)) { + if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), + pdata->name)) { printk(KERN_ERR "%s: Error while requesting mem region\n", __func__); res = -EBUSY; goto err; } - pdata->mc_vbase = devm_ioremap(&op->dev, r.start, r.end - r.start + 1); + pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->mc_vbase) { printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__); res = -ENOMEM; diff --git a/drivers/gpio/gpio-u300.c b/drivers/gpio/gpio-u300.c index d92790140fe..1a86fefd0f8 100644 --- a/drivers/gpio/gpio-u300.c +++ b/drivers/gpio/gpio-u300.c @@ -581,8 +581,8 @@ static int __init gpio_probe(struct platform_device *pdev) if (!memres) goto err_no_resource; - if (request_mem_region(memres->start, memres->end - memres->start, "GPIO Controller") - == NULL) { + if (!request_mem_region(memres->start, resource_size(memres), + "GPIO Controller")) { err = -ENODEV; goto err_no_ioregion; } @@ -640,7 +640,7 @@ static int __init gpio_probe(struct platform_device *pdev) free_irq(gpio_ports[i].irq, &gpio_ports[i]); iounmap(virtbase); err_no_ioremap: - release_mem_region(memres->start, memres->end - memres->start); + release_mem_region(memres->start, resource_size(memres)); err_no_ioregion: err_no_resource: clk_disable(clk); @@ -660,7 +660,7 @@ static int __exit gpio_remove(struct platform_device *pdev) for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++) free_irq(gpio_ports[i].irq, &gpio_ports[i]); iounmap(virtbase); - release_mem_region(memres->start, memres->end - memres->start); + release_mem_region(memres->start, resource_size(memres)); clk_disable(clk); clk_put(clk); return 0; diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c index 9e8f4e1b0cc..712c7904d03 100644 --- a/drivers/ide/palm_bk3710.c +++ b/drivers/ide/palm_bk3710.c @@ -342,7 +342,7 @@ static int __init palm_bk3710_probe(struct platform_device *pdev) return -ENODEV; } - mem_size = mem->end - mem->start + 1; + mem_size = resource_size(mem); if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) { printk(KERN_ERR "failed to request memory region\n"); return -EBUSY; diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c index bed3e39aac9..71c23195497 100644 --- a/drivers/ide/tx4939ide.c +++ b/drivers/ide/tx4939ide.c @@ -551,10 +551,10 @@ static int __init tx4939ide_probe(struct platform_device *pdev) return -ENODEV; if (!devm_request_mem_region(&pdev->dev, res->start, - res->end - res->start + 1, "tx4938ide")) + resource_size(res), "tx4938ide")) return -EBUSY; mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, - res->end - res->start + 1); + resource_size(res)); if (!mapbase) return -EBUSY; memset(&hw, 0, sizeof(hw)); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index d55874e5d1c..44fc8b4bcd8 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -300,8 +300,7 @@ static int __devinit ps2_probe(struct sa1111_dev *dev) out: sa1111_disable_device(ps2if->dev); - release_mem_region(dev->res.start, - dev->res.end - dev->res.start + 1); + release_mem_region(dev->res.start, resource_size(&dev->res)); free: sa1111_set_drvdata(dev, NULL); kfree(ps2if); @@ -317,8 +316,7 @@ static int __devexit ps2_remove(struct sa1111_dev *dev) struct ps2if *ps2if = sa1111_get_drvdata(dev); serio_unregister_port(ps2if->io); - release_mem_region(dev->res.start, - dev->res.end - dev->res.start + 1); + release_mem_region(dev->res.start, resource_size(&dev->res)); sa1111_set_drvdata(dev, NULL); kfree(ps2if); diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index 9f3bfc1eb24..af9680273ff 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c @@ -422,7 +422,7 @@ static int __init vpif_probe(struct platform_device *pdev) if (!res) return -ENOENT; - res_len = res->end - res->start + 1; + res_len = resource_size(res); res = request_mem_region(res->start, res_len, res->name); if (!res) diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index f6626e87dbc..69b60ba5dd7 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -1768,14 +1768,13 @@ static int __devinit omap24xxcam_probe(struct platform_device *pdev) dev_err(cam->dev, "no mem resource?\n"); goto err; } - if (!request_mem_region(mem->start, (mem->end - mem->start) + 1, - pdev->name)) { + if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) { dev_err(cam->dev, "cannot reserve camera register I/O region\n"); goto err; } cam->mmio_base_phys = mem->start; - cam->mmio_size = (mem->end - mem->start) + 1; + cam->mmio_size = resource_size(mem); /* map the region */ cam->mmio_base = (unsigned long) diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 090d2a3a654..a8c08f332da 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -681,11 +681,11 @@ static int i2o_iop_systab_set(struct i2o_controller *c) if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ NULL, NULL) >= 0) { c->mem_alloc = 1; - sb->current_mem_size = 1 + res->end - res->start; + sb->current_mem_size = resource_size(res); sb->current_mem_base = res->start; osm_info("%s: allocated %llu bytes of PCI memory at " "0x%016llX.\n", c->name, - (unsigned long long)(1 + res->end - res->start), + (unsigned long long)resource_size(res), (unsigned long long)res->start); } } @@ -703,11 +703,11 @@ static int i2o_iop_systab_set(struct i2o_controller *c) if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ NULL, NULL) >= 0) { c->io_alloc = 1; - sb->current_io_size = 1 + res->end - res->start; + sb->current_io_size = resource_size(res); sb->current_mem_base = res->start; osm_info("%s: allocated %llu bytes of PCI I/O at " "0x%016llX.\n", c->name, - (unsigned long long)(1 + res->end - res->start), + (unsigned long long)resource_size(res), (unsigned long long)res->start); } } diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index ad715bf49ca..71bc835324d 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -177,7 +177,7 @@ static int __devinit tc6387xb_probe(struct platform_device *dev) if (ret) goto err_resource; - tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); + tc6387xb->scr = ioremap(rscr->start, resource_size(rscr)); if (!tc6387xb->scr) { ret = -ENOMEM; goto err_ioremap; diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 4afffe610f9..769a4e8e10d 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -95,7 +95,7 @@ static int __init ssc_probe(struct platform_device *pdev) } ssc->pdev = pdev; - ssc->regs = ioremap(regs->start, regs->end - regs->start + 1); + ssc->regs = ioremap(regs->start, resource_size(regs)); if (!ssc->regs) { dev_dbg(&pdev->dev, "ioremap failed\n"); retval = -EINVAL; diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c index 0f3fb4f03bd..28f5aaa19d4 100644 --- a/drivers/misc/atmel_pwm.c +++ b/drivers/misc/atmel_pwm.c @@ -329,7 +329,7 @@ static int __init pwm_probe(struct platform_device *pdev) p->pdev = pdev; p->mask = *mp; p->irq = irq; - p->base = ioremap(r->start, r->end - r->start + 1); + p->base = ioremap(r->start, resource_size(r)); if (!p->base) goto fail; p->clk = clk_get(&pdev->dev, "pwm_clk"); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 66dcddb9c20..2a069f908b2 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1595,7 +1595,7 @@ static int dw_mci_probe(struct platform_device *pdev) INIT_LIST_HEAD(&host->queue); ret = -ENOMEM; - host->regs = ioremap(regs->start, regs->end - regs->start + 1); + host->regs = ioremap(regs->start, resource_size(regs)); if (!host->regs) goto err_freehost; diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index d4297a97e10..67815eed2f0 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -142,7 +142,7 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev) state->map.write = bfin_flash_write; state->map.copy_to = bfin_flash_copy_to; state->map.bankwidth = pdata->width; - state->map.size = memory->end - memory->start + 1; + state->map.size = resource_size(memory); state->map.virt = (void __iomem *)memory->start; state->map.phys = memory->start; state->map.map_priv_1 = (unsigned long)state; diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index c00b9175ba9..1594a802631 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -155,7 +155,7 @@ static int ixp2000_flash_probe(struct platform_device *dev) if (!plat) return -ENODEV; - window_size = dev->resource->end - dev->resource->start + 1; + window_size = resource_size(dev->resource); dev_info(&dev->dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", ixp_data->nr_banks, ((u32)window_size >> 20)); @@ -194,16 +194,17 @@ static int ixp2000_flash_probe(struct platform_device *dev) info->map.copy_to = ixp2000_flash_copy_to; info->res = request_mem_region(dev->resource->start, - dev->resource->end - dev->resource->start + 1, - dev_name(&dev->dev)); + resource_size(dev->resource), + dev_name(&dev->dev)); if (!info->res) { dev_err(&dev->dev, "Could not reserve memory region\n"); err = -ENOMEM; goto Error; } - info->map.map_priv_1 = (unsigned long) ioremap(dev->resource->start, - dev->resource->end - dev->resource->start + 1); + info->map.map_priv_1 = + (unsigned long)ioremap(dev->resource->start, + resource_size(dev->resource)); if (!info->map.map_priv_1) { dev_err(&dev->dev, "Failed to ioremap flash region\n"); err = -EIO; diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index f59d62f74d4..7ae137d4b99 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -70,7 +70,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) info->map.name = (char *) flash->name; info->map.bankwidth = flash->width; info->map.phys = res->start; - info->map.size = res->end - res->start + 1; + info->map.size = resource_size(res); info->parts = flash->parts; info->nr_parts = flash->nr_parts; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index b300705d41c..d4ba1f218e9 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -513,7 +513,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) host->io_phys = (dma_addr_t)mem->start; - host->io_base = ioremap(mem->start, mem->end - mem->start + 1); + host->io_base = ioremap(mem->start, resource_size(mem)); if (host->io_base == NULL) { printk(KERN_ERR "atmel_nand: ioremap failed\n"); res = -EIO; @@ -547,7 +547,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (no_ecc) nand_chip->ecc.mode = NAND_ECC_NONE; if (hard_ecc && regs) { - host->ecc = ioremap(regs->start, regs->end - regs->start + 1); + host->ecc = ioremap(regs->start, resource_size(regs)); if (host->ecc == NULL) { printk(KERN_ERR "atmel_nand: ioremap failed\n"); res = -EIO; diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 9ec280738a9..8c569e454dc 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -380,7 +380,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) return -ENXIO; /* map physical address */ - bcm_umi_io_base = ioremap(r->start, r->end - r->start + 1); + bcm_umi_io_base = ioremap(r->start, resource_size(r)); if (!bcm_umi_io_base) { printk(KERN_ERR "ioremap to access BCM UMI NAND chip failed\n"); diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 2f7c930872f..eb1fbac63eb 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -713,7 +713,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) } regs_paddr = res.start; - regs_size = res.end - res.start + 1; + regs_size = resource_size(&res); if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) { dev_err(dev, "Error requesting memory region!\n"); diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index f1573d492e9..85045cde312 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -1646,7 +1646,7 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev) if (ret) goto out; - iomem_size = res_mem->end - res_mem->start + 1; + iomem_size = resource_size(res_mem); if (!request_mem_region(res_mem->start, iomem_size, "bcm63xx_enet")) { ret = -EBUSY; goto out; @@ -1861,7 +1861,7 @@ static int __devexit bcm_enet_remove(struct platform_device *pdev) /* release device resources */ iounmap(priv->base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); /* disable hw block clocks */ if (priv->phy_clk) { @@ -1897,7 +1897,7 @@ static int __devinit bcm_enet_shared_probe(struct platform_device *pdev) if (!res) return -ENODEV; - iomem_size = res->end - res->start + 1; + iomem_size = resource_size(res); if (!request_mem_region(res->start, iomem_size, "bcm63xx_enet_dma")) return -EBUSY; @@ -1915,7 +1915,7 @@ static int __devexit bcm_enet_shared_remove(struct platform_device *pdev) iounmap(bcm_enet_shared_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); return 0; } diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index 60a49e5a2a5..f76e88e7428 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -799,7 +799,7 @@ static __devinit int softing_pdev_probe(struct platform_device *pdev) if (!pres) goto platform_resource_failed; card->dpram_phys = pres->start; - card->dpram_size = pres->end - pres->start + 1; + card->dpram_size = resource_size(pres); card->dpram = ioremap_nocache(card->dpram_phys, card->dpram_size); if (!card->dpram) { dev_alert(&card->pdev->dev, "dpram ioremap failed\n"); diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index dcc4a170b0f..c35ba5fba8f 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1821,7 +1821,7 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) } priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; - size = res->end - res->start + 1; + size = resource_size(res); if (!request_mem_region(res->start, size, ndev->name)) { dev_err(&pdev->dev, "failed request_mem_region() for regs\n"); rc = -ENXIO; @@ -1926,7 +1926,7 @@ no_irq_res: cpdma_ctlr_destroy(priv->dma); no_dma: res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); iounmap(priv->remap_addr); probe_quit: @@ -1960,7 +1960,7 @@ static int __devexit davinci_emac_remove(struct platform_device *pdev) cpdma_chan_destroy(priv->rxchan); cpdma_ctlr_destroy(priv->dma); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); unregister_netdev(ndev); iounmap(priv->remap_addr); diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index a83dd312c3a..15e4a71fbf1 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -965,7 +965,7 @@ static int __devinit ethoc_probe(struct platform_device *pdev) priv = netdev_priv(netdev); priv->netdev = netdev; priv->dma_alloc = 0; - priv->io_region_size = mmio->end - mmio->start + 1; + priv->io_region_size = resource_size(mmio); priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, resource_size(mmio)); diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 9f81b1ac130..fe57eee8a67 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -867,10 +867,11 @@ static int __devinit mpc52xx_fec_probe(struct platform_device *op) "Error while parsing device node resource\n" ); goto err_netdev; } - if ((mem.end - mem.start + 1) < sizeof(struct mpc52xx_fec)) { + if (resource_size(&mem) < sizeof(struct mpc52xx_fec)) { printk(KERN_ERR DRIVER_NAME - " - invalid resource size (%lx < %x), check mpc52xx_devices.c\n", - (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec)); + " - invalid resource size (%lx < %x), check mpc52xx_devices.c\n", + (unsigned long)resource_size(&mem), + sizeof(struct mpc52xx_fec)); rv = -EINVAL; goto err_netdev; } diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index ad297544071..b09270b5d0a 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -120,7 +120,7 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, if (ret) return ret; - if (res.end - res.start < 13) + if (resource_size(&res) <= 13) return -ENODEV; /* This should really encode the pin number as well, but all @@ -139,7 +139,7 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, return -ENODEV; mdc_pin = *data; - bitbang->dir = ioremap(res.start, res.end - res.start + 1); + bitbang->dir = ioremap(res.start, resource_size(&res)); if (!bitbang->dir) return -ENOMEM; diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 6a2e150e75b..e0e9d6c35d8 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -136,7 +136,7 @@ static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); - fec->fecp = ioremap(res.start, res.end - res.start + 1); + fec->fecp = ioremap(res.start, resource_size(&res)); if (!fec->fecp) goto out_fec; diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/gianfar_ptp.c index d8e175382d1..1c97861596f 100644 --- a/drivers/net/gianfar_ptp.c +++ b/drivers/net/gianfar_ptp.c @@ -491,7 +491,7 @@ static int gianfar_ptp_probe(struct platform_device *dev) spin_lock_init(&etsects->lock); etsects->regs = ioremap(etsects->rsrc->start, - 1 + etsects->rsrc->end - etsects->rsrc->start); + resource_size(etsects->rsrc)); if (!etsects->regs) { pr_err("ioremap ptp registers failed\n"); goto no_ioremap; diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 079450fe5e9..725399ea069 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2770,7 +2770,7 @@ static int __devinit emac_probe(struct platform_device *ofdev) } // TODO : request_mem_region dev->emacp = ioremap(dev->rsrc_regs.start, - dev->rsrc_regs.end - dev->rsrc_regs.start + 1); + resource_size(&dev->rsrc_regs)); if (dev->emacp == NULL) { printk(KERN_ERR "%s: Can't map device registers!\n", np->full_name); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 6c6a02869df..27125cdd7e0 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1169,7 +1169,7 @@ static int __init macb_probe(struct platform_device *pdev) clk_enable(bp->hclk); #endif - bp->regs = ioremap(regs->start, regs->end - regs->start + 1); + bp->regs = ioremap(regs->start, resource_size(regs)); if (!bp->regs) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); err = -ENOMEM; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index a5d9b1c310b..b7564825738 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2593,7 +2593,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) if (msp == NULL) goto out; - msp->base = ioremap(res->start, res->end - res->start + 1); + msp->base = ioremap(res->start, resource_size(res)); if (msp->base == NULL) goto out_free; diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index 89f7540d90f..df1292eb9c2 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -1502,7 +1502,7 @@ static int pxa168_eth_probe(struct platform_device *pdev) err = -ENODEV; goto err_netdev; } - pep->base = ioremap(res->start, res->end - res->start + 1); + pep->base = ioremap(res->start, resource_size(res)); if (pep->base == NULL) { err = -ENOMEM; goto err_netdev; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 68d50429ddf..ea65f7ec360 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2597,7 +2597,7 @@ static int __devinit sbmac_probe(struct platform_device *pldev) res = platform_get_resource(pldev, IORESOURCE_MEM, 0); BUG_ON(!res); - sbm_base = ioremap_nocache(res->start, res->end - res->start + 1); + sbm_base = ioremap_nocache(res->start, resource_size(res)); if (!sbm_base) { printk(KERN_ERR "%s: unable to map device registers\n", dev_name(&pldev->dev)); diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c index 2c5ac2bf5c5..844f6137970 100644 --- a/drivers/parport/parport_ax88796.c +++ b/drivers/parport/parport_ax88796.c @@ -293,7 +293,7 @@ static int parport_ax88796_probe(struct platform_device *pdev) goto exit_mem; } - size = (res->end - res->start) + 1; + size = resource_size(res); spacing = size / 3; dd->io = request_mem_region(res->start, size, pdev->name); diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index 071b7dc0094..efa30da1ae8 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -50,29 +50,26 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_MEM) && !(res->flags & IORESOURCE_PREFETCH)) { - out += sprintf(out, "start = %8.8llx, " - "length = %8.8llx\n", - (unsigned long long)res->start, - (unsigned long long)(res->end - res->start)); + out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } out += sprintf(out, "Free resources: prefetchable memory\n"); pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_MEM) && (res->flags & IORESOURCE_PREFETCH)) { - out += sprintf(out, "start = %8.8llx, " - "length = %8.8llx\n", - (unsigned long long)res->start, - (unsigned long long)(res->end - res->start)); + out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } out += sprintf(out, "Free resources: IO\n"); pci_bus_for_each_resource(bus, res, index) { if (res && (res->flags & IORESOURCE_IO)) { - out += sprintf(out, "start = %8.8llx, " - "length = %8.8llx\n", - (unsigned long long)res->start, - (unsigned long long)(res->end - res->start)); + out += sprintf(out, "start = %8.8llx, length = %8.8llx\n", + (unsigned long long)res->start, + (unsigned long long)resource_size(res)); } } out += sprintf(out, "Free resources: bus numbers\n"); diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index fb33fa42d24..4902206f53d 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -283,8 +283,7 @@ static int __init at91_cf_probe(struct platform_device *pdev) } /* reserve chip-select regions */ - if (!request_mem_region(io->start, io->end + 1 - io->start, - driver_name)) { + if (!request_mem_region(io->start, resource_size(io), driver_name)) { status = -ENXIO; goto fail1; } @@ -308,7 +307,7 @@ static int __init at91_cf_probe(struct platform_device *pdev) return 0; fail2: - release_mem_region(io->start, io->end + 1 - io->start); + release_mem_region(io->start, resource_size(io)); fail1: if (cf->socket.io_offset) iounmap((void __iomem *) cf->socket.io_offset); @@ -339,7 +338,7 @@ static int __exit at91_cf_remove(struct platform_device *pdev) struct resource *io = cf->socket.io[0].res; pcmcia_unregister_socket(&cf->socket); - release_mem_region(io->start, io->end + 1 - io->start); + release_mem_region(io->start, resource_size(io)); iounmap((void __iomem *) cf->socket.io_offset); if (board->irq_pin) { free_irq(board->irq_pin, cf); diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index 6defd4a8168..06ad3e5e7d3 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -209,9 +209,9 @@ static int __devinit electra_cf_probe(struct platform_device *ofdev) cf->ofdev = ofdev; cf->mem_phys = mem.start; - cf->mem_size = PAGE_ALIGN(mem.end - mem.start); + cf->mem_size = PAGE_ALIGN(resource_size(&mem)); cf->mem_base = ioremap(cf->mem_phys, cf->mem_size); - cf->io_size = PAGE_ALIGN(io.end - io.start); + cf->io_size = PAGE_ALIGN(resource_size(&io)); area = __get_vm_area(cf->io_size, 0, PHB_IO_BASE, PHB_IO_END); if (area == NULL) diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c index 523eb691c30..f53c237bda2 100644 --- a/drivers/pcmcia/rsrc_iodyn.c +++ b/drivers/pcmcia/rsrc_iodyn.c @@ -135,7 +135,7 @@ static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr, try = res->end + 1; if ((*base == 0) || (*base == try)) { if (adjust_resource(s->io[i].res, res->start, - res->end - res->start + num + 1)) + resource_size(res) + num)) continue; *base = try; s->io[i].InUse += num; @@ -147,8 +147,8 @@ static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr, try = res->start - num; if ((*base == 0) || (*base == try)) { if (adjust_resource(s->io[i].res, - res->start - num, - res->end - res->start + num + 1)) + res->start - num, + resource_size(res) + num)) continue; *base = try; s->io[i].InUse += num; diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index b187555d438..9da9656242a 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -770,7 +770,7 @@ static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr, res->end + num); if (!ret) { ret = adjust_resource(s->io[i].res, res->start, - res->end - res->start + num + 1); + resource_size(res) + num); if (ret) continue; *base = try; @@ -788,8 +788,8 @@ static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr, res->end); if (!ret) { ret = adjust_resource(s->io[i].res, - res->start - num, - res->end - res->start + num + 1); + res->start - num, + resource_size(res) + num); if (ret) continue; *base = try; diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 100e4d9372f..1a6937d9118 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -1018,7 +1018,7 @@ static void pnpacpi_encode_io(struct pnp_dev *dev, io->minimum = p->start; io->maximum = p->end; io->alignment = 0; /* Correct? */ - io->address_length = p->end - p->start + 1; + io->address_length = resource_size(p); } else { io->minimum = 0; io->address_length = 0; @@ -1036,7 +1036,7 @@ static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, if (pnp_resource_enabled(p)) { fixed_io->address = p->start; - fixed_io->address_length = p->end - p->start + 1; + fixed_io->address_length = resource_size(p); } else { fixed_io->address = 0; fixed_io->address_length = 0; @@ -1059,7 +1059,7 @@ static void pnpacpi_encode_mem24(struct pnp_dev *dev, memory24->minimum = p->start; memory24->maximum = p->end; memory24->alignment = 0; - memory24->address_length = p->end - p->start + 1; + memory24->address_length = resource_size(p); } else { memory24->minimum = 0; memory24->address_length = 0; @@ -1083,7 +1083,7 @@ static void pnpacpi_encode_mem32(struct pnp_dev *dev, memory32->minimum = p->start; memory32->maximum = p->end; memory32->alignment = 0; - memory32->address_length = p->end - p->start + 1; + memory32->address_length = resource_size(p); } else { memory32->minimum = 0; memory32->alignment = 0; @@ -1106,7 +1106,7 @@ static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, p->flags & IORESOURCE_MEM_WRITEABLE ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; fixed_memory32->address = p->start; - fixed_memory32->address_length = p->end - p->start + 1; + fixed_memory32->address_length = resource_size(p); } else { fixed_memory32->address = 0; fixed_memory32->address_length = 0; diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index cb1f47bfee9..cca2f9f9f3e 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -505,7 +505,7 @@ static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -529,7 +529,7 @@ static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -559,7 +559,7 @@ static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -617,7 +617,7 @@ static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -636,11 +636,11 @@ static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p, struct resource *res) { unsigned long base = res->start; - unsigned long len = res->end - res->start + 1; + unsigned long len = resource_size(res); if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index e725d51e773..8dd08305aae 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -223,7 +223,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) } rtc->irq = irq; - rtc->regs = ioremap(regs->start, regs->end - regs->start + 1); + rtc->regs = ioremap(regs->start, resource_size(regs)); if (!rtc->regs) { ret = -ENOMEM; dev_dbg(&pdev->dev, "could not map I/O memory\n"); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 911e75cdc12..05beb6c1ca7 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -606,7 +606,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) * (needing ioremap etc), not i/o space resources like this ... */ ports = request_region(ports->start, - ports->end + 1 - ports->start, + resource_size(ports), driver_name); if (!ports) { dev_dbg(dev, "i/o registers already in use\n"); @@ -750,7 +750,7 @@ cleanup1: cmos_rtc.dev = NULL; rtc_device_unregister(cmos_rtc.rtc); cleanup0: - release_region(ports->start, ports->end + 1 - ports->start); + release_region(ports->start, resource_size(ports)); return retval; } @@ -779,7 +779,7 @@ static void __exit cmos_do_remove(struct device *dev) cmos->rtc = NULL; ports = cmos->iomem; - release_region(ports->start, ports->end + 1 - ports->start); + release_region(ports->start, resource_size(ports)); cmos->iomem = NULL; cmos->dev = NULL; diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 47e681df31e..68e6caf2549 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -343,7 +343,7 @@ static int __devinit ds1286_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->size = res->end - res->start + 1; + priv->size = resource_size(res); if (!request_mem_region(res->start, priv->size, pdev->name)) { ret = -EBUSY; goto out; diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index fbabc773dde..568ad30617e 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -490,7 +490,7 @@ ds1511_rtc_probe(struct platform_device *pdev) pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->size = res->end - res->start + 1; + pdata->size = resource_size(res); if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, pdev->name)) return -EBUSY; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 042630c90dd..d84a448dd75 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -173,7 +173,7 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->size = res->end - res->start + 1; + pdata->size = resource_size(res); if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, pdev->name)) return -EBUSY; diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index 7410875e583..8e2a24e33ed 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -154,7 +154,7 @@ static int __devinit m48t35_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->size = res->end - res->start + 1; + priv->size = resource_size(res); /* * kludge: remove the #ifndef after ioc3 resource * conflicts are resolved diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 3978f4caf72..28365388fb6 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -433,7 +433,7 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) if (!m48t59->ioaddr) { /* ioaddr not mapped externally */ - m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1); + m48t59->ioaddr = ioremap(res->start, resource_size(res)); if (!m48t59->ioaddr) goto out; } diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index 0cec5650d56..d33544802a2 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -332,9 +332,8 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) if (!iomem) return -ENODEV; - iomem = request_mem_region(iomem->start, - iomem->end + 1 - iomem->start, - driver_name); + iomem = request_mem_region(iomem->start, resource_size(iomem), + driver_name); if (!iomem) { dev_dbg(dev, "i/o mem already in use.\n"); return -EBUSY; diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 46f14b82f3a..b3eba3cddd4 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -267,9 +267,8 @@ static int puv3_rtc_probe(struct platform_device *pdev) return -ENOENT; } - puv3_rtc_mem = request_mem_region(res->start, - res->end-res->start+1, - pdev->name); + puv3_rtc_mem = request_mem_region(res->start, resource_size(res), + pdev->name); if (puv3_rtc_mem == NULL) { dev_err(&pdev->dev, "failed to reserve memory region\n"); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 16512ecae31..2a65e85e0f5 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -455,8 +455,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) return -ENOENT; } - s3c_rtc_mem = request_mem_region(res->start, - res->end-res->start+1, + s3c_rtc_mem = request_mem_region(res->start, resource_size(res), pdev->name); if (s3c_rtc_mem == NULL) { @@ -465,7 +464,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) goto err_nores; } - s3c_rtc_base = ioremap(res->start, res->end - res->start + 1); + s3c_rtc_base = ioremap(res->start, resource_size(res)); if (s3c_rtc_base == NULL) { dev_err(&pdev->dev, "failed ioremap()\n"); ret = -EINVAL; diff --git a/drivers/staging/generic_serial/ser_a2232.c b/drivers/staging/generic_serial/ser_a2232.c index 3f47c2ead8e..0c08e1c2558 100644 --- a/drivers/staging/generic_serial/ser_a2232.c +++ b/drivers/staging/generic_serial/ser_a2232.c @@ -746,7 +746,8 @@ static int __init a2232board_init(void) zd_a2232[nr_a2232] = z; boardaddr = ZTWO_VADDR( z->resource.start ); - printk("Board is located at address 0x%x, size is 0x%x.\n", boardaddr, (unsigned int) ((z->resource.end+1) - (z->resource.start))); + printk("Board is located at address 0x%x, size is 0x%x\n", + boardaddr, (unsigned int)resource_size(&z->resource)); mem = (volatile struct a2232memory *) boardaddr; diff --git a/drivers/staging/gma500/psb_gtt.c b/drivers/staging/gma500/psb_gtt.c index 74c5a6569d0..280f9d44546 100644 --- a/drivers/staging/gma500/psb_gtt.c +++ b/drivers/staging/gma500/psb_gtt.c @@ -80,7 +80,7 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r) { struct drm_psb_private *dev_priv = dev->dev_private; u32 *gtt_slot, pte; - int numpages = (r->resource.end + 1 - r->resource.start) >> PAGE_SHIFT; + int numpages = resource_size(&r->resource) >> PAGE_SHIFT; struct page **pages; int i; @@ -121,7 +121,7 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) { struct drm_psb_private *dev_priv = dev->dev_private; u32 *gtt_slot, pte; - int numpages = (r->resource.end + 1 - r->resource.start) >> PAGE_SHIFT; + int numpages = resource_size(&r->resource) >> PAGE_SHIFT; int i; WARN_ON(r->stolen); @@ -149,7 +149,7 @@ static int psb_gtt_attach_pages(struct gtt_range *gt) struct address_space *mapping; int i; struct page *p; - int pages = (gt->resource.end + 1 - gt->resource.start) >> PAGE_SHIFT; + int pages = resource_size(>->resource) >> PAGE_SHIFT; WARN_ON(gt->pages); @@ -191,7 +191,7 @@ err: static void psb_gtt_detach_pages(struct gtt_range *gt) { int i; - int pages = (gt->resource.end + 1 - gt->resource.start) >> PAGE_SHIFT; + int pages = resource_size(>->resource) >> PAGE_SHIFT; for (i = 0; i < pages; i++) { /* FIXME: do we need to force dirty */ diff --git a/drivers/tty/serial/bfin_5xx.c b/drivers/tty/serial/bfin_5xx.c index 9b1ff2b6bb3..ff6979181ac 100644 --- a/drivers/tty/serial/bfin_5xx.c +++ b/drivers/tty/serial/bfin_5xx.c @@ -1304,8 +1304,7 @@ static int bfin_serial_probe(struct platform_device *pdev) goto out_error_free_peripherals; } - uart->port.membase = ioremap(res->start, - res->end - res->start); + uart->port.membase = ioremap(res->start, resource_size(res)); if (!uart->port.membase) { dev_err(&pdev->dev, "Cannot map uart IO\n"); ret = -ENXIO; @@ -1483,7 +1482,7 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev) } bfin_earlyprintk_port.port.membase = ioremap(res->start, - res->end - res->start); + resource_size(res)); if (!bfin_earlyprintk_port.port.membase) { dev_err(&pdev->dev, "Cannot map uart IO\n"); ret = -ENXIO; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index a54473123e0..22fe801cce3 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -954,7 +954,7 @@ static void imx_release_port(struct uart_port *port) struct resource *mmres; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mmres->start, mmres->end - mmres->start + 1); + release_mem_region(mmres->start, resource_size(mmres)); } /* @@ -970,8 +970,7 @@ static int imx_request_port(struct uart_port *port) if (!mmres) return -ENODEV; - ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1, - "imx-uart"); + ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart"); return ret ? 0 : -EBUSY; } diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 84db7321cce..8e07517f8ac 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -892,7 +892,7 @@ static int m32r_sio_request_port(struct uart_port *port) * If we have a mapbase, then request that as well. */ if (ret == 0 && up->port.flags & UPF_IOREMAP) { - int size = res->end - res->start + 1; + int size = resource_size(res); up->port.membase = ioremap(up->port.mapbase, size); if (!up->port.membase) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 47cadf47414..c37df8d0fa2 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1241,8 +1241,8 @@ static int serial_omap_probe(struct platform_device *pdev) return -ENODEV; } - if (!request_mem_region(mem->start, (mem->end - mem->start) + 1, - pdev->dev.driver->name)) { + if (!request_mem_region(mem->start, resource_size(mem), + pdev->dev.driver->name)) { dev_err(&pdev->dev, "memory region already claimed\n"); return -EBUSY; } @@ -1308,7 +1308,7 @@ err: dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", pdev->id, __func__, ret); do_release_region: - release_mem_region(mem->start, (mem->end - mem->start) + 1); + release_mem_region(mem->start, resource_size(mem)); return ret; } diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 4302e6e3768..531931c1b25 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -803,7 +803,7 @@ static int serial_pxa_probe(struct platform_device *dev) break; } - sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1); + sport->port.membase = ioremap(mmres->start, resource_size(mmres)); if (!sport->port.membase) { ret = -ENOMEM; goto err_clk; diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 92aa54550e8..ad0f8f5f6ea 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1435,7 +1435,7 @@ static int __devinit su_probe(struct platform_device *op) rp = &op->resource[0]; up->port.mapbase = rp->start; - up->reg_size = (rp->end - rp->start) + 1; + up->reg_size = resource_size(rp); up->port.membase = of_ioremap(rp, 0, up->reg_size, "su"); if (!up->port.membase) { if (type != SU_PORT_PORT) diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 37fc4e3d487..026cb9ea5cd 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -573,8 +573,7 @@ static int __init vt8500_serial_probe(struct platform_device *pdev) snprintf(vt8500_port->name, sizeof(vt8500_port->name), "VT8500 UART%d", pdev->id); - vt8500_port->uart.membase = ioremap(mmres->start, - mmres->end - mmres->start + 1); + vt8500_port->uart.membase = ioremap(mmres->start, resource_size(mmres)); if (!vt8500_port->uart.membase) { ret = -ENOMEM; goto err; diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c index 7d3e469b990..bdc3db94612 100644 --- a/drivers/uio/uio_pdrv.c +++ b/drivers/uio/uio_pdrv.c @@ -58,7 +58,7 @@ static int uio_pdrv_probe(struct platform_device *pdev) uiomem->memtype = UIO_MEM_PHYS; uiomem->addr = r->start; - uiomem->size = r->end - r->start + 1; + uiomem->size = resource_size(r); ++uiomem; } diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 0f424af7f10..31e799d9efe 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -137,7 +137,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) uiomem->memtype = UIO_MEM_PHYS; uiomem->addr = r->start; - uiomem->size = r->end - r->start + 1; + uiomem->size = resource_size(r); ++uiomem; } diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index db1a659702b..f045c8968a6 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -272,7 +272,7 @@ static void usba_init_debugfs(struct usba_udc *udc) regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); - regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; + regs->d_inode->i_size = resource_size(regs_resource); udc->debugfs_regs = regs; usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 2cd9a60c7f3..9c8e56fd0ff 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2445,7 +2445,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) } if (pdata->operating_mode == FSL_USB2_DR_DEVICE) { - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), driver_name)) { ERR("request mem region for %s failed\n", pdev->name); ret = -EBUSY; @@ -2593,7 +2593,7 @@ err_iounmap_noclk: iounmap(dr_regs); err_release_mem_region: if (pdata->operating_mode == FSL_USB2_DR_DEVICE) - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); err_kfree: kfree(udc_controller); udc_controller = NULL; @@ -2628,7 +2628,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs); if (pdata->operating_mode == FSL_USB2_DR_DEVICE) - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); device_unregister(&udc_controller->gadget.dev); /* free udc --wait for the release() finished */ diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c index 98cc8a13169..eab3d7059fb 100644 --- a/drivers/usb/host/ehci-ath79.c +++ b/drivers/usb/host/ehci-ath79.c @@ -146,7 +146,7 @@ static int ehci_ath79_probe(struct platform_device *pdev) return -ENOMEM; hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_dbg(&pdev->dev, "controller already in use\n"); diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c index d41745c6f0c..6536abdea6e 100644 --- a/drivers/usb/host/ehci-cns3xxx.c +++ b/drivers/usb/host/ehci-cns3xxx.c @@ -107,7 +107,7 @@ static int cns3xxx_ehci_probe(struct platform_device *pdev) } hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index f380bf97e5a..34a3140d1e5 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -100,7 +100,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, goto err2; } hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { dev_dbg(&pdev->dev, "controller already in use\n"); diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index 93b230dc51a..fdfd8c5b639 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -130,7 +130,7 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op) return -ENOMEM; hcd->rsrc_start = res.start; - hcd->rsrc_len = res.end - res.start + 1; + hcd->rsrc_len = resource_size(&res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index 50e600d26e2..c4460f3d009 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -100,7 +100,7 @@ static int ixp4xx_ehci_probe(struct platform_device *pdev) goto fail_request_resource; } hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index ff55757ba7d..c3ba3ed5f3a 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -124,7 +124,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) return -ENOMEM; hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = res_mem->end - res_mem->start + 1; + hcd->rsrc_len = resource_size(res_mem); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, OCTEON_EHCI_HCD_NAME)) { diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index cd69099cda1..e8d54de44ac 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c @@ -124,7 +124,7 @@ static int usb_hcd_msp_map_regs(struct mspusb_device *dev) res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res == NULL) return -ENOMEM; - res_len = res->end - res->start + 1; + res_len = resource_size(res); if (!request_mem_region(res->start, res_len, "mab regs")) return -EBUSY; @@ -140,7 +140,7 @@ static int usb_hcd_msp_map_regs(struct mspusb_device *dev) retval = -ENOMEM; goto err2; } - res_len = res->end - res->start + 1; + res_len = resource_size(res); if (!request_mem_region(res->start, res_len, "usbid regs")) { retval = -EBUSY; goto err2; @@ -154,13 +154,13 @@ static int usb_hcd_msp_map_regs(struct mspusb_device *dev) return 0; err3: res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - res_len = res->end - res->start + 1; + res_len = resource_size(res); release_mem_region(res->start, res_len); err2: iounmap(dev->mab_regs); err1: res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - res_len = res->end - res->start + 1; + res_len = resource_size(res); release_mem_region(res->start, res_len); dev_err(&pdev->dev, "Failed to map non-EHCI regs.\n"); return retval; @@ -194,7 +194,7 @@ int usb_hcd_msp_probe(const struct hc_driver *driver, goto err1; } hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, dev->name)) { retval = -EBUSY; goto err1; diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 8552db6c29c..41d11fe1425 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -130,7 +130,7 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op) return -ENOMEM; hcd->rsrc_start = res.start; - hcd->rsrc_len = res.end - res.start + 1; + hcd->rsrc_len = resource_size(&res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index 52a027aaa37..d661cf7de14 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -41,7 +41,7 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver, } hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { retval = -EBUSY; diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index a64d6d66d76..32793ce3d9e 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -174,7 +174,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op) return -ENOMEM; hcd->rsrc_start = res.start; - hcd->rsrc_len = res.end - res.start + 1; + hcd->rsrc_len = resource_size(&res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 19223c7449e..572ea53b022 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -605,7 +605,7 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev) goto err_regs; } - hcd->regs = ioremap(usb_regs.start, usb_regs.end - usb_regs.start + 1); + hcd->regs = ioremap(usb_regs.start, resource_size(&usb_regs)); if (!hcd->regs) { dev_err(dev, "could not ioremap regs\n"); ret = -ENOMEM; diff --git a/drivers/usb/host/ohci-ath79.c b/drivers/usb/host/ohci-ath79.c index ffea3e7cb0a..c620c50f677 100644 --- a/drivers/usb/host/ohci-ath79.c +++ b/drivers/usb/host/ohci-ath79.c @@ -93,8 +93,8 @@ static int ohci_ath79_probe(struct platform_device *pdev) ret = -ENODEV; goto err_put_hcd; } - hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_dbg(&pdev->dev, "controller already in use\n"); diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c index f05ef87e934..5a00a1e1c6c 100644 --- a/drivers/usb/host/ohci-cns3xxx.c +++ b/drivers/usb/host/ohci-cns3xxx.c @@ -100,7 +100,7 @@ static int cns3xxx_ohci_probe(struct platform_device *pdev) goto err1; } hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index d22fb4d577b..6aca2c4453f 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -322,7 +322,7 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver, goto err2; } hcd->rsrc_start = mem->start; - hcd->rsrc_len = mem->end - mem->start + 1; + hcd->rsrc_len = resource_size(mem); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_dbg(&pdev->dev, "request_mem_region failed\n"); diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c index e4ddfaf8870..d8b45647d1d 100644 --- a/drivers/usb/host/ohci-octeon.c +++ b/drivers/usb/host/ohci-octeon.c @@ -135,7 +135,7 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev) return -ENOMEM; hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = res_mem->end - res_mem->start + 1; + hcd->rsrc_len = resource_size(res_mem); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, OCTEON_OHCI_HCD_NAME)) { diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 1ca1821320f..0c12f4e14dc 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -110,7 +110,7 @@ static int __devinit ohci_hcd_ppc_of_probe(struct platform_device *op) return -ENOMEM; hcd->rsrc_start = res.start; - hcd->rsrc_len = res.end - res.start + 1; + hcd->rsrc_len = resource_size(&res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 89e670e38c1..c0f595c4448 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -56,7 +56,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, if (!hcd) return -ENOMEM; hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { pr_debug("%s: request_mem_region failed\n", __FILE__); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index d8eb3bdafab..4204d9720d2 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -131,7 +131,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, if (!hcd) return -ENOMEM; hcd->rsrc_start = dev->res.start; - hcd->rsrc_len = dev->res.end - dev->res.start + 1; + hcd->rsrc_len = resource_size(&dev->res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dbg("request_mem_region failed"); diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 041d30f30c1..78918ca0da2 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -103,8 +103,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) goto err0; } - if (!request_mem_region(mem->start, mem->end - mem->start + 1, - pdev->name)) { + if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) { dev_err(dev, "request_mem_region failed\n"); retval = -EBUSY; goto err0; @@ -126,7 +125,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) if (!dma_declare_coherent_memory(dev, mem->start, mem->start - mem->parent->start, - (mem->end - mem->start) + 1, + resource_size(mem), DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE)) { dev_err(dev, "cannot declare coherent memory\n"); @@ -149,7 +148,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) } hcd->rsrc_start = res->start; - hcd->rsrc_len = res->end - res->start + 1; + hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) { dev_err(dev, "request_mem_region failed\n"); @@ -185,7 +184,7 @@ err3: err2: dma_release_declared_memory(dev); err1: - release_mem_region(mem->start, mem->end - mem->start + 1); + release_mem_region(mem->start, resource_size(mem)); err0: return retval; } @@ -201,7 +200,7 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) dma_release_declared_memory(&pdev->dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (mem) - release_mem_region(mem->start, mem->end - mem->start + 1); + release_mem_region(mem->start, resource_size(mem)); /* mask interrupts and disable power */ diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index 3558491dd87..57ad1271fc9 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -208,13 +208,13 @@ static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev) } hcd->rsrc_start = regs->start; - hcd->rsrc_len = regs->end - regs->start + 1; + hcd->rsrc_len = resource_size(regs); tmio = hcd_to_tmio(hcd); spin_lock_init(&tmio->lock); - tmio->ccr = ioremap(config->start, config->end - config->start + 1); + tmio->ccr = ioremap(config->start, resource_size(config)); if (!tmio->ccr) { ret = -ENOMEM; goto err_ioremap_ccr; @@ -228,7 +228,7 @@ static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev) if (!dma_declare_coherent_memory(&dev->dev, sram->start, sram->start, - sram->end - sram->start + 1, + resource_size(sram), DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE)) { ret = -EBUSY; goto err_dma_declare; diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 5fbe997dc6d..dcd889803f0 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3828,7 +3828,7 @@ static int oxu_drv_probe(struct platform_device *pdev) return -ENODEV; } memstart = res->start; - memlen = res->end - res->start + 1; + memlen = resource_size(res); dev_dbg(&pdev->dev, "MEM resource %lx-%lx\n", memstart, memlen); if (!request_mem_region(memstart, memlen, oxu_hc_driver.description)) { diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c index d01c1e22768..f7a62138e3e 100644 --- a/drivers/usb/host/uhci-grlib.c +++ b/drivers/usb/host/uhci-grlib.c @@ -111,7 +111,7 @@ static int __devinit uhci_hcd_grlib_probe(struct platform_device *op) return -ENOMEM; hcd->rsrc_start = res.start; - hcd->rsrc_len = res.end - res.start + 1; + hcd->rsrc_len = resource_size(&res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c index f7582e8e216..d3e13b640d4 100644 --- a/drivers/usb/host/whci/init.c +++ b/drivers/usb/host/whci/init.c @@ -178,7 +178,7 @@ void whc_clean_up(struct whc *whc) if (whc->qset_pool) dma_pool_destroy(whc->qset_pool); - len = whc->umc->resource.end - whc->umc->resource.start + 1; + len = resource_size(&whc->umc->resource); if (whc->base) iounmap(whc->base); if (whc->base_phys) diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c index 70a004aa19d..3ae3c702500 100644 --- a/drivers/uwb/whc-rc.c +++ b/drivers/uwb/whc-rc.c @@ -222,7 +222,7 @@ int whcrc_setup_rc_umc(struct whcrc *whcrc) struct umc_dev *umc_dev = whcrc->umc_dev; whcrc->area = umc_dev->resource.start; - whcrc->rc_len = umc_dev->resource.end - umc_dev->resource.start + 1; + whcrc->rc_len = resource_size(&umc_dev->resource); result = -EBUSY; if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) { dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n", diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 4484c721f0f..817ab60f753 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -906,7 +906,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) if (map) { /* use a pre-allocated memory buffer */ info->fix.smem_start = map->start; - info->fix.smem_len = map->end - map->start + 1; + info->fix.smem_len = resource_size(map); if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, pdev->name)) { ret = -EBUSY; @@ -932,7 +932,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) /* LCDC registers */ info->fix.mmio_start = regs->start; - info->fix.mmio_len = regs->end - regs->start + 1; + info->fix.mmio_len = resource_size(regs); if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len, pdev->name)) { diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index ebb893c49e9..ad41f508b42 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -3460,9 +3460,10 @@ static int __devinit atyfb_setup_generic(struct pci_dev *pdev, raddr = addr + 0x7ff000UL; rrp = &pdev->resource[2]; - if ((rrp->flags & IORESOURCE_MEM) && request_mem_region(rrp->start, rrp->end - rrp->start + 1, "atyfb")) { + if ((rrp->flags & IORESOURCE_MEM) && + request_mem_region(rrp->start, resource_size(rrp), "atyfb")) { par->aux_start = rrp->start; - par->aux_size = rrp->end - rrp->start + 1; + par->aux_size = resource_size(rrp); raddr = rrp->start; PRINTKI("using auxiliary register aperture\n"); } @@ -3552,7 +3553,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, /* Reserve space */ res_start = rp->start; - res_size = rp->end - rp->start + 1; + res_size = resource_size(rp); if (!request_mem_region(res_start, res_size, "atyfb")) return -EBUSY; diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 34b2fc472fe..01a8fde67f2 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -486,7 +486,7 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) } au1100fb_fix.mmio_start = regs_res->start; - au1100fb_fix.mmio_len = regs_res->end - regs_res->start + 1; + au1100fb_fix.mmio_len = resource_size(regs_res); if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len, DRIVER_NAME)) { diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c index 42fe155aba0..e02764319ff 100644 --- a/drivers/video/cobalt_lcdfb.c +++ b/drivers/video/cobalt_lcdfb.c @@ -303,7 +303,7 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev) return -EBUSY; } - info->screen_size = res->end - res->start + 1; + info->screen_size = resource_size(res); info->screen_base = ioremap(res->start, info->screen_size); info->fbops = &cobalt_lcd_fbops; info->fix = cobalt_lcdfb_fix; diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index c225dcce89e..9075bea5587 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -709,11 +709,11 @@ static int __init control_of_init(struct device_node *dp) /* Map in frame buffer and registers */ p->fb_orig_base = fb_res.start; - p->fb_orig_size = fb_res.end - fb_res.start + 1; + p->fb_orig_size = resource_size(&fb_res); /* use the big-endian aperture (??) */ p->frame_buffer_phys = fb_res.start + 0x800000; p->control_regs_phys = reg_res.start; - p->control_regs_size = reg_res.end - reg_res.start + 1; + p->control_regs_size = resource_size(®_res); if (!p->fb_orig_base || !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) { diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index f70bd63b018..ee1de3e26de 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -697,7 +697,7 @@ static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev) goto fbrel; } - res_size = 1 + res.end - res.start; + res_size = resource_size(&res); par->res = request_mem_region(res.start, res_size, DRV_NAME); if (par->res == NULL) { dev_err(dev, "Cannot claim framebuffer/mmio\n"); @@ -787,7 +787,7 @@ static int __devexit of_platform_mb862xx_remove(struct platform_device *ofdev) { struct fb_info *fbi = dev_get_drvdata(&ofdev->dev); struct mb862xxfb_par *par = fbi->par; - resource_size_t res_size = 1 + par->res->end - par->res->start; + resource_size_t res_size = resource_size(par->res); unsigned long reg; dev_dbg(fbi->dev, "%s release\n", fbi->fix.id); diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index c3636d55a3c..243d16f09b8 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -406,8 +406,7 @@ int mdp_probe(struct platform_device *pdev) goto error_get_irq; } - mdp->base = ioremap(resource->start, - resource->end - resource->start); + mdp->base = ioremap(resource->start, resource_size(resource)); if (mdp->base == 0) { printk(KERN_ERR "msmfb: cannot allocate mdp regs!\n"); ret = -ENOMEM; diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index ec351309e60..c6e3b4fcdd6 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -525,10 +525,9 @@ static int setup_fbmem(struct msmfb_info *msmfb, struct platform_device *pdev) return -ENOMEM; } fb->fix.smem_start = resource->start; - fb->fix.smem_len = resource->end - resource->start; - fbram = ioremap(resource->start, - resource->end - resource->start); - if (fbram == 0) { + fb->fix.smem_len = resource_size(resource); + fbram = ioremap(resource->start, resource_size(resource)); + if (fbram == NULL) { printk(KERN_ERR "msmfb: cannot allocate fbram!\n"); return -ENOMEM; } diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index f838d9e277f..0fff59782e4 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -551,7 +551,7 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - size = (res->end - res->start) + 1; + size = resource_size(res); fbi->mem = request_mem_region(res->start, size, pdev->name); if (fbi->mem == NULL) { dev_err(&pdev->dev, "failed to alloc memory region\n"); diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index ef532d9d3c9..f27ae16ead2 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -567,7 +567,7 @@ static int __devinit platinumfb_probe(struct platform_device* odev) * northbridge and that can fail. Only request framebuffer */ if (!request_mem_region(pinfo->rsrc_fb.start, - pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1, + resource_size(&pinfo->rsrc_fb), "platinumfb framebuffer")) { printk(KERN_ERR "platinumfb: Can't request framebuffer !\n"); framebuffer_release(info); @@ -658,8 +658,7 @@ static int __devexit platinumfb_remove(struct platform_device* odev) iounmap(pinfo->cmap_regs); release_mem_region(pinfo->rsrc_fb.start, - pinfo->rsrc_fb.end - - pinfo->rsrc_fb.start + 1); + resource_size(&pinfo->rsrc_fb)); release_mem_region(pinfo->cmap_regs_phys, 0x1000); diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index bb95ec56d25..18ead6f0184 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -662,7 +662,7 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev) info->fix.ypanstep = 0; info->fix.ywrapstep = 0; info->fix.mmio_start = res->start; - info->fix.mmio_len = res->end - res->start + 1; + info->fix.mmio_len = resource_size(res); info->fix.accel = FB_ACCEL_NONE; info->fbops = &pxa168fb_ops; info->pseudo_palette = fbi->pseudo_palette; diff --git a/include/linux/dio.h b/include/linux/dio.h index b2dd31ca171..2cc0fd00463 100644 --- a/include/linux/dio.h +++ b/include/linux/dio.h @@ -254,7 +254,7 @@ static inline struct dio_driver *dio_dev_driver(const struct dio_dev *d) #define dio_resource_start(d) ((d)->resource.start) #define dio_resource_end(d) ((d)->resource.end) -#define dio_resource_len(d) ((d)->resource.end-(d)->resource.start+1) +#define dio_resource_len(d) (resource_size(&(d)->resource)) #define dio_resource_flags(d) ((d)->resource.flags) #define dio_request_device(d, name) \ diff --git a/include/linux/pnp.h b/include/linux/pnp.h index 1bc1338b817..195aafc6cd0 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -50,7 +50,7 @@ static inline resource_size_t pnp_resource_len(struct resource *res) { if (res->start == 0 && res->end == 0) return 0; - return res->end - res->start + 1; + return resource_size(res); } diff --git a/include/linux/zorro.h b/include/linux/zorro.h index 7bf9db525e9..dff42025649 100644 --- a/include/linux/zorro.h +++ b/include/linux/zorro.h @@ -187,7 +187,7 @@ extern struct zorro_dev *zorro_find_device(zorro_id id, #define zorro_resource_start(z) ((z)->resource.start) #define zorro_resource_end(z) ((z)->resource.end) -#define zorro_resource_len(z) ((z)->resource.end-(z)->resource.start+1) +#define zorro_resource_len(z) (resource_size(&(z)->resource)) #define zorro_resource_flags(z) ((z)->resource.flags) #define zorro_request_device(z, name) \ diff --git a/kernel/kexec.c b/kernel/kexec.c index 8d814cbc810..296fbc84d65 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1095,7 +1095,7 @@ size_t crash_get_memory_size(void) size_t size = 0; mutex_lock(&kexec_mutex); if (crashk_res.end != crashk_res.start) - size = crashk_res.end - crashk_res.start + 1; + size = resource_size(&crashk_res); mutex_unlock(&kexec_mutex); return size; } diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 3ff8cc5f487..01065833588 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -262,8 +262,7 @@ static int i2sbus_add_dev(struct macio_dev *macio, */ dev->allocated_resource[i] = request_mem_region(dev->resources[i].start, - dev->resources[i].end - - dev->resources[i].start + 1, + resource_size(&dev->resources[i]), dev->rnames[i]); if (!dev->allocated_resource[i]) { printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i); @@ -272,19 +271,19 @@ static int i2sbus_add_dev(struct macio_dev *macio, } r = &dev->resources[aoa_resource_i2smmio]; - rlen = r->end - r->start + 1; + rlen = resource_size(r); if (rlen < sizeof(struct i2s_interface_regs)) goto err; dev->intfregs = ioremap(r->start, rlen); r = &dev->resources[aoa_resource_txdbdma]; - rlen = r->end - r->start + 1; + rlen = resource_size(r); if (rlen < sizeof(struct dbdma_regs)) goto err; dev->out.dbdma = ioremap(r->start, rlen); r = &dev->resources[aoa_resource_rxdbdma]; - rlen = r->end - r->start + 1; + rlen = resource_size(r); if (rlen < sizeof(struct dbdma_regs)) goto err; dev->in.dbdma = ioremap(r->start, rlen); diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index 6e240918189..30468b31cad 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -448,7 +448,7 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev) goto out_free_card; } - dac->regs = ioremap(regs->start, regs->end - regs->start + 1); + dac->regs = ioremap(regs->start, resource_size(regs)); if (!dac->regs) { dev_dbg(&pdev->dev, "could not remap register memory\n"); goto out_free_card; diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index b310702c646..41b901bde5c 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -971,7 +971,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) chip->card = card; chip->pclk = pclk; chip->pdev = pdev; - chip->regs = ioremap(regs->start, regs->end - regs->start + 1); + chip->regs = ioremap(regs->start, resource_size(regs)); if (!chip->regs) { dev_dbg(&pdev->dev, "could not remap register memory\n"); diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 3ecbd67f88c..ab96cde7417 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -881,8 +881,7 @@ static int snd_pmac_free(struct snd_pmac *chip) for (i = 0; i < 3; i++) { if (chip->requested & (1 << i)) release_mem_region(chip->rsrc[i].start, - chip->rsrc[i].end - - chip->rsrc[i].start + 1); + resource_size(&chip->rsrc[i])); } } @@ -1228,8 +1227,7 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) goto __error; } if (request_mem_region(chip->rsrc[i].start, - chip->rsrc[i].end - - chip->rsrc[i].start + 1, + resource_size(&chip->rsrc[i]), rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " " %d (%s: %pR)\n", @@ -1254,8 +1252,7 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) goto __error; } if (request_mem_region(chip->rsrc[i].start, - chip->rsrc[i].end - - chip->rsrc[i].start + 1, + resource_size(&chip->rsrc[i]), rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " " %d (%s: %pR)\n", diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 313e0ccedd5..6a882aa5553 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -678,7 +678,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) kfree(ssi_private); return ret; } - ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start); + ssi_private->ssi = ioremap(res.start, resource_size(&res)); ssi_private->ssi_phys = res.start; ssi_private->irq = irq_of_parse_and_map(np, 0); diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index fff695ccdd3..86023142a4c 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -384,7 +384,7 @@ static int mpc5200_hpcd_probe(struct of_device *op) dev_err(&op->dev, "Missing reg property\n"); return -ENODEV; } - regs = ioremap(res.start, 1 + res.end - res.start); + regs = ioremap(res.start, resource_size(&res)); if (!regs) { dev_err(&op->dev, "Could not map registers\n"); return -ENODEV; -- cgit v1.2.3-70-g09d2 From 83ae417b857072d54c3c111067046283e3ee6b58 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Wed, 22 Jun 2011 23:29:19 -0700 Subject: Input: libps2.c: fix comment typo arrrives. Fix a typo in a comment. Signed-off-by: Justin P. Mattock Signed-off-by: Jiri Kosina --- drivers/input/serio/libps2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 980af94ba9c..07a8363f3c5 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -210,7 +210,7 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) /* * Some devices (Synaptics) peform the reset before * ACKing the reset command, and so it can take a long - * time before the ACK arrrives. + * time before the ACK arrives. */ if (ps2_sendbyte(ps2dev, command & 0xff, command == PS2_CMD_RESET_BAT ? 1000 : 200)) -- cgit v1.2.3-70-g09d2 From 57fe7251f5bfc4332f24479376de48a1e8ca6211 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 31 May 2011 12:02:49 +0300 Subject: MFD: twl4030-codec -> twl4030-audio: Rename the driver Rename the driver, and header file from twl4030-codec to twl4030-audio. To avoid breakage change depending drivers at the same time. Signed-off-by: Peter Ujfalusi CC: Misael Lopez Cruz Acked-by: Samuel Ortiz --- drivers/input/misc/Kconfig | 2 +- drivers/input/misc/twl4030-vibra.c | 10 +- drivers/mfd/Kconfig | 2 +- drivers/mfd/Makefile | 2 +- drivers/mfd/twl4030-audio.c | 277 ++++++++++++++++++++++++++++++++++++ drivers/mfd/twl4030-codec.c | 278 ------------------------------------- include/linux/mfd/twl4030-audio.h | 272 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/twl4030-codec.h | 272 ------------------------------------ sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/twl4030.c | 16 +-- sound/soc/omap/sdp3430.c | 2 +- sound/soc/omap/zoom2.c | 2 +- 12 files changed, 568 insertions(+), 569 deletions(-) create mode 100644 drivers/mfd/twl4030-audio.c delete mode 100644 drivers/mfd/twl4030-codec.c create mode 100644 include/linux/mfd/twl4030-audio.h delete mode 100644 include/linux/mfd/twl4030-codec.h (limited to 'drivers/input') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 45dc6aa62ba..077309a29a2 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -267,7 +267,7 @@ config INPUT_TWL4030_PWRBUTTON config INPUT_TWL4030_VIBRA tristate "Support for TWL4030 Vibrator" depends on TWL4030_CORE - select TWL4030_CODEC + select MFD_TWL4030_AUDIO select INPUT_FF_MEMLESS help This option enables support for TWL4030 Vibrator Driver. diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 014dd4ad0d4..7abca85b5a7 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include @@ -67,7 +67,7 @@ static void vibra_enable(struct vibra_info *info) { u8 reg; - twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER); + twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER); /* turn H-Bridge on */ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, @@ -75,7 +75,7 @@ static void vibra_enable(struct vibra_info *info) twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, (reg | TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL); - twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL); + twl4030_audio_enable_resource(TWL4030_AUDIO_RES_APLL); info->enabled = true; } @@ -90,8 +90,8 @@ static void vibra_disable(struct vibra_info *info) twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL); - twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL); - twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER); + twl4030_audio_disable_resource(TWL4030_AUDIO_RES_APLL); + twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER); info->enabled = false; } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0f09c057e79..3a6f76aac00 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -218,7 +218,7 @@ config TWL4030_POWER and load scripts controlling which resources are switched off/on or reset when a sleep, wakeup or warm reset event occurs. -config TWL4030_CODEC +config MFD_TWL4030_AUDIO bool depends on TWL4030_CORE select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index efe3cc33ed9..4cf946537e3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o -obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o +obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c new file mode 100644 index 00000000000..5cdf8414679 --- /dev/null +++ b/drivers/mfd/twl4030-audio.c @@ -0,0 +1,277 @@ +/* + * MFD driver for twl4030 audio submodule, which contains an audio codec, and + * the vibra control. + * + * Author: Peter Ujfalusi + * + * Copyright: (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TWL4030_AUDIO_CELLS 2 + +static struct platform_device *twl4030_audio_dev; + +struct twl4030_audio_resource { + int request_count; + u8 reg; + u8 mask; +}; + +struct twl4030_audio { + unsigned int audio_mclk; + struct mutex mutex; + struct twl4030_audio_resource resource[TWL4030_AUDIO_RES_MAX]; + struct mfd_cell cells[TWL4030_AUDIO_CELLS]; +}; + +/* + * Modify the resource, the function returns the content of the register + * after the modification. + */ +static int twl4030_audio_set_resource(enum twl4030_audio_res id, int enable) +{ + struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); + u8 val; + + twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, + audio->resource[id].reg); + + if (enable) + val |= audio->resource[id].mask; + else + val &= ~audio->resource[id].mask; + + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, + val, audio->resource[id].reg); + + return val; +} + +static inline int twl4030_audio_get_resource(enum twl4030_audio_res id) +{ + struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); + u8 val; + + twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, + audio->resource[id].reg); + + return val; +} + +/* + * Enable the resource. + * The function returns with error or the content of the register + */ +int twl4030_audio_enable_resource(enum twl4030_audio_res id) +{ + struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); + int val; + + if (id >= TWL4030_AUDIO_RES_MAX) { + dev_err(&twl4030_audio_dev->dev, + "Invalid resource ID (%u)\n", id); + return -EINVAL; + } + + mutex_lock(&audio->mutex); + if (!audio->resource[id].request_count) + /* Resource was disabled, enable it */ + val = twl4030_audio_set_resource(id, 1); + else + val = twl4030_audio_get_resource(id); + + audio->resource[id].request_count++; + mutex_unlock(&audio->mutex); + + return val; +} +EXPORT_SYMBOL_GPL(twl4030_audio_enable_resource); + +/* + * Disable the resource. + * The function returns with error or the content of the register + */ +int twl4030_audio_disable_resource(unsigned id) +{ + struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); + int val; + + if (id >= TWL4030_AUDIO_RES_MAX) { + dev_err(&twl4030_audio_dev->dev, + "Invalid resource ID (%u)\n", id); + return -EINVAL; + } + + mutex_lock(&audio->mutex); + if (!audio->resource[id].request_count) { + dev_err(&twl4030_audio_dev->dev, + "Resource has been disabled already (%u)\n", id); + mutex_unlock(&audio->mutex); + return -EPERM; + } + audio->resource[id].request_count--; + + if (!audio->resource[id].request_count) + /* Resource can be disabled now */ + val = twl4030_audio_set_resource(id, 0); + else + val = twl4030_audio_get_resource(id); + + mutex_unlock(&audio->mutex); + + return val; +} +EXPORT_SYMBOL_GPL(twl4030_audio_disable_resource); + +unsigned int twl4030_audio_get_mclk(void) +{ + struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); + + return audio->audio_mclk; +} +EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); + +static int __devinit twl4030_audio_probe(struct platform_device *pdev) +{ + struct twl4030_audio *audio; + struct twl4030_codec_data *pdata = pdev->dev.platform_data; + struct mfd_cell *cell = NULL; + int ret, childs = 0; + u8 val; + + if (!pdata) { + dev_err(&pdev->dev, "Platform data is missing\n"); + return -EINVAL; + } + + /* Configure APLL_INFREQ and disable APLL if enabled */ + val = 0; + switch (pdata->audio_mclk) { + case 19200000: + val |= TWL4030_APLL_INFREQ_19200KHZ; + break; + case 26000000: + val |= TWL4030_APLL_INFREQ_26000KHZ; + break; + case 38400000: + val |= TWL4030_APLL_INFREQ_38400KHZ; + break; + default: + dev_err(&pdev->dev, "Invalid audio_mclk\n"); + return -EINVAL; + } + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, + val, TWL4030_REG_APLL_CTL); + + audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL); + if (!audio) + return -ENOMEM; + + platform_set_drvdata(pdev, audio); + + twl4030_audio_dev = pdev; + mutex_init(&audio->mutex); + audio->audio_mclk = pdata->audio_mclk; + + /* Codec power */ + audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE; + audio->resource[TWL4030_AUDIO_RES_POWER].mask = TWL4030_CODECPDZ; + + /* PLL */ + audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL; + audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN; + + if (pdata->audio) { + cell = &audio->cells[childs]; + cell->name = "twl4030-codec"; + cell->platform_data = pdata->audio; + cell->pdata_size = sizeof(*pdata->audio); + childs++; + } + if (pdata->vibra) { + cell = &audio->cells[childs]; + cell->name = "twl4030-vibra"; + cell->platform_data = pdata->vibra; + cell->pdata_size = sizeof(*pdata->vibra); + childs++; + } + + if (childs) + ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, + childs, NULL, 0); + else { + dev_err(&pdev->dev, "No platform data found for childs\n"); + ret = -ENODEV; + } + + if (!ret) + return 0; + + platform_set_drvdata(pdev, NULL); + kfree(audio); + twl4030_audio_dev = NULL; + return ret; +} + +static int __devexit twl4030_audio_remove(struct platform_device *pdev) +{ + struct twl4030_audio *audio = platform_get_drvdata(pdev); + + mfd_remove_devices(&pdev->dev); + platform_set_drvdata(pdev, NULL); + kfree(audio); + twl4030_audio_dev = NULL; + + return 0; +} + +MODULE_ALIAS("platform:twl4030-audio"); + +static struct platform_driver twl4030_audio_driver = { + .probe = twl4030_audio_probe, + .remove = __devexit_p(twl4030_audio_remove), + .driver = { + .owner = THIS_MODULE, + .name = "twl4030-audio", + }, +}; + +static int __devinit twl4030_audio_init(void) +{ + return platform_driver_register(&twl4030_audio_driver); +} +module_init(twl4030_audio_init); + +static void __devexit twl4030_audio_exit(void) +{ + platform_driver_unregister(&twl4030_audio_driver); +} +module_exit(twl4030_audio_exit); + +MODULE_AUTHOR("Peter Ujfalusi "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c deleted file mode 100644 index e1782b3f66a..00000000000 --- a/drivers/mfd/twl4030-codec.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * MFD driver for twl4030 audio submodule, which contains an audio codec, and - * the vibra control. - * - * Author: Peter Ujfalusi - * - * Copyright: (C) 2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TWL4030_AUDIO_CELLS 2 - -static struct platform_device *twl4030_audio_dev; - -struct twl4030_audio_resource { - int request_count; - u8 reg; - u8 mask; -}; - -struct twl4030_audio { - unsigned int audio_mclk; - struct mutex mutex; - struct twl4030_audio_resource resource[TWL4030_CODEC_RES_MAX]; - struct mfd_cell cells[TWL4030_AUDIO_CELLS]; -}; - -/* - * Modify the resource, the function returns the content of the register - * after the modification. - */ -static int twl4030_audio_set_resource(enum twl4030_codec_res id, int enable) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - u8 val; - - twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, - audio->resource[id].reg); - - if (enable) - val |= audio->resource[id].mask; - else - val &= ~audio->resource[id].mask; - - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - val, audio->resource[id].reg); - - return val; -} - -static inline int twl4030_audio_get_resource(enum twl4030_codec_res id) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - u8 val; - - twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, - audio->resource[id].reg); - - return val; -} - -/* - * Enable the resource. - * The function returns with error or the content of the register - */ -int twl4030_codec_enable_resource(enum twl4030_codec_res id) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - int val; - - if (id >= TWL4030_CODEC_RES_MAX) { - dev_err(&twl4030_audio_dev->dev, - "Invalid resource ID (%u)\n", id); - return -EINVAL; - } - - mutex_lock(&audio->mutex); - if (!audio->resource[id].request_count) - /* Resource was disabled, enable it */ - val = twl4030_audio_set_resource(id, 1); - else - val = twl4030_audio_get_resource(id); - - audio->resource[id].request_count++; - mutex_unlock(&audio->mutex); - - return val; -} -EXPORT_SYMBOL_GPL(twl4030_codec_enable_resource); - -/* - * Disable the resource. - * The function returns with error or the content of the register - */ -int twl4030_codec_disable_resource(unsigned id) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - int val; - - if (id >= TWL4030_CODEC_RES_MAX) { - dev_err(&twl4030_audio_dev->dev, - "Invalid resource ID (%u)\n", id); - return -EINVAL; - } - - mutex_lock(&audio->mutex); - if (!audio->resource[id].request_count) { - dev_err(&twl4030_audio_dev->dev, - "Resource has been disabled already (%u)\n", id); - mutex_unlock(&audio->mutex); - return -EPERM; - } - audio->resource[id].request_count--; - - if (!audio->resource[id].request_count) - /* Resource can be disabled now */ - val = twl4030_audio_set_resource(id, 0); - else - val = twl4030_audio_get_resource(id); - - mutex_unlock(&audio->mutex); - - return val; -} -EXPORT_SYMBOL_GPL(twl4030_codec_disable_resource); - -unsigned int twl4030_codec_get_mclk(void) -{ - struct twl4030_audio *audio = platform_get_drvdata(twl4030_audio_dev); - - return audio->audio_mclk; -} -EXPORT_SYMBOL_GPL(twl4030_codec_get_mclk); - -static int __devinit twl4030_audio_probe(struct platform_device *pdev) -{ - struct twl4030_audio *audio; - struct twl4030_codec_data *pdata = pdev->dev.platform_data; - struct mfd_cell *cell = NULL; - int ret, childs = 0; - u8 val; - - if (!pdata) { - dev_err(&pdev->dev, "Platform data is missing\n"); - return -EINVAL; - } - - /* Configure APLL_INFREQ and disable APLL if enabled */ - val = 0; - switch (pdata->audio_mclk) { - case 19200000: - val |= TWL4030_APLL_INFREQ_19200KHZ; - break; - case 26000000: - val |= TWL4030_APLL_INFREQ_26000KHZ; - break; - case 38400000: - val |= TWL4030_APLL_INFREQ_38400KHZ; - break; - default: - dev_err(&pdev->dev, "Invalid audio_mclk\n"); - return -EINVAL; - } - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - val, TWL4030_REG_APLL_CTL); - - audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL); - if (!audio) - return -ENOMEM; - - platform_set_drvdata(pdev, audio); - - twl4030_audio_dev = pdev; - mutex_init(&audio->mutex); - audio->audio_mclk = pdata->audio_mclk; - - /* Codec power */ - audio->resource[TWL4030_CODEC_RES_POWER].reg = TWL4030_REG_CODEC_MODE; - audio->resource[TWL4030_CODEC_RES_POWER].mask = TWL4030_CODECPDZ; - - /* PLL */ - audio->resource[TWL4030_CODEC_RES_APLL].reg = TWL4030_REG_APLL_CTL; - audio->resource[TWL4030_CODEC_RES_APLL].mask = TWL4030_APLL_EN; - - if (pdata->audio) { - cell = &audio->cells[childs]; - cell->name = "twl4030-codec"; - cell->platform_data = pdata->audio; - cell->pdata_size = sizeof(*pdata->audio); - childs++; - } - if (pdata->vibra) { - cell = &audio->cells[childs]; - cell->name = "twl4030-vibra"; - cell->platform_data = pdata->vibra; - cell->pdata_size = sizeof(*pdata->vibra); - childs++; - } - - if (childs) - ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, - childs, NULL, 0); - else { - dev_err(&pdev->dev, "No platform data found for childs\n"); - ret = -ENODEV; - } - - if (!ret) - return 0; - - platform_set_drvdata(pdev, NULL); - kfree(audio); - twl4030_audio_dev = NULL; - return ret; -} - -static int __devexit twl4030_audio_remove(struct platform_device *pdev) -{ - struct twl4030_audio *audio = platform_get_drvdata(pdev); - - mfd_remove_devices(&pdev->dev); - platform_set_drvdata(pdev, NULL); - kfree(audio); - twl4030_audio_dev = NULL; - - return 0; -} - -MODULE_ALIAS("platform:twl4030-audio"); - -static struct platform_driver twl4030_audio_driver = { - .probe = twl4030_audio_probe, - .remove = __devexit_p(twl4030_audio_remove), - .driver = { - .owner = THIS_MODULE, - .name = "twl4030-audio", - }, -}; - -static int __devinit twl4030_audio_init(void) -{ - return platform_driver_register(&twl4030_audio_driver); -} -module_init(twl4030_audio_init); - -static void __devexit twl4030_audio_exit(void) -{ - platform_driver_unregister(&twl4030_audio_driver); -} -module_exit(twl4030_audio_exit); - -MODULE_AUTHOR("Peter Ujfalusi "); -MODULE_LICENSE("GPL"); - diff --git a/include/linux/mfd/twl4030-audio.h b/include/linux/mfd/twl4030-audio.h new file mode 100644 index 00000000000..3d22b72df07 --- /dev/null +++ b/include/linux/mfd/twl4030-audio.h @@ -0,0 +1,272 @@ +/* + * MFD driver for twl4030 audio submodule + * + * Author: Peter Ujfalusi + * + * Copyright: (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __TWL4030_CODEC_H__ +#define __TWL4030_CODEC_H__ + +/* Codec registers */ +#define TWL4030_REG_CODEC_MODE 0x01 +#define TWL4030_REG_OPTION 0x02 +#define TWL4030_REG_UNKNOWN 0x03 +#define TWL4030_REG_MICBIAS_CTL 0x04 +#define TWL4030_REG_ANAMICL 0x05 +#define TWL4030_REG_ANAMICR 0x06 +#define TWL4030_REG_AVADC_CTL 0x07 +#define TWL4030_REG_ADCMICSEL 0x08 +#define TWL4030_REG_DIGMIXING 0x09 +#define TWL4030_REG_ATXL1PGA 0x0A +#define TWL4030_REG_ATXR1PGA 0x0B +#define TWL4030_REG_AVTXL2PGA 0x0C +#define TWL4030_REG_AVTXR2PGA 0x0D +#define TWL4030_REG_AUDIO_IF 0x0E +#define TWL4030_REG_VOICE_IF 0x0F +#define TWL4030_REG_ARXR1PGA 0x10 +#define TWL4030_REG_ARXL1PGA 0x11 +#define TWL4030_REG_ARXR2PGA 0x12 +#define TWL4030_REG_ARXL2PGA 0x13 +#define TWL4030_REG_VRXPGA 0x14 +#define TWL4030_REG_VSTPGA 0x15 +#define TWL4030_REG_VRX2ARXPGA 0x16 +#define TWL4030_REG_AVDAC_CTL 0x17 +#define TWL4030_REG_ARX2VTXPGA 0x18 +#define TWL4030_REG_ARXL1_APGA_CTL 0x19 +#define TWL4030_REG_ARXR1_APGA_CTL 0x1A +#define TWL4030_REG_ARXL2_APGA_CTL 0x1B +#define TWL4030_REG_ARXR2_APGA_CTL 0x1C +#define TWL4030_REG_ATX2ARXPGA 0x1D +#define TWL4030_REG_BT_IF 0x1E +#define TWL4030_REG_BTPGA 0x1F +#define TWL4030_REG_BTSTPGA 0x20 +#define TWL4030_REG_EAR_CTL 0x21 +#define TWL4030_REG_HS_SEL 0x22 +#define TWL4030_REG_HS_GAIN_SET 0x23 +#define TWL4030_REG_HS_POPN_SET 0x24 +#define TWL4030_REG_PREDL_CTL 0x25 +#define TWL4030_REG_PREDR_CTL 0x26 +#define TWL4030_REG_PRECKL_CTL 0x27 +#define TWL4030_REG_PRECKR_CTL 0x28 +#define TWL4030_REG_HFL_CTL 0x29 +#define TWL4030_REG_HFR_CTL 0x2A +#define TWL4030_REG_ALC_CTL 0x2B +#define TWL4030_REG_ALC_SET1 0x2C +#define TWL4030_REG_ALC_SET2 0x2D +#define TWL4030_REG_BOOST_CTL 0x2E +#define TWL4030_REG_SOFTVOL_CTL 0x2F +#define TWL4030_REG_DTMF_FREQSEL 0x30 +#define TWL4030_REG_DTMF_TONEXT1H 0x31 +#define TWL4030_REG_DTMF_TONEXT1L 0x32 +#define TWL4030_REG_DTMF_TONEXT2H 0x33 +#define TWL4030_REG_DTMF_TONEXT2L 0x34 +#define TWL4030_REG_DTMF_TONOFF 0x35 +#define TWL4030_REG_DTMF_WANONOFF 0x36 +#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37 +#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38 +#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39 +#define TWL4030_REG_APLL_CTL 0x3A +#define TWL4030_REG_DTMF_CTL 0x3B +#define TWL4030_REG_DTMF_PGA_CTL2 0x3C +#define TWL4030_REG_DTMF_PGA_CTL1 0x3D +#define TWL4030_REG_MISC_SET_1 0x3E +#define TWL4030_REG_PCMBTMUX 0x3F +#define TWL4030_REG_RX_PATH_SEL 0x43 +#define TWL4030_REG_VDL_APGA_CTL 0x44 +#define TWL4030_REG_VIBRA_CTL 0x45 +#define TWL4030_REG_VIBRA_SET 0x46 +#define TWL4030_REG_VIBRA_PWM_SET 0x47 +#define TWL4030_REG_ANAMIC_GAIN 0x48 +#define TWL4030_REG_MISC_SET_2 0x49 + +/* Bitfield Definitions */ + +/* TWL4030_CODEC_MODE (0x01) Fields */ +#define TWL4030_APLL_RATE 0xF0 +#define TWL4030_APLL_RATE_8000 0x00 +#define TWL4030_APLL_RATE_11025 0x10 +#define TWL4030_APLL_RATE_12000 0x20 +#define TWL4030_APLL_RATE_16000 0x40 +#define TWL4030_APLL_RATE_22050 0x50 +#define TWL4030_APLL_RATE_24000 0x60 +#define TWL4030_APLL_RATE_32000 0x80 +#define TWL4030_APLL_RATE_44100 0x90 +#define TWL4030_APLL_RATE_48000 0xA0 +#define TWL4030_APLL_RATE_96000 0xE0 +#define TWL4030_SEL_16K 0x08 +#define TWL4030_CODECPDZ 0x02 +#define TWL4030_OPT_MODE 0x01 +#define TWL4030_OPTION_1 (1 << 0) +#define TWL4030_OPTION_2 (0 << 0) + +/* TWL4030_OPTION (0x02) Fields */ +#define TWL4030_ATXL1_EN (1 << 0) +#define TWL4030_ATXR1_EN (1 << 1) +#define TWL4030_ATXL2_VTXL_EN (1 << 2) +#define TWL4030_ATXR2_VTXR_EN (1 << 3) +#define TWL4030_ARXL1_VRX_EN (1 << 4) +#define TWL4030_ARXR1_EN (1 << 5) +#define TWL4030_ARXL2_EN (1 << 6) +#define TWL4030_ARXR2_EN (1 << 7) + +/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ +#define TWL4030_MICBIAS2_CTL 0x40 +#define TWL4030_MICBIAS1_CTL 0x20 +#define TWL4030_HSMICBIAS_EN 0x04 +#define TWL4030_MICBIAS2_EN 0x02 +#define TWL4030_MICBIAS1_EN 0x01 + +/* ANAMICL (0x05) Fields */ +#define TWL4030_CNCL_OFFSET_START 0x80 +#define TWL4030_OFFSET_CNCL_SEL 0x60 +#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 +#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20 +#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40 +#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60 +#define TWL4030_MICAMPL_EN 0x10 +#define TWL4030_CKMIC_EN 0x08 +#define TWL4030_AUXL_EN 0x04 +#define TWL4030_HSMIC_EN 0x02 +#define TWL4030_MAINMIC_EN 0x01 + +/* ANAMICR (0x06) Fields */ +#define TWL4030_MICAMPR_EN 0x10 +#define TWL4030_AUXR_EN 0x04 +#define TWL4030_SUBMIC_EN 0x01 + +/* AVADC_CTL (0x07) Fields */ +#define TWL4030_ADCL_EN 0x08 +#define TWL4030_AVADC_CLK_PRIORITY 0x04 +#define TWL4030_ADCR_EN 0x02 + +/* TWL4030_REG_ADCMICSEL (0x08) Fields */ +#define TWL4030_DIGMIC1_EN 0x08 +#define TWL4030_TX2IN_SEL 0x04 +#define TWL4030_DIGMIC0_EN 0x02 +#define TWL4030_TX1IN_SEL 0x01 + +/* AUDIO_IF (0x0E) Fields */ +#define TWL4030_AIF_SLAVE_EN 0x80 +#define TWL4030_DATA_WIDTH 0x60 +#define TWL4030_DATA_WIDTH_16S_16W 0x00 +#define TWL4030_DATA_WIDTH_32S_16W 0x40 +#define TWL4030_DATA_WIDTH_32S_24W 0x60 +#define TWL4030_AIF_FORMAT 0x18 +#define TWL4030_AIF_FORMAT_CODEC 0x00 +#define TWL4030_AIF_FORMAT_LEFT 0x08 +#define TWL4030_AIF_FORMAT_RIGHT 0x10 +#define TWL4030_AIF_FORMAT_TDM 0x18 +#define TWL4030_AIF_TRI_EN 0x04 +#define TWL4030_CLK256FS_EN 0x02 +#define TWL4030_AIF_EN 0x01 + +/* VOICE_IF (0x0F) Fields */ +#define TWL4030_VIF_SLAVE_EN 0x80 +#define TWL4030_VIF_DIN_EN 0x40 +#define TWL4030_VIF_DOUT_EN 0x20 +#define TWL4030_VIF_SWAP 0x10 +#define TWL4030_VIF_FORMAT 0x08 +#define TWL4030_VIF_TRI_EN 0x04 +#define TWL4030_VIF_SUB_EN 0x02 +#define TWL4030_VIF_EN 0x01 + +/* EAR_CTL (0x21) */ +#define TWL4030_EAR_GAIN 0x30 + +/* HS_GAIN_SET (0x23) Fields */ +#define TWL4030_HSR_GAIN 0x0C +#define TWL4030_HSR_GAIN_PWR_DOWN 0x00 +#define TWL4030_HSR_GAIN_PLUS_6DB 0x04 +#define TWL4030_HSR_GAIN_0DB 0x08 +#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C +#define TWL4030_HSL_GAIN 0x03 +#define TWL4030_HSL_GAIN_PWR_DOWN 0x00 +#define TWL4030_HSL_GAIN_PLUS_6DB 0x01 +#define TWL4030_HSL_GAIN_0DB 0x02 +#define TWL4030_HSL_GAIN_MINUS_6DB 0x03 + +/* HS_POPN_SET (0x24) Fields */ +#define TWL4030_VMID_EN 0x40 +#define TWL4030_EXTMUTE 0x20 +#define TWL4030_RAMP_DELAY 0x1C +#define TWL4030_RAMP_DELAY_20MS 0x00 +#define TWL4030_RAMP_DELAY_40MS 0x04 +#define TWL4030_RAMP_DELAY_81MS 0x08 +#define TWL4030_RAMP_DELAY_161MS 0x0C +#define TWL4030_RAMP_DELAY_323MS 0x10 +#define TWL4030_RAMP_DELAY_645MS 0x14 +#define TWL4030_RAMP_DELAY_1291MS 0x18 +#define TWL4030_RAMP_DELAY_2581MS 0x1C +#define TWL4030_RAMP_EN 0x02 + +/* PREDL_CTL (0x25) */ +#define TWL4030_PREDL_GAIN 0x30 + +/* PREDR_CTL (0x26) */ +#define TWL4030_PREDR_GAIN 0x30 + +/* PRECKL_CTL (0x27) */ +#define TWL4030_PRECKL_GAIN 0x30 + +/* PRECKR_CTL (0x28) */ +#define TWL4030_PRECKR_GAIN 0x30 + +/* HFL_CTL (0x29, 0x2A) Fields */ +#define TWL4030_HF_CTL_HB_EN 0x04 +#define TWL4030_HF_CTL_LOOP_EN 0x08 +#define TWL4030_HF_CTL_RAMP_EN 0x10 +#define TWL4030_HF_CTL_REF_EN 0x20 + +/* APLL_CTL (0x3A) Fields */ +#define TWL4030_APLL_EN 0x10 +#define TWL4030_APLL_INFREQ 0x0F +#define TWL4030_APLL_INFREQ_19200KHZ 0x05 +#define TWL4030_APLL_INFREQ_26000KHZ 0x06 +#define TWL4030_APLL_INFREQ_38400KHZ 0x0F + +/* REG_MISC_SET_1 (0x3E) Fields */ +#define TWL4030_CLK64_EN 0x80 +#define TWL4030_SCRAMBLE_EN 0x40 +#define TWL4030_FMLOOP_EN 0x20 +#define TWL4030_SMOOTH_ANAVOL_EN 0x02 +#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 + +/* VIBRA_CTL (0x45) */ +#define TWL4030_VIBRA_EN 0x01 +#define TWL4030_VIBRA_DIR 0x02 +#define TWL4030_VIBRA_AUDIO_SEL_L1 (0x00 << 2) +#define TWL4030_VIBRA_AUDIO_SEL_R1 (0x01 << 2) +#define TWL4030_VIBRA_AUDIO_SEL_L2 (0x02 << 2) +#define TWL4030_VIBRA_AUDIO_SEL_R2 (0x03 << 2) +#define TWL4030_VIBRA_SEL 0x10 +#define TWL4030_VIBRA_DIR_SEL 0x20 + +/* TWL4030 codec resource IDs */ +enum twl4030_audio_res { + TWL4030_AUDIO_RES_POWER = 0, + TWL4030_AUDIO_RES_APLL, + TWL4030_AUDIO_RES_MAX, +}; + +int twl4030_audio_disable_resource(enum twl4030_audio_res id); +int twl4030_audio_enable_resource(enum twl4030_audio_res id); +unsigned int twl4030_audio_get_mclk(void); + +#endif /* End of __TWL4030_CODEC_H__ */ diff --git a/include/linux/mfd/twl4030-codec.h b/include/linux/mfd/twl4030-codec.h deleted file mode 100644 index 5cc16bbd1da..00000000000 --- a/include/linux/mfd/twl4030-codec.h +++ /dev/null @@ -1,272 +0,0 @@ -/* - * MFD driver for twl4030 codec submodule - * - * Author: Peter Ujfalusi - * - * Copyright: (C) 2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __TWL4030_CODEC_H__ -#define __TWL4030_CODEC_H__ - -/* Codec registers */ -#define TWL4030_REG_CODEC_MODE 0x01 -#define TWL4030_REG_OPTION 0x02 -#define TWL4030_REG_UNKNOWN 0x03 -#define TWL4030_REG_MICBIAS_CTL 0x04 -#define TWL4030_REG_ANAMICL 0x05 -#define TWL4030_REG_ANAMICR 0x06 -#define TWL4030_REG_AVADC_CTL 0x07 -#define TWL4030_REG_ADCMICSEL 0x08 -#define TWL4030_REG_DIGMIXING 0x09 -#define TWL4030_REG_ATXL1PGA 0x0A -#define TWL4030_REG_ATXR1PGA 0x0B -#define TWL4030_REG_AVTXL2PGA 0x0C -#define TWL4030_REG_AVTXR2PGA 0x0D -#define TWL4030_REG_AUDIO_IF 0x0E -#define TWL4030_REG_VOICE_IF 0x0F -#define TWL4030_REG_ARXR1PGA 0x10 -#define TWL4030_REG_ARXL1PGA 0x11 -#define TWL4030_REG_ARXR2PGA 0x12 -#define TWL4030_REG_ARXL2PGA 0x13 -#define TWL4030_REG_VRXPGA 0x14 -#define TWL4030_REG_VSTPGA 0x15 -#define TWL4030_REG_VRX2ARXPGA 0x16 -#define TWL4030_REG_AVDAC_CTL 0x17 -#define TWL4030_REG_ARX2VTXPGA 0x18 -#define TWL4030_REG_ARXL1_APGA_CTL 0x19 -#define TWL4030_REG_ARXR1_APGA_CTL 0x1A -#define TWL4030_REG_ARXL2_APGA_CTL 0x1B -#define TWL4030_REG_ARXR2_APGA_CTL 0x1C -#define TWL4030_REG_ATX2ARXPGA 0x1D -#define TWL4030_REG_BT_IF 0x1E -#define TWL4030_REG_BTPGA 0x1F -#define TWL4030_REG_BTSTPGA 0x20 -#define TWL4030_REG_EAR_CTL 0x21 -#define TWL4030_REG_HS_SEL 0x22 -#define TWL4030_REG_HS_GAIN_SET 0x23 -#define TWL4030_REG_HS_POPN_SET 0x24 -#define TWL4030_REG_PREDL_CTL 0x25 -#define TWL4030_REG_PREDR_CTL 0x26 -#define TWL4030_REG_PRECKL_CTL 0x27 -#define TWL4030_REG_PRECKR_CTL 0x28 -#define TWL4030_REG_HFL_CTL 0x29 -#define TWL4030_REG_HFR_CTL 0x2A -#define TWL4030_REG_ALC_CTL 0x2B -#define TWL4030_REG_ALC_SET1 0x2C -#define TWL4030_REG_ALC_SET2 0x2D -#define TWL4030_REG_BOOST_CTL 0x2E -#define TWL4030_REG_SOFTVOL_CTL 0x2F -#define TWL4030_REG_DTMF_FREQSEL 0x30 -#define TWL4030_REG_DTMF_TONEXT1H 0x31 -#define TWL4030_REG_DTMF_TONEXT1L 0x32 -#define TWL4030_REG_DTMF_TONEXT2H 0x33 -#define TWL4030_REG_DTMF_TONEXT2L 0x34 -#define TWL4030_REG_DTMF_TONOFF 0x35 -#define TWL4030_REG_DTMF_WANONOFF 0x36 -#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37 -#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38 -#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39 -#define TWL4030_REG_APLL_CTL 0x3A -#define TWL4030_REG_DTMF_CTL 0x3B -#define TWL4030_REG_DTMF_PGA_CTL2 0x3C -#define TWL4030_REG_DTMF_PGA_CTL1 0x3D -#define TWL4030_REG_MISC_SET_1 0x3E -#define TWL4030_REG_PCMBTMUX 0x3F -#define TWL4030_REG_RX_PATH_SEL 0x43 -#define TWL4030_REG_VDL_APGA_CTL 0x44 -#define TWL4030_REG_VIBRA_CTL 0x45 -#define TWL4030_REG_VIBRA_SET 0x46 -#define TWL4030_REG_VIBRA_PWM_SET 0x47 -#define TWL4030_REG_ANAMIC_GAIN 0x48 -#define TWL4030_REG_MISC_SET_2 0x49 - -/* Bitfield Definitions */ - -/* TWL4030_CODEC_MODE (0x01) Fields */ -#define TWL4030_APLL_RATE 0xF0 -#define TWL4030_APLL_RATE_8000 0x00 -#define TWL4030_APLL_RATE_11025 0x10 -#define TWL4030_APLL_RATE_12000 0x20 -#define TWL4030_APLL_RATE_16000 0x40 -#define TWL4030_APLL_RATE_22050 0x50 -#define TWL4030_APLL_RATE_24000 0x60 -#define TWL4030_APLL_RATE_32000 0x80 -#define TWL4030_APLL_RATE_44100 0x90 -#define TWL4030_APLL_RATE_48000 0xA0 -#define TWL4030_APLL_RATE_96000 0xE0 -#define TWL4030_SEL_16K 0x08 -#define TWL4030_CODECPDZ 0x02 -#define TWL4030_OPT_MODE 0x01 -#define TWL4030_OPTION_1 (1 << 0) -#define TWL4030_OPTION_2 (0 << 0) - -/* TWL4030_OPTION (0x02) Fields */ -#define TWL4030_ATXL1_EN (1 << 0) -#define TWL4030_ATXR1_EN (1 << 1) -#define TWL4030_ATXL2_VTXL_EN (1 << 2) -#define TWL4030_ATXR2_VTXR_EN (1 << 3) -#define TWL4030_ARXL1_VRX_EN (1 << 4) -#define TWL4030_ARXR1_EN (1 << 5) -#define TWL4030_ARXL2_EN (1 << 6) -#define TWL4030_ARXR2_EN (1 << 7) - -/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ -#define TWL4030_MICBIAS2_CTL 0x40 -#define TWL4030_MICBIAS1_CTL 0x20 -#define TWL4030_HSMICBIAS_EN 0x04 -#define TWL4030_MICBIAS2_EN 0x02 -#define TWL4030_MICBIAS1_EN 0x01 - -/* ANAMICL (0x05) Fields */ -#define TWL4030_CNCL_OFFSET_START 0x80 -#define TWL4030_OFFSET_CNCL_SEL 0x60 -#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 -#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20 -#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40 -#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60 -#define TWL4030_MICAMPL_EN 0x10 -#define TWL4030_CKMIC_EN 0x08 -#define TWL4030_AUXL_EN 0x04 -#define TWL4030_HSMIC_EN 0x02 -#define TWL4030_MAINMIC_EN 0x01 - -/* ANAMICR (0x06) Fields */ -#define TWL4030_MICAMPR_EN 0x10 -#define TWL4030_AUXR_EN 0x04 -#define TWL4030_SUBMIC_EN 0x01 - -/* AVADC_CTL (0x07) Fields */ -#define TWL4030_ADCL_EN 0x08 -#define TWL4030_AVADC_CLK_PRIORITY 0x04 -#define TWL4030_ADCR_EN 0x02 - -/* TWL4030_REG_ADCMICSEL (0x08) Fields */ -#define TWL4030_DIGMIC1_EN 0x08 -#define TWL4030_TX2IN_SEL 0x04 -#define TWL4030_DIGMIC0_EN 0x02 -#define TWL4030_TX1IN_SEL 0x01 - -/* AUDIO_IF (0x0E) Fields */ -#define TWL4030_AIF_SLAVE_EN 0x80 -#define TWL4030_DATA_WIDTH 0x60 -#define TWL4030_DATA_WIDTH_16S_16W 0x00 -#define TWL4030_DATA_WIDTH_32S_16W 0x40 -#define TWL4030_DATA_WIDTH_32S_24W 0x60 -#define TWL4030_AIF_FORMAT 0x18 -#define TWL4030_AIF_FORMAT_CODEC 0x00 -#define TWL4030_AIF_FORMAT_LEFT 0x08 -#define TWL4030_AIF_FORMAT_RIGHT 0x10 -#define TWL4030_AIF_FORMAT_TDM 0x18 -#define TWL4030_AIF_TRI_EN 0x04 -#define TWL4030_CLK256FS_EN 0x02 -#define TWL4030_AIF_EN 0x01 - -/* VOICE_IF (0x0F) Fields */ -#define TWL4030_VIF_SLAVE_EN 0x80 -#define TWL4030_VIF_DIN_EN 0x40 -#define TWL4030_VIF_DOUT_EN 0x20 -#define TWL4030_VIF_SWAP 0x10 -#define TWL4030_VIF_FORMAT 0x08 -#define TWL4030_VIF_TRI_EN 0x04 -#define TWL4030_VIF_SUB_EN 0x02 -#define TWL4030_VIF_EN 0x01 - -/* EAR_CTL (0x21) */ -#define TWL4030_EAR_GAIN 0x30 - -/* HS_GAIN_SET (0x23) Fields */ -#define TWL4030_HSR_GAIN 0x0C -#define TWL4030_HSR_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSR_GAIN_PLUS_6DB 0x04 -#define TWL4030_HSR_GAIN_0DB 0x08 -#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C -#define TWL4030_HSL_GAIN 0x03 -#define TWL4030_HSL_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSL_GAIN_PLUS_6DB 0x01 -#define TWL4030_HSL_GAIN_0DB 0x02 -#define TWL4030_HSL_GAIN_MINUS_6DB 0x03 - -/* HS_POPN_SET (0x24) Fields */ -#define TWL4030_VMID_EN 0x40 -#define TWL4030_EXTMUTE 0x20 -#define TWL4030_RAMP_DELAY 0x1C -#define TWL4030_RAMP_DELAY_20MS 0x00 -#define TWL4030_RAMP_DELAY_40MS 0x04 -#define TWL4030_RAMP_DELAY_81MS 0x08 -#define TWL4030_RAMP_DELAY_161MS 0x0C -#define TWL4030_RAMP_DELAY_323MS 0x10 -#define TWL4030_RAMP_DELAY_645MS 0x14 -#define TWL4030_RAMP_DELAY_1291MS 0x18 -#define TWL4030_RAMP_DELAY_2581MS 0x1C -#define TWL4030_RAMP_EN 0x02 - -/* PREDL_CTL (0x25) */ -#define TWL4030_PREDL_GAIN 0x30 - -/* PREDR_CTL (0x26) */ -#define TWL4030_PREDR_GAIN 0x30 - -/* PRECKL_CTL (0x27) */ -#define TWL4030_PRECKL_GAIN 0x30 - -/* PRECKR_CTL (0x28) */ -#define TWL4030_PRECKR_GAIN 0x30 - -/* HFL_CTL (0x29, 0x2A) Fields */ -#define TWL4030_HF_CTL_HB_EN 0x04 -#define TWL4030_HF_CTL_LOOP_EN 0x08 -#define TWL4030_HF_CTL_RAMP_EN 0x10 -#define TWL4030_HF_CTL_REF_EN 0x20 - -/* APLL_CTL (0x3A) Fields */ -#define TWL4030_APLL_EN 0x10 -#define TWL4030_APLL_INFREQ 0x0F -#define TWL4030_APLL_INFREQ_19200KHZ 0x05 -#define TWL4030_APLL_INFREQ_26000KHZ 0x06 -#define TWL4030_APLL_INFREQ_38400KHZ 0x0F - -/* REG_MISC_SET_1 (0x3E) Fields */ -#define TWL4030_CLK64_EN 0x80 -#define TWL4030_SCRAMBLE_EN 0x40 -#define TWL4030_FMLOOP_EN 0x20 -#define TWL4030_SMOOTH_ANAVOL_EN 0x02 -#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 - -/* VIBRA_CTL (0x45) */ -#define TWL4030_VIBRA_EN 0x01 -#define TWL4030_VIBRA_DIR 0x02 -#define TWL4030_VIBRA_AUDIO_SEL_L1 (0x00 << 2) -#define TWL4030_VIBRA_AUDIO_SEL_R1 (0x01 << 2) -#define TWL4030_VIBRA_AUDIO_SEL_L2 (0x02 << 2) -#define TWL4030_VIBRA_AUDIO_SEL_R2 (0x03 << 2) -#define TWL4030_VIBRA_SEL 0x10 -#define TWL4030_VIBRA_DIR_SEL 0x20 - -/* TWL4030 codec resource IDs */ -enum twl4030_codec_res { - TWL4030_CODEC_RES_POWER = 0, - TWL4030_CODEC_RES_APLL, - TWL4030_CODEC_RES_MAX, -}; - -int twl4030_codec_disable_resource(enum twl4030_codec_res id); -int twl4030_codec_enable_resource(enum twl4030_codec_res id); -unsigned int twl4030_codec_get_mclk(void); - -#endif /* End of __TWL4030_CODEC_H__ */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 98175a096df..0002220bbc3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -236,7 +236,7 @@ config SND_SOC_TLV320DAC33 tristate config SND_SOC_TWL4030 - select TWL4030_CODEC + select MFD_TWL4030_AUDIO tristate config SND_SOC_TWL6040 diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index bec788b1261..5e648d33d55 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -36,7 +36,7 @@ #include /* Register descriptions are here */ -#include +#include /* Shadow register used by the audio driver */ #define TWL4030_REG_SW_SHADOW 0x4A @@ -251,9 +251,9 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) return; if (enable) - mode = twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER); + mode = twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER); else - mode = twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER); + mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER); if (mode >= 0) { twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode); @@ -375,13 +375,13 @@ static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) if (enable) { twl4030->apll_enabled++; if (twl4030->apll_enabled == 1) - status = twl4030_codec_enable_resource( - TWL4030_CODEC_RES_APLL); + status = twl4030_audio_enable_resource( + TWL4030_AUDIO_RES_APLL); } else { twl4030->apll_enabled--; if (!twl4030->apll_enabled) - status = twl4030_codec_disable_resource( - TWL4030_CODEC_RES_APLL); + status = twl4030_audio_disable_resource( + TWL4030_AUDIO_RES_APLL); } if (status >= 0) @@ -2260,7 +2260,7 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec) } snd_soc_codec_set_drvdata(codec, twl4030); /* Set the defaults, and power up the codec */ - twl4030->sysclk = twl4030_codec_get_mclk() / 1000; + twl4030->sysclk = twl4030_audio_get_mclk() / 1000; codec->dapm.idle_bias_off = 1; twl4030_init_chip(codec); diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 3f72d17d1ef..9f6a758029d 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -36,7 +36,7 @@ #include /* Register descriptions for twl4030 codec part */ -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 01709940a43..9a2666ffc16 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -32,7 +32,7 @@ #include /* Register descriptions for twl4030 codec part */ -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" -- cgit v1.2.3-70-g09d2 From 4ae6df5e1018796ce260be59b2c603bd0f9faa94 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 31 May 2011 15:21:13 +0300 Subject: MFD: twl4030-audio: Rename platform data Allign the platform data names for twl4030 audio submodule: twl4030_audio_data: for the core MFD driver twl4030_codec_data: for ASoC codec driver twl4030_vibra_data: for the input/ForceFeedback driver To avoid breakage, change all depending drivers, files to use the new types. Signed-off-by: Peter Ujfalusi Acked-by: Samuel Ortiz --- arch/arm/mach-omap2/board-rx51-peripherals.c | 6 +++--- arch/arm/mach-omap2/board-zoom-peripherals.c | 10 +++++----- arch/arm/mach-omap2/twl-common.c | 10 +++++----- drivers/input/misc/twl4030-vibra.c | 2 +- drivers/mfd/twl-core.c | 8 ++++---- drivers/mfd/twl4030-audio.c | 8 ++++---- include/linux/i2c/twl.h | 12 ++++++------ sound/soc/codecs/twl4030.c | 6 +++--- sound/soc/codecs/twl6040.c | 2 +- 9 files changed, 32 insertions(+), 32 deletions(-) (limited to 'drivers/input') diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 6140290721a..f52bc61f35a 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -741,11 +741,11 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = { .resource_config = twl4030_rconfig, }; -struct twl4030_codec_vibra_data rx51_vibra_data __initdata = { +struct twl4030_vibra_data rx51_vibra_data __initdata = { .coexist = 0, }; -struct twl4030_codec_data rx51_codec_data __initdata = { +struct twl4030_audio_data rx51_audio_data __initdata = { .audio_mclk = 26000000, .vibra = &rx51_vibra_data, }; @@ -755,7 +755,7 @@ static struct twl4030_platform_data rx51_twldata __initdata = { .gpio = &rx51_gpio_data, .keypad = &rx51_kp_data, .power = &rx51_t2scripts_data, - .codec = &rx51_codec_data, + .audio = &rx51_audio_data, .vaux1 = &rx51_vaux1, .vaux2 = &rx51_vaux2, diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 13a64423366..6d0aa4fcb7c 100644 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -274,12 +274,12 @@ static int __init omap_i2c_init(void) TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); if (machine_is_omap_zoom2()) { - struct twl4030_codec_audio_data *audio_data; - audio_data = zoom_twldata.codec->audio; + struct twl4030_codec_data *codec_data; + codec_data = zoom_twldata.audio->codec; - audio_data->ramp_delay_value = 3; /* 161 ms */ - audio_data->hs_extmute = 1; - audio_data->set_hs_extmute = zoom2_set_hs_extmute; + codec_data->ramp_delay_value = 3; /* 161 ms */ + codec_data->hs_extmute = 1; + codec_data->set_hs_extmute = zoom2_set_hs_extmute; } omap_pmic_init(1, 2400, "twl5030", INT_34XX_SYS_NIRQ, &zoom_twldata); omap_register_i2c_bus(2, 400, NULL, 0); diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 3aaa46f6cd1..2543342dbcc 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -80,11 +80,11 @@ static struct twl4030_madc_platform_data omap3_madc_pdata = { .irq_line = 1, }; -static struct twl4030_codec_audio_data omap3_audio; +static struct twl4030_codec_data omap3_codec; -static struct twl4030_codec_data omap3_codec_pdata = { +static struct twl4030_audio_data omap3_audio_pdata = { .audio_mclk = 26000000, - .audio = &omap3_audio, + .codec = &omap3_codec, }; static struct regulator_consumer_supply omap3_vdda_dac_supplies[] = { @@ -292,8 +292,8 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data, if (pdata_flags & TWL_COMMON_PDATA_MADC && !pmic_data->madc) pmic_data->madc = &omap3_madc_pdata; - if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->codec) - pmic_data->codec = &omap3_codec_pdata; + if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->audio) + pmic_data->audio = &omap3_audio_pdata; /* Common regulator configurations */ if (regulators_flags & TWL_COMMON_REGULATOR_VDAC && !pmic_data->vdac) diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 7abca85b5a7..3c1a432c14d 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -196,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, static int __devinit twl4030_vibra_probe(struct platform_device *pdev) { - struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data; + struct twl4030_vibra_data *pdata = pdev->dev.platform_data; struct vibra_info *info; int ret; diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index b8f2a4e7f6e..f9d7880fd63 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -815,20 +815,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) return PTR_ERR(child); } - if (twl_has_codec() && pdata->codec && twl_class_is_4030()) { + if (twl_has_codec() && pdata->audio && twl_class_is_4030()) { sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; child = add_child(sub_chip_id, "twl4030-audio", - pdata->codec, sizeof(*pdata->codec), + pdata->audio, sizeof(*pdata->audio), false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } /* Phoenix codec driver is probed directly atm */ - if (twl_has_codec() && pdata->codec && twl_class_is_6030()) { + if (twl_has_codec() && pdata->audio && twl_class_is_6030()) { sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; child = add_child(sub_chip_id, "twl6040-codec", - pdata->codec, sizeof(*pdata->codec), + pdata->audio, sizeof(*pdata->audio), false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 5cdf8414679..ae51ab5d0e5 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -159,7 +159,7 @@ EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); static int __devinit twl4030_audio_probe(struct platform_device *pdev) { struct twl4030_audio *audio; - struct twl4030_codec_data *pdata = pdev->dev.platform_data; + struct twl4030_audio_data *pdata = pdev->dev.platform_data; struct mfd_cell *cell = NULL; int ret, childs = 0; u8 val; @@ -206,11 +206,11 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL; audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN; - if (pdata->audio) { + if (pdata->codec) { cell = &audio->cells[childs]; cell->name = "twl4030-codec"; - cell->platform_data = pdata->audio; - cell->pdata_size = sizeof(*pdata->audio); + cell->platform_data = pdata->codec; + cell->pdata_size = sizeof(*pdata->codec); childs++; } if (pdata->vibra) { diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index ba4f88624fc..e0aba2b92fa 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -657,7 +657,7 @@ struct twl4030_power_data { extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts); extern int twl4030_remove_script(u8 flags); -struct twl4030_codec_audio_data { +struct twl4030_codec_data { unsigned int digimic_delay; /* in ms */ unsigned int ramp_delay_value; unsigned int offset_cncl_path; @@ -667,14 +667,14 @@ struct twl4030_codec_audio_data { void (*set_hs_extmute)(int mute); }; -struct twl4030_codec_vibra_data { +struct twl4030_vibra_data { unsigned int coexist; }; -struct twl4030_codec_data { +struct twl4030_audio_data { unsigned int audio_mclk; - struct twl4030_codec_audio_data *audio; - struct twl4030_codec_vibra_data *vibra; + struct twl4030_codec_data *codec; + struct twl4030_vibra_data *vibra; /* twl6040 */ int audpwron_gpio; /* audio power-on gpio */ @@ -690,7 +690,7 @@ struct twl4030_platform_data { struct twl4030_keypad_data *keypad; struct twl4030_usb_data *usb; struct twl4030_power_data *power; - struct twl4030_codec_data *codec; + struct twl4030_audio_data *audio; /* Common LDO regulators for TWL4030/TWL6030 */ struct regulator_init_data *vdac; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 5e648d33d55..71674bec960 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -297,7 +297,7 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec) static void twl4030_init_chip(struct snd_soc_codec *codec) { - struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev); + struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev); struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); u8 reg, byte; int i = 0; @@ -732,7 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w, static void headset_ramp(struct snd_soc_codec *codec, int ramp) { - struct twl4030_codec_audio_data *pdata = codec->dev->platform_data; + struct twl4030_codec_data *pdata = codec->dev->platform_data; unsigned char hs_gain, hs_pop; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); /* Base values for ramp delay calculation: 2^19 - 2^26 */ @@ -2297,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { static int __devinit twl4030_codec_probe(struct platform_device *pdev) { - struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data; + struct twl4030_codec_data *pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "platform_data is missing\n"); diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 4c336636d4f..ade6616bb79 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1600,7 +1600,7 @@ static int twl6040_resume(struct snd_soc_codec *codec) static int twl6040_probe(struct snd_soc_codec *codec) { - struct twl4030_codec_data *twl_codec = codec->dev->platform_data; + struct twl4030_audio_data *twl_codec = codec->dev->platform_data; struct twl6040_data *priv; int audpwron, naudint; int ret = 0; -- cgit v1.2.3-70-g09d2 From cc697d38392c92b7504e7719c65ae905f0a0618a Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Sun, 1 May 2011 03:51:24 -0500 Subject: input: Add initial support for TWL6040 vibrator Add twl6040_vibra as a child of MFD device twl6040_codec. This implementation covers the PCM-to-PWM mode of TWL6040 vibrator module. Signed-off-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi CC: Tejun Heo Acked-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 11 + drivers/input/misc/Makefile | 1 + drivers/input/misc/twl6040-vibra.c | 416 +++++++++++++++++++++++++++++++++++++ include/linux/i2c/twl.h | 8 + 4 files changed, 436 insertions(+) create mode 100644 drivers/input/misc/twl6040-vibra.c (limited to 'drivers/input') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 077309a29a2..d1bf8724b58 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -275,6 +275,17 @@ config INPUT_TWL4030_VIBRA To compile this driver as a module, choose M here. The module will be called twl4030_vibra. +config INPUT_TWL6040_VIBRA + tristate "Support for TWL6040 Vibrator" + depends on TWL4030_CORE + select TWL6040_CORE + select INPUT_FF_MEMLESS + help + This option enables support for TWL6040 Vibrator Driver. + + To compile this driver as a module, choose M here. The module will + be called twl6040_vibra. + config INPUT_UINPUT tristate "User level driver support" help diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 38efb2cb182..4da7c3a60e0 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o +obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c new file mode 100644 index 00000000000..dbf745ddfe5 --- /dev/null +++ b/drivers/input/misc/twl6040-vibra.c @@ -0,0 +1,416 @@ +/* + * twl6040-vibra.c - TWL6040 Vibrator driver + * + * Author: Jorge Eduardo Candelaria + * Author: Misael Lopez Cruz + * + * Copyright: (C) 2011 Texas Instruments, Inc. + * + * Based on twl4030-vibra.c by Henrik Saari + * Felipe Balbi + * Jari Vanhala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFFECT_DIR_180_DEG 0x8000 + +/* Recommended modulation index 85% */ +#define TWL6040_VIBRA_MOD 85 + +#define TWL6040_NUM_SUPPLIES 2 + +struct vibra_info { + struct device *dev; + struct input_dev *input_dev; + struct workqueue_struct *workqueue; + struct work_struct play_work; + struct mutex mutex; + + bool enabled; + int weak_speed; + int strong_speed; + int direction; + + unsigned int vibldrv_res; + unsigned int vibrdrv_res; + unsigned int viblmotor_res; + unsigned int vibrmotor_res; + + struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES]; + + struct twl6040 *twl6040; +}; + +static irqreturn_t twl6040_vib_irq_handler(int irq, void *data) +{ + struct vibra_info *info = data; + struct twl6040 *twl6040 = info->twl6040; + u8 status; + + status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS); + if (status & TWL6040_VIBLOCDET) { + dev_warn(info->dev, "Left Vibrator overcurrent detected\n"); + twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, + TWL6040_VIBENAL); + } + if (status & TWL6040_VIBROCDET) { + dev_warn(info->dev, "Right Vibrator overcurrent detected\n"); + twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, + TWL6040_VIBENAR); + } + + return IRQ_HANDLED; +} + +static void twl6040_vibra_enable(struct vibra_info *info) +{ + struct twl6040 *twl6040 = info->twl6040; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies); + if (ret) { + dev_err(info->dev, "failed to enable regulators %d\n", ret); + return; + } + + twl6040_power(info->twl6040, 1); + if (twl6040->rev <= TWL6040_REV_ES1_1) { + /* + * ERRATA: Disable overcurrent protection for at least + * 3ms when enabling vibrator drivers to avoid false + * overcurrent detection + */ + twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, + TWL6040_VIBENAL | TWL6040_VIBCTRLL); + twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, + TWL6040_VIBENAR | TWL6040_VIBCTRLR); + usleep_range(3000, 3500); + } + + twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, + TWL6040_VIBENAL); + twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, + TWL6040_VIBENAR); + + info->enabled = true; +} + +static void twl6040_vibra_disable(struct vibra_info *info) +{ + struct twl6040 *twl6040 = info->twl6040; + + twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00); + twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00); + twl6040_power(info->twl6040, 0); + + regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies); + + info->enabled = false; +} + +static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res, + int speed, int direction) +{ + int vpk, max_code; + u8 vibdat; + + /* output swing */ + vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) / + (100 * (vibdrv_res + motor_res)); + + /* 50mV per VIBDAT code step */ + max_code = vpk / 50; + if (max_code > TWL6040_VIBDAT_MAX) + max_code = TWL6040_VIBDAT_MAX; + + /* scale speed to max allowed code */ + vibdat = (u8)((speed * max_code) / USHRT_MAX); + + /* 2's complement for direction > 180 degrees */ + vibdat *= direction; + + return vibdat; +} + +static void twl6040_vibra_set_effect(struct vibra_info *info) +{ + struct twl6040 *twl6040 = info->twl6040; + u8 vibdatl, vibdatr; + int volt; + + /* weak motor */ + volt = regulator_get_voltage(info->supplies[0].consumer) / 1000; + vibdatl = twl6040_vibra_code(volt, info->vibldrv_res, + info->viblmotor_res, + info->weak_speed, info->direction); + + /* strong motor */ + volt = regulator_get_voltage(info->supplies[1].consumer) / 1000; + vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res, + info->vibrmotor_res, + info->strong_speed, info->direction); + + twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl); + twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr); +} + +static void vibra_play_work(struct work_struct *work) +{ + struct vibra_info *info = container_of(work, + struct vibra_info, play_work); + + mutex_lock(&info->mutex); + + if (info->weak_speed || info->strong_speed) { + if (!info->enabled) + twl6040_vibra_enable(info); + + twl6040_vibra_set_effect(info); + } else if (info->enabled) + twl6040_vibra_disable(info); + + mutex_unlock(&info->mutex); +} + +static int vibra_play(struct input_dev *input, void *data, + struct ff_effect *effect) +{ + struct vibra_info *info = input_get_drvdata(input); + int ret; + + info->weak_speed = effect->u.rumble.weak_magnitude; + info->strong_speed = effect->u.rumble.strong_magnitude; + info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1; + + ret = queue_work(info->workqueue, &info->play_work); + if (!ret) { + dev_info(&input->dev, "work is already on queue\n"); + return ret; + } + + return 0; +} + +static void twl6040_vibra_close(struct input_dev *input) +{ + struct vibra_info *info = input_get_drvdata(input); + + cancel_work_sync(&info->play_work); + + mutex_lock(&info->mutex); + + if (info->enabled) + twl6040_vibra_disable(info); + + mutex_unlock(&info->mutex); +} + +#if CONFIG_PM_SLEEP +static int twl6040_vibra_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vibra_info *info = platform_get_drvdata(pdev); + + mutex_lock(&info->mutex); + + if (info->enabled) + twl6040_vibra_disable(info); + + mutex_unlock(&info->mutex); + + return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL); + +static int __devinit twl6040_vibra_probe(struct platform_device *pdev) +{ + struct twl4030_vibra_data *pdata = pdev->dev.platform_data; + struct vibra_info *info; + int ret; + + if (!pdata) { + dev_err(&pdev->dev, "platform_data not available\n"); + return -EINVAL; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(&pdev->dev, "couldn't allocate memory\n"); + return -ENOMEM; + } + + info->dev = &pdev->dev; + info->twl6040 = dev_get_drvdata(pdev->dev.parent); + info->vibldrv_res = pdata->vibldrv_res; + info->vibrdrv_res = pdata->vibrdrv_res; + info->viblmotor_res = pdata->viblmotor_res; + info->vibrmotor_res = pdata->vibrmotor_res; + if ((!info->vibldrv_res && !info->viblmotor_res) || + (!info->vibrdrv_res && !info->vibrmotor_res)) { + dev_err(info->dev, "invalid vibra driver/motor resistance\n"); + ret = -EINVAL; + goto err_kzalloc; + } + + mutex_init(&info->mutex); + + info->input_dev = input_allocate_device(); + if (info->input_dev == NULL) { + dev_err(info->dev, "couldn't allocate input device\n"); + ret = -ENOMEM; + goto err_kzalloc; + } + + input_set_drvdata(info->input_dev, info); + + info->input_dev->name = "twl6040:vibrator"; + info->input_dev->id.version = 1; + info->input_dev->dev.parent = pdev->dev.parent; + info->input_dev->close = twl6040_vibra_close; + __set_bit(FF_RUMBLE, info->input_dev->ffbit); + + ret = input_ff_create_memless(info->input_dev, NULL, vibra_play); + if (ret < 0) { + dev_err(info->dev, "couldn't register vibrator to FF\n"); + goto err_ialloc; + } + + ret = input_register_device(info->input_dev); + if (ret < 0) { + dev_err(info->dev, "couldn't register input device\n"); + goto err_iff; + } + + platform_set_drvdata(pdev, info); + + ret = twl6040_request_irq(info->twl6040, TWL6040_IRQ_VIB, + twl6040_vib_irq_handler, 0, + "twl6040_irq_vib", info); + if (ret) { + dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); + goto err_irq; + } + + info->supplies[0].supply = "vddvibl"; + info->supplies[1].supply = "vddvibr"; + ret = regulator_bulk_get(info->dev, ARRAY_SIZE(info->supplies), + info->supplies); + if (ret) { + dev_err(info->dev, "couldn't get regulators %d\n", ret); + goto err_regulator; + } + + if (pdata->vddvibl_uV) { + ret = regulator_set_voltage(info->supplies[0].consumer, + pdata->vddvibl_uV, + pdata->vddvibl_uV); + if (ret) { + dev_err(info->dev, "failed to set VDDVIBL volt %d\n", + ret); + goto err_voltage; + } + } + + if (pdata->vddvibr_uV) { + ret = regulator_set_voltage(info->supplies[1].consumer, + pdata->vddvibr_uV, + pdata->vddvibr_uV); + if (ret) { + dev_err(info->dev, "failed to set VDDVIBR volt %d\n", + ret); + goto err_voltage; + } + } + + info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0); + if (info->workqueue == NULL) { + dev_err(info->dev, "couldn't create workqueue\n"); + ret = -ENOMEM; + goto err_voltage; + } + INIT_WORK(&info->play_work, vibra_play_work); + + return 0; + +err_voltage: + regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); +err_regulator: + twl6040_free_irq(info->twl6040, TWL6040_IRQ_VIB, info); +err_irq: + input_unregister_device(info->input_dev); + info->input_dev = NULL; +err_iff: + if (info->input_dev) + input_ff_destroy(info->input_dev); +err_ialloc: + input_free_device(info->input_dev); +err_kzalloc: + kfree(info); + return ret; +} + +static int __devexit twl6040_vibra_remove(struct platform_device *pdev) +{ + struct vibra_info *info = platform_get_drvdata(pdev); + + input_unregister_device(info->input_dev); + twl6040_free_irq(info->twl6040, TWL6040_IRQ_VIB, info); + regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); + destroy_workqueue(info->workqueue); + kfree(info); + + return 0; +} + +static struct platform_driver twl6040_vibra_driver = { + .probe = twl6040_vibra_probe, + .remove = __devexit_p(twl6040_vibra_remove), + .driver = { + .name = "twl6040-vibra", + .owner = THIS_MODULE, + .pm = &twl6040_vibra_pm_ops, + }, +}; + +static int __init twl6040_vibra_init(void) +{ + return platform_driver_register(&twl6040_vibra_driver); +} +module_init(twl6040_vibra_init); + +static void __exit twl6040_vibra_exit(void) +{ + platform_driver_unregister(&twl6040_vibra_driver); +} +module_exit(twl6040_vibra_exit); + +MODULE_ALIAS("platform:twl6040-vibra"); +MODULE_DESCRIPTION("TWL6040 Vibra driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jorge Eduardo Candelaria "); +MODULE_AUTHOR("Misael Lopez Cruz "); diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index ea5baa26922..685fd767c69 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -669,6 +669,14 @@ struct twl4030_codec_data { struct twl4030_vibra_data { unsigned int coexist; + + /* twl6040 */ + unsigned int vibldrv_res; /* left driver resistance */ + unsigned int vibrdrv_res; /* right driver resistance */ + unsigned int viblmotor_res; /* left motor resistance */ + unsigned int vibrmotor_res; /* right motor resistance */ + int vddvibl_uV; /* VDDVIBL volt, set 0 for fixed reg */ + int vddvibr_uV; /* VDDVIBR volt, set 0 for fixed reg */ }; struct twl4030_audio_data { -- cgit v1.2.3-70-g09d2 From 1d08382a0e8a272fed9517a1b39ae6be634a77d5 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 8 Jun 2011 11:03:23 +0200 Subject: input: pmic8xxx-keypad: Do not use mfd_get_data() mfd_get_data() has been removed from the MFD API. Cc: Anirudh Ghayal Signed-off-by: Samuel Ortiz --- drivers/input/keyboard/pmic8xxx-keypad.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 40b02ae96f8..6229c3e8e78 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -520,7 +520,8 @@ static void pmic8xxx_kp_close(struct input_dev *dev) */ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) { - const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev); + const struct pm8xxx_keypad_platform_data *pdata = + dev_get_platdata(&pdev->dev); const struct matrix_keymap_data *keymap_data; struct pmic8xxx_kp *kp; int rc; -- cgit v1.2.3-70-g09d2 From 63ef1124f1cb07836f232b8eaed1ae4c73899643 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 8 Jun 2011 11:06:30 +0200 Subject: input: pmic8xxx-pwrkey: Do not use mfd_get_data() mfd_get_data() has been removed from the MFD API. Cc: Anirudh Ghayal Signed-off-by: Samuel Ortiz --- drivers/input/misc/pmic8xxx-pwrkey.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 97e07e786e4..b3cfb9c71e6 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -90,7 +90,8 @@ static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev) unsigned int delay; u8 pon_cntl; struct pmic8xxx_pwrkey *pwrkey; - const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev); + const struct pm8xxx_pwrkey_platform_data *pdata = + dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "power key platform data not supplied\n"); -- cgit v1.2.3-70-g09d2 From 625cbe46bc97a82dcd9254b5bc01c8520d78b227 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 4 Jul 2011 19:50:02 +0300 Subject: input: twl6040-vibra: Do not use wrapper for irq request The twl6040_request_irq/free_irq inline functions are going to be removed, so replace them with direct calls. The irq number is provided by the core driver via resource. Signed-off-by: Peter Ujfalusi Reviewed-by: Felipe Balbi Acked-by: Dmitry Torokhov --- drivers/input/misc/twl6040-vibra.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index dbf745ddfe5..c43002e7ec7 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -47,6 +47,7 @@ struct vibra_info { struct workqueue_struct *workqueue; struct work_struct play_work; struct mutex mutex; + int irq; bool enabled; int weak_speed; @@ -277,6 +278,13 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev) goto err_kzalloc; } + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + dev_err(info->dev, "invalid irq\n"); + ret = -EINVAL; + goto err_kzalloc; + } + mutex_init(&info->mutex); info->input_dev = input_allocate_device(); @@ -308,9 +316,8 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev) platform_set_drvdata(pdev, info); - ret = twl6040_request_irq(info->twl6040, TWL6040_IRQ_VIB, - twl6040_vib_irq_handler, 0, - "twl6040_irq_vib", info); + ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0, + "twl6040_irq_vib", info); if (ret) { dev_err(info->dev, "VIB IRQ request failed: %d\n", ret); goto err_irq; @@ -360,7 +367,7 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev) err_voltage: regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); err_regulator: - twl6040_free_irq(info->twl6040, TWL6040_IRQ_VIB, info); + free_irq(info->irq, info); err_irq: input_unregister_device(info->input_dev); info->input_dev = NULL; @@ -379,7 +386,7 @@ static int __devexit twl6040_vibra_remove(struct platform_device *pdev) struct vibra_info *info = platform_get_drvdata(pdev); input_unregister_device(info->input_dev); - twl6040_free_irq(info->twl6040, TWL6040_IRQ_VIB, info); + free_irq(info->irq, info); regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies); destroy_workqueue(info->workqueue); kfree(info); -- cgit v1.2.3-70-g09d2 From 5f9288af065537be1fe6d1d5bd54ba51d6df721a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 13 Jul 2011 15:46:21 +0200 Subject: input: xilinx_ps2: Add missing of_address.h header Add missing header. Error log: CC drivers/input/serio/xilinx_ps2.o drivers/input/serio/xilinx_ps2.c: In function 'xps2_of_probe': drivers/input/serio/xilinx_ps2.c:249: error: implicit declaration of function 'of_address_to_resource' Signed-off-by: Michal Simek Signed-off-by: Grant Likely --- drivers/input/serio/xilinx_ps2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 80baa53da5b..d64c5a43aaa 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include -- cgit v1.2.3-70-g09d2 From 11205bb63e5c2e5174f377595103005b00c68370 Mon Sep 17 00:00:00 2001 From: Amy Maloche Date: Mon, 1 Aug 2011 23:41:44 -0700 Subject: Input: add support for pm8xxx based vibrator driver Add support for pm8xx based vibrator to facilitate haptics. This module uses the ff-memless framework. Signed-off-by: Amy Maloche Signed-off-by: Anirudh Ghayal Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 34 ++-- drivers/input/misc/Makefile | 3 +- drivers/input/misc/pm8xxx-vibrator.c | 296 +++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+), 12 deletions(-) create mode 100644 drivers/input/misc/pm8xxx-vibrator.c (limited to 'drivers/input') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 01344280e14..40bcedafd4a 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -74,6 +74,29 @@ config INPUT_PCSPKR To compile this driver as a module, choose M here: the module will be called pcspkr. +config INPUT_PM8XXX_VIBRATOR + tristate "Qualcomm PM8XXX vibrator support" + depends on MFD_PM8XXX + select INPUT_FF_MEMLESS + help + This option enables device driver support for the vibrator + on Qualcomm PM8xxx chip. This driver supports ff-memless interface + from input framework. + + To compile this driver as module, choose M here: the + module will be called pm8xxx-vibrator. + +config INPUT_PMIC8XXX_PWRKEY + tristate "PMIC8XXX power key support" + depends on MFD_PM8XXX + help + Say Y here if you want support for the PMIC8XXX power key. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called pmic8xxx-pwrkey. + config INPUT_SPARCSPKR tristate "SPARC Speaker support" depends on PCI && SPARC64 @@ -368,17 +391,6 @@ config INPUT_PWM_BEEPER To compile this driver as a module, choose M here: the module will be called pwm-beeper. -config INPUT_PMIC8XXX_PWRKEY - tristate "PMIC8XXX power key support" - depends on MFD_PM8XXX - help - Say Y here if you want support for the PMIC8XXX power key. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called pmic8xxx-pwrkey. - config INPUT_GPIO_ROTARY_ENCODER tristate "Rotary encoders connected to GPIO pins" depends on GPIOLIB && GENERIC_GPIO diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index be39d813354..0caad97e7dd 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -34,9 +34,10 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o +obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o +obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o -obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c new file mode 100644 index 00000000000..43192930824 --- /dev/null +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -0,0 +1,296 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIB_DRV 0x4A + +#define VIB_DRV_SEL_MASK 0xf8 +#define VIB_DRV_SEL_SHIFT 0x03 +#define VIB_DRV_EN_MANUAL_MASK 0xfc + +#define VIB_MAX_LEVEL_mV (3100) +#define VIB_MIN_LEVEL_mV (1200) +#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) + +#define MAX_FF_SPEED 0xff + +/** + * struct pm8xxx_vib - structure to hold vibrator data + * @vib_input_dev: input device supporting force feedback + * @work: work structure to set the vibration parameters + * @dev: device supporting force feedback + * @speed: speed of vibration set from userland + * @active: state of vibrator + * @level: level of vibration to set in the chip + * @reg_vib_drv: VIB_DRV register value + */ +struct pm8xxx_vib { + struct input_dev *vib_input_dev; + struct work_struct work; + struct device *dev; + int speed; + int level; + bool active; + u8 reg_vib_drv; +}; + +/** + * pm8xxx_vib_read_u8 - helper to read a byte from pmic chip + * @vib: pointer to vibrator structure + * @data: placeholder for data to be read + * @reg: register address + */ +static int pm8xxx_vib_read_u8(struct pm8xxx_vib *vib, + u8 *data, u16 reg) +{ + int rc; + + rc = pm8xxx_readb(vib->dev->parent, reg, data); + if (rc < 0) + dev_warn(vib->dev, "Error reading pm8xxx reg 0x%x(0x%x)\n", + reg, rc); + return rc; +} + +/** + * pm8xxx_vib_write_u8 - helper to write a byte to pmic chip + * @vib: pointer to vibrator structure + * @data: data to write + * @reg: register address + */ +static int pm8xxx_vib_write_u8(struct pm8xxx_vib *vib, + u8 data, u16 reg) +{ + int rc; + + rc = pm8xxx_writeb(vib->dev->parent, reg, data); + if (rc < 0) + dev_warn(vib->dev, "Error writing pm8xxx reg 0x%x(0x%x)\n", + reg, rc); + return rc; +} + +/** + * pm8xxx_vib_set - handler to start/stop vibration + * @vib: pointer to vibrator structure + * @on: state to set + */ +static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) +{ + int rc; + u8 val = vib->reg_vib_drv; + + if (on) + val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK); + else + val &= ~VIB_DRV_SEL_MASK; + + rc = pm8xxx_vib_write_u8(vib, val, VIB_DRV); + if (rc < 0) + return rc; + + vib->reg_vib_drv = val; + return 0; +} + +/** + * pm8xxx_work_handler - worker to set vibration level + * @work: pointer to work_struct + */ +static void pm8xxx_work_handler(struct work_struct *work) +{ + struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); + int rc; + u8 val; + + rc = pm8xxx_vib_read_u8(vib, &val, VIB_DRV); + if (rc < 0) + return; + + /* + * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so + * scale the level to fit into these ranges. + */ + if (vib->speed) { + vib->active = true; + vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) + + VIB_MIN_LEVEL_mV; + vib->level /= 100; + } else { + vib->active = false; + vib->level = VIB_MIN_LEVEL_mV / 100; + } + + pm8xxx_vib_set(vib, vib->active); +} + +/** + * pm8xxx_vib_close - callback of input close callback + * @dev: input device pointer + * + * Turns off the vibrator. + */ +static void pm8xxx_vib_close(struct input_dev *dev) +{ + struct pm8xxx_vib *vib = input_get_drvdata(dev); + + cancel_work_sync(&vib->work); + if (vib->active) + pm8xxx_vib_set(vib, false); +} + +/** + * pm8xxx_vib_play_effect - function to handle vib effects. + * @dev: input device pointer + * @data: data of effect + * @effect: effect to play + * + * Currently this driver supports only rumble effects. + */ +static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct pm8xxx_vib *vib = input_get_drvdata(dev); + + vib->speed = effect->u.rumble.strong_magnitude >> 8; + if (!vib->speed) + vib->speed = effect->u.rumble.weak_magnitude >> 9; + + schedule_work(&vib->work); + + return 0; +} + +static int __devinit pm8xxx_vib_probe(struct platform_device *pdev) + +{ + struct pm8xxx_vib *vib; + struct input_dev *input_dev; + int error; + u8 val; + + vib = kzalloc(sizeof(*vib), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!vib || !input_dev) { + dev_err(&pdev->dev, "couldn't allocate memory\n"); + error = -ENOMEM; + goto err_free_mem; + } + + INIT_WORK(&vib->work, pm8xxx_work_handler); + vib->dev = &pdev->dev; + vib->vib_input_dev = input_dev; + + /* operate in manual mode */ + error = pm8xxx_vib_read_u8(vib, &val, VIB_DRV); + if (error < 0) + goto err_free_mem; + val &= ~VIB_DRV_EN_MANUAL_MASK; + error = pm8xxx_vib_write_u8(vib, val, VIB_DRV); + if (error < 0) + goto err_free_mem; + + vib->reg_vib_drv = val; + + input_dev->name = "pm8xxx_vib_ffmemless"; + input_dev->id.version = 1; + input_dev->dev.parent = &pdev->dev; + input_dev->close = pm8xxx_vib_close; + input_set_drvdata(input_dev, vib); + input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE); + + error = input_ff_create_memless(input_dev, NULL, + pm8xxx_vib_play_effect); + if (error) { + dev_err(&pdev->dev, + "couldn't register vibrator as FF device\n"); + goto err_free_mem; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "couldn't register input device\n"); + goto err_destroy_memless; + } + + platform_set_drvdata(pdev, vib); + return 0; + +err_destroy_memless: + input_ff_destroy(input_dev); +err_free_mem: + input_free_device(input_dev); + kfree(vib); + + return error; +} + +static int __devexit pm8xxx_vib_remove(struct platform_device *pdev) +{ + struct pm8xxx_vib *vib = platform_get_drvdata(pdev); + + input_unregister_device(vib->vib_input_dev); + kfree(vib); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pm8xxx_vib_suspend(struct device *dev) +{ + struct pm8xxx_vib *vib = dev_get_drvdata(dev); + + /* Turn off the vibrator */ + pm8xxx_vib_set(vib, false); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); + +static struct platform_driver pm8xxx_vib_driver = { + .probe = pm8xxx_vib_probe, + .remove = __devexit_p(pm8xxx_vib_remove), + .driver = { + .name = "pm8xxx-vib", + .owner = THIS_MODULE, + .pm = &pm8xxx_vib_pm_ops, + }, +}; + +static int __init pm8xxx_vib_init(void) +{ + return platform_driver_register(&pm8xxx_vib_driver); +} +module_init(pm8xxx_vib_init); + +static void __exit pm8xxx_vib_exit(void) +{ + platform_driver_unregister(&pm8xxx_vib_driver); +} +module_exit(pm8xxx_vib_exit); + +MODULE_ALIAS("platform:pm8xxx_vib"); +MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Amy Maloche "); -- cgit v1.2.3-70-g09d2 From 5e3e4eb1bf212d9ae4997ebcbe2fdfb348b70213 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 2 Aug 2011 22:22:46 -0700 Subject: Input: polldev - immediately poll device upon opening To allow open/ioctl(EVIOCGABS)/close use pattern for polled devices read the device in context of open() call instead of offloading the first read to a workqueue. This will ensure that once call to open() returns device would have cached reasonably recent axis values that can be retrieved via appropriate ioctl. Signed-off-by: Dmitry Torokhov --- drivers/input/input-polldev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index b1aabde8752..b253973881b 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -49,8 +49,10 @@ static int input_open_polled_device(struct input_dev *input) dev->open(dev); /* Only start polling if polling is enabled */ - if (dev->poll_interval > 0) - queue_delayed_work(system_freezable_wq, &dev->work, 0); + if (dev->poll_interval > 0) { + dev->poll(dev); + input_polldev_queue_work(dev); + } return 0; } -- cgit v1.2.3-70-g09d2 From c17ca3f5a2c98784739bbbcc3f6b6ee177f4f201 Mon Sep 17 00:00:00 2001 From: Eric Andersson Date: Tue, 9 Aug 2011 00:06:37 -0700 Subject: Input: add driver for Bosch Sensortec's BMA150 accelerometer Signed-off-by: Albert Zhang Signed-off-by: Eric Andersson Acked-by: Jonathan Cameron Reviewed-by: Alan Cox Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 11 + drivers/input/misc/Makefile | 1 + drivers/input/misc/bma150.c | 691 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/bma150.h | 46 +++ 4 files changed, 749 insertions(+) create mode 100644 drivers/input/misc/bma150.c create mode 100644 include/linux/bma150.h (limited to 'drivers/input') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 40bcedafd4a..e141debb9d0 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -62,6 +62,17 @@ config INPUT_AD714X_SPI To compile this driver as a module, choose M here: the module will be called ad714x-spi. +config INPUT_BMA150 + tristate "BMA150/SMB380 acceleration sensor support" + depends on I2C + select INPUT_POLLDEV + help + Say Y here if you have Bosch Sensortec's BMA150 or SMB380 + acceleration sensor hooked to an I2C bus. + + To compile this driver as a module, choose M here: the + module will be called bma150. + config INPUT_PCSPKR tristate "PC Speaker support" depends on PCSPKR_PLATFORM diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 0caad97e7dd..ac65eb22bce 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o +obj-$(CONFIG_INPUT_BMA150) += bma150.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c new file mode 100644 index 00000000000..8f55b54352b --- /dev/null +++ b/drivers/input/misc/bma150.c @@ -0,0 +1,691 @@ +/* + * Copyright (c) 2011 Bosch Sensortec GmbH + * Copyright (c) 2011 Unixphere + * + * This driver adds support for Bosch Sensortec's digital acceleration + * sensors BMA150 and SMB380. + * The SMB380 is fully compatible with BMA150 and only differs in packaging. + * + * The datasheet for the BMA150 chip can be found here: + * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ABSMAX_ACC_VAL 0x01FF +#define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL) + +/* Each axis is represented by a 2-byte data word */ +#define BMA150_XYZ_DATA_SIZE 6 + +/* Input poll interval in milliseconds */ +#define BMA150_POLL_INTERVAL 10 +#define BMA150_POLL_MAX 200 +#define BMA150_POLL_MIN 0 + +#define BMA150_BW_25HZ 0 +#define BMA150_BW_50HZ 1 +#define BMA150_BW_100HZ 2 +#define BMA150_BW_190HZ 3 +#define BMA150_BW_375HZ 4 +#define BMA150_BW_750HZ 5 +#define BMA150_BW_1500HZ 6 + +#define BMA150_RANGE_2G 0 +#define BMA150_RANGE_4G 1 +#define BMA150_RANGE_8G 2 + +#define BMA150_MODE_NORMAL 0 +#define BMA150_MODE_SLEEP 2 +#define BMA150_MODE_WAKE_UP 3 + +/* Data register addresses */ +#define BMA150_DATA_0_REG 0x00 +#define BMA150_DATA_1_REG 0x01 +#define BMA150_DATA_2_REG 0x02 + +/* Control register addresses */ +#define BMA150_CTRL_0_REG 0x0A +#define BMA150_CTRL_1_REG 0x0B +#define BMA150_CTRL_2_REG 0x14 +#define BMA150_CTRL_3_REG 0x15 + +/* Configuration/Setting register addresses */ +#define BMA150_CFG_0_REG 0x0C +#define BMA150_CFG_1_REG 0x0D +#define BMA150_CFG_2_REG 0x0E +#define BMA150_CFG_3_REG 0x0F +#define BMA150_CFG_4_REG 0x10 +#define BMA150_CFG_5_REG 0x11 + +#define BMA150_CHIP_ID 2 +#define BMA150_CHIP_ID_REG BMA150_DATA_0_REG + +#define BMA150_ACC_X_LSB_REG BMA150_DATA_2_REG + +#define BMA150_SLEEP_POS 0 +#define BMA150_SLEEP_MSK 0x01 +#define BMA150_SLEEP_REG BMA150_CTRL_0_REG + +#define BMA150_BANDWIDTH_POS 0 +#define BMA150_BANDWIDTH_MSK 0x07 +#define BMA150_BANDWIDTH_REG BMA150_CTRL_2_REG + +#define BMA150_RANGE_POS 3 +#define BMA150_RANGE_MSK 0x18 +#define BMA150_RANGE_REG BMA150_CTRL_2_REG + +#define BMA150_WAKE_UP_POS 0 +#define BMA150_WAKE_UP_MSK 0x01 +#define BMA150_WAKE_UP_REG BMA150_CTRL_3_REG + +#define BMA150_SW_RES_POS 1 +#define BMA150_SW_RES_MSK 0x02 +#define BMA150_SW_RES_REG BMA150_CTRL_0_REG + +/* Any-motion interrupt register fields */ +#define BMA150_ANY_MOTION_EN_POS 6 +#define BMA150_ANY_MOTION_EN_MSK 0x40 +#define BMA150_ANY_MOTION_EN_REG BMA150_CTRL_1_REG + +#define BMA150_ANY_MOTION_DUR_POS 6 +#define BMA150_ANY_MOTION_DUR_MSK 0xC0 +#define BMA150_ANY_MOTION_DUR_REG BMA150_CFG_5_REG + +#define BMA150_ANY_MOTION_THRES_REG BMA150_CFG_4_REG + +/* Advanced interrupt register fields */ +#define BMA150_ADV_INT_EN_POS 6 +#define BMA150_ADV_INT_EN_MSK 0x40 +#define BMA150_ADV_INT_EN_REG BMA150_CTRL_3_REG + +/* High-G interrupt register fields */ +#define BMA150_HIGH_G_EN_POS 1 +#define BMA150_HIGH_G_EN_MSK 0x02 +#define BMA150_HIGH_G_EN_REG BMA150_CTRL_1_REG + +#define BMA150_HIGH_G_HYST_POS 3 +#define BMA150_HIGH_G_HYST_MSK 0x38 +#define BMA150_HIGH_G_HYST_REG BMA150_CFG_5_REG + +#define BMA150_HIGH_G_DUR_REG BMA150_CFG_3_REG +#define BMA150_HIGH_G_THRES_REG BMA150_CFG_2_REG + +/* Low-G interrupt register fields */ +#define BMA150_LOW_G_EN_POS 0 +#define BMA150_LOW_G_EN_MSK 0x01 +#define BMA150_LOW_G_EN_REG BMA150_CTRL_1_REG + +#define BMA150_LOW_G_HYST_POS 0 +#define BMA150_LOW_G_HYST_MSK 0x07 +#define BMA150_LOW_G_HYST_REG BMA150_CFG_5_REG + +#define BMA150_LOW_G_DUR_REG BMA150_CFG_1_REG +#define BMA150_LOW_G_THRES_REG BMA150_CFG_0_REG + +struct bma150_data { + struct i2c_client *client; + struct input_polled_dev *input_polled; + struct input_dev *input; + u8 mode; +}; + +/* + * The settings for the given range, bandwidth and interrupt features + * are stated and verified by Bosch Sensortec where they are configured + * to provide a generic sensitivity performance. + */ +static struct bma150_cfg default_cfg __devinitdata = { + .any_motion_int = 1, + .hg_int = 1, + .lg_int = 1, + .any_motion_dur = 0, + .any_motion_thres = 0, + .hg_hyst = 0, + .hg_dur = 150, + .hg_thres = 160, + .lg_hyst = 0, + .lg_dur = 150, + .lg_thres = 20, + .range = BMA150_RANGE_2G, + .bandwidth = BMA150_BW_50HZ +}; + +static int bma150_write_byte(struct i2c_client *client, u8 reg, u8 val) +{ + s32 ret; + + /* As per specification, disable irq in between register writes */ + if (client->irq) + disable_irq_nosync(client->irq); + + ret = i2c_smbus_write_byte_data(client, reg, val); + + if (client->irq) + enable_irq(client->irq); + + return ret; +} + +static int bma150_set_reg_bits(struct i2c_client *client, + int val, int shift, u8 mask, u8 reg) +{ + int data; + + data = i2c_smbus_read_byte_data(client, reg); + if (data < 0) + return data; + + data = (data & ~mask) | ((val << shift) & mask); + return bma150_write_byte(client, reg, data); +} + +static int bma150_set_mode(struct bma150_data *bma150, u8 mode) +{ + int error; + + error = bma150_set_reg_bits(bma150->client, mode, BMA150_WAKE_UP_POS, + BMA150_WAKE_UP_MSK, BMA150_WAKE_UP_REG); + if (error) + return error; + + error = bma150_set_reg_bits(bma150->client, mode, BMA150_SLEEP_POS, + BMA150_SLEEP_MSK, BMA150_SLEEP_REG); + if (error) + return error; + + if (mode == BMA150_MODE_NORMAL) + msleep(2); + + bma150->mode = mode; + return 0; +} + +static int __devinit bma150_soft_reset(struct bma150_data *bma150) +{ + int error; + + error = bma150_set_reg_bits(bma150->client, 1, BMA150_SW_RES_POS, + BMA150_SW_RES_MSK, BMA150_SW_RES_REG); + if (error) + return error; + + msleep(2); + return 0; +} + +static int __devinit bma150_set_range(struct bma150_data *bma150, u8 range) +{ + return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS, + BMA150_RANGE_MSK, BMA150_RANGE_REG); +} + +static int __devinit bma150_set_bandwidth(struct bma150_data *bma150, u8 bw) +{ + return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS, + BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG); +} + +static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150, + u8 enable, u8 hyst, u8 dur, u8 thres) +{ + int error; + + error = bma150_set_reg_bits(bma150->client, hyst, + BMA150_LOW_G_HYST_POS, BMA150_LOW_G_HYST_MSK, + BMA150_LOW_G_HYST_REG); + if (error) + return error; + + error = bma150_write_byte(bma150->client, BMA150_LOW_G_DUR_REG, dur); + if (error) + return error; + + error = bma150_write_byte(bma150->client, BMA150_LOW_G_THRES_REG, thres); + if (error) + return error; + + return bma150_set_reg_bits(bma150->client, !!enable, + BMA150_LOW_G_EN_POS, BMA150_LOW_G_EN_MSK, + BMA150_LOW_G_EN_REG); +} + +static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150, + u8 enable, u8 hyst, u8 dur, u8 thres) +{ + int error; + + error = bma150_set_reg_bits(bma150->client, hyst, + BMA150_HIGH_G_HYST_POS, BMA150_HIGH_G_HYST_MSK, + BMA150_HIGH_G_HYST_REG); + if (error) + return error; + + error = bma150_write_byte(bma150->client, + BMA150_HIGH_G_DUR_REG, dur); + if (error) + return error; + + error = bma150_write_byte(bma150->client, + BMA150_HIGH_G_THRES_REG, thres); + if (error) + return error; + + return bma150_set_reg_bits(bma150->client, !!enable, + BMA150_HIGH_G_EN_POS, BMA150_HIGH_G_EN_MSK, + BMA150_HIGH_G_EN_REG); +} + + +static int __devinit bma150_set_any_motion_interrupt(struct bma150_data *bma150, + u8 enable, u8 dur, u8 thres) +{ + int error; + + error = bma150_set_reg_bits(bma150->client, dur, + BMA150_ANY_MOTION_DUR_POS, + BMA150_ANY_MOTION_DUR_MSK, + BMA150_ANY_MOTION_DUR_REG); + if (error) + return error; + + error = bma150_write_byte(bma150->client, + BMA150_ANY_MOTION_THRES_REG, thres); + if (error) + return error; + + error = bma150_set_reg_bits(bma150->client, !!enable, + BMA150_ADV_INT_EN_POS, BMA150_ADV_INT_EN_MSK, + BMA150_ADV_INT_EN_REG); + if (error) + return error; + + return bma150_set_reg_bits(bma150->client, !!enable, + BMA150_ANY_MOTION_EN_POS, + BMA150_ANY_MOTION_EN_MSK, + BMA150_ANY_MOTION_EN_REG); +} + +static void bma150_report_xyz(struct bma150_data *bma150) +{ + u8 data[BMA150_XYZ_DATA_SIZE]; + s16 x, y, z; + s32 ret; + + ret = i2c_smbus_read_i2c_block_data(bma150->client, + BMA150_ACC_X_LSB_REG, BMA150_XYZ_DATA_SIZE, data); + if (ret != BMA150_XYZ_DATA_SIZE) + return; + + x = ((0xc0 & data[0]) >> 6) | (data[1] << 2); + y = ((0xc0 & data[2]) >> 6) | (data[3] << 2); + z = ((0xc0 & data[4]) >> 6) | (data[5] << 2); + + /* sign extension */ + x = (s16) (x << 6) >> 6; + y = (s16) (y << 6) >> 6; + z = (s16) (z << 6) >> 6; + + input_report_abs(bma150->input, ABS_X, x); + input_report_abs(bma150->input, ABS_Y, y); + input_report_abs(bma150->input, ABS_Z, z); + input_sync(bma150->input); +} + +static irqreturn_t bma150_irq_thread(int irq, void *dev) +{ + bma150_report_xyz(dev); + + return IRQ_HANDLED; +} + +static void bma150_poll(struct input_polled_dev *dev) +{ + bma150_report_xyz(dev->private); +} + +static int bma150_open(struct bma150_data *bma150) +{ + int error; + + error = pm_runtime_get_sync(&bma150->client->dev); + if (error && error != -ENOSYS) + return error; + + /* + * See if runtime PM woke up the device. If runtime PM + * is disabled we need to do it ourselves. + */ + if (bma150->mode != BMA150_MODE_NORMAL) { + error = bma150_set_mode(bma150, BMA150_MODE_NORMAL); + if (error) + return error; + } + + return 0; +} + +static void bma150_close(struct bma150_data *bma150) +{ + pm_runtime_put_sync(&bma150->client->dev); + + if (bma150->mode != BMA150_MODE_SLEEP) + bma150_set_mode(bma150, BMA150_MODE_SLEEP); +} + +static int bma150_irq_open(struct input_dev *input) +{ + struct bma150_data *bma150 = input_get_drvdata(input); + + return bma150_open(bma150); +} + +static void bma150_irq_close(struct input_dev *input) +{ + struct bma150_data *bma150 = input_get_drvdata(input); + + bma150_close(bma150); +} + +static void bma150_poll_open(struct input_polled_dev *ipoll_dev) +{ + struct bma150_data *bma150 = ipoll_dev->private; + + bma150_open(bma150); +} + +static void bma150_poll_close(struct input_polled_dev *ipoll_dev) +{ + struct bma150_data *bma150 = ipoll_dev->private; + + bma150_close(bma150); +} + +static int __devinit bma150_initialize(struct bma150_data *bma150, + const struct bma150_cfg *cfg) +{ + int error; + + error = bma150_soft_reset(bma150); + if (error) + return error; + + error = bma150_set_bandwidth(bma150, cfg->bandwidth); + if (error) + return error; + + error = bma150_set_range(bma150, cfg->range); + if (error) + return error; + + if (bma150->client->irq) { + error = bma150_set_any_motion_interrupt(bma150, + cfg->any_motion_int, + cfg->any_motion_dur, + cfg->any_motion_thres); + if (error) + return error; + + error = bma150_set_high_g_interrupt(bma150, + cfg->hg_int, cfg->hg_hyst, + cfg->hg_dur, cfg->hg_thres); + if (error) + return error; + + error = bma150_set_low_g_interrupt(bma150, + cfg->lg_int, cfg->lg_hyst, + cfg->lg_dur, cfg->lg_thres); + if (error) + return error; + } + + return bma150_set_mode(bma150, BMA150_MODE_SLEEP); +} + +static void __devinit bma150_init_input_device(struct bma150_data *bma150, + struct input_dev *idev) +{ + idev->name = BMA150_DRIVER; + idev->phys = BMA150_DRIVER "/input0"; + idev->id.bustype = BUS_I2C; + idev->dev.parent = &bma150->client->dev; + + idev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0); + input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0); + input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0); +} + +static int __devinit bma150_register_input_device(struct bma150_data *bma150) +{ + struct input_dev *idev; + int error; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + bma150_init_input_device(bma150, idev); + + idev->open = bma150_irq_open; + idev->close = bma150_irq_close; + input_set_drvdata(idev, bma150); + + error = input_register_device(idev); + if (error) { + input_free_device(idev); + return error; + } + + bma150->input = idev; + return 0; +} + +static int __devinit bma150_register_polled_device(struct bma150_data *bma150) +{ + struct input_polled_dev *ipoll_dev; + int error; + + ipoll_dev = input_allocate_polled_device(); + if (!ipoll_dev) + return -ENOMEM; + + ipoll_dev->private = bma150; + ipoll_dev->open = bma150_poll_open; + ipoll_dev->close = bma150_poll_close; + ipoll_dev->poll = bma150_poll; + ipoll_dev->poll_interval = BMA150_POLL_INTERVAL; + ipoll_dev->poll_interval_min = BMA150_POLL_MIN; + ipoll_dev->poll_interval_max = BMA150_POLL_MAX; + + bma150_init_input_device(bma150, ipoll_dev->input); + + error = input_register_polled_device(ipoll_dev); + if (error) { + input_free_polled_device(ipoll_dev); + return error; + } + + bma150->input_polled = ipoll_dev; + bma150->input = ipoll_dev->input; + + return 0; +} + +static int __devinit bma150_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct bma150_platform_data *pdata = client->dev.platform_data; + const struct bma150_cfg *cfg; + struct bma150_data *bma150; + int chip_id; + int error; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c_check_functionality error\n"); + return -EIO; + } + + chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG); + if (chip_id != BMA150_CHIP_ID) { + dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id); + return -EINVAL; + } + + bma150 = kzalloc(sizeof(struct bma150_data), GFP_KERNEL); + if (!bma150) + return -ENOMEM; + + bma150->client = client; + + if (pdata) { + if (pdata->irq_gpio_cfg) { + error = pdata->irq_gpio_cfg(); + if (error) { + dev_err(&client->dev, + "IRQ GPIO conf. error %d, error %d\n", + client->irq, error); + goto err_free_mem; + } + } + cfg = &pdata->cfg; + } else { + cfg = &default_cfg; + } + + error = bma150_initialize(bma150, cfg); + if (error) + goto err_free_mem; + + if (client->irq > 0) { + error = bma150_register_input_device(bma150); + if (error) + goto err_free_mem; + + error = request_threaded_irq(client->irq, + NULL, bma150_irq_thread, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + BMA150_DRIVER, bma150); + if (error) { + dev_err(&client->dev, + "irq request failed %d, error %d\n", + client->irq, error); + input_unregister_device(bma150->input); + goto err_free_mem; + } + } else { + error = bma150_register_polled_device(bma150); + if (error) + goto err_free_mem; + } + + i2c_set_clientdata(client, bma150); + + pm_runtime_enable(&client->dev); + + return 0; + +err_free_mem: + kfree(bma150); + return error; +} + +static int __devexit bma150_remove(struct i2c_client *client) +{ + struct bma150_data *bma150 = i2c_get_clientdata(client); + + pm_runtime_disable(&client->dev); + + if (client->irq > 0) { + free_irq(client->irq, bma150); + input_unregister_device(bma150->input); + } else { + input_unregister_polled_device(bma150->input_polled); + input_free_polled_device(bma150->input_polled); + } + + kfree(bma150); + + return 0; +} + +#ifdef CONFIG_PM +static int bma150_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma150_data *bma150 = i2c_get_clientdata(client); + + return bma150_set_mode(bma150, BMA150_MODE_SLEEP); +} + +static int bma150_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma150_data *bma150 = i2c_get_clientdata(client); + + return bma150_set_mode(bma150, BMA150_MODE_NORMAL); +} +#endif + +static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL); + +static const struct i2c_device_id bma150_id[] = { + { "bma150", 0 }, + { "smb380", 0 }, + { "bma023", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, bma150_id); + +static struct i2c_driver bma150_driver = { + .driver = { + .owner = THIS_MODULE, + .name = BMA150_DRIVER, + .pm = &bma150_pm, + }, + .class = I2C_CLASS_HWMON, + .id_table = bma150_id, + .probe = bma150_probe, + .remove = __devexit_p(bma150_remove), +}; + +static int __init BMA150_init(void) +{ + return i2c_add_driver(&bma150_driver); +} + +static void __exit BMA150_exit(void) +{ + i2c_del_driver(&bma150_driver); +} + +MODULE_AUTHOR("Albert Zhang "); +MODULE_DESCRIPTION("BMA150 driver"); +MODULE_LICENSE("GPL"); + +module_init(BMA150_init); +module_exit(BMA150_exit); diff --git a/include/linux/bma150.h b/include/linux/bma150.h new file mode 100644 index 00000000000..7911fda23bb --- /dev/null +++ b/include/linux/bma150.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Bosch Sensortec GmbH + * Copyright (c) 2011 Unixphere + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _BMA150_H_ +#define _BMA150_H_ + +#define BMA150_DRIVER "bma150" + +struct bma150_cfg { + bool any_motion_int; /* Set to enable any-motion interrupt */ + bool hg_int; /* Set to enable high-G interrupt */ + bool lg_int; /* Set to enable low-G interrupt */ + unsigned char any_motion_dur; /* Any-motion duration */ + unsigned char any_motion_thres; /* Any-motion threshold */ + unsigned char hg_hyst; /* High-G hysterisis */ + unsigned char hg_dur; /* High-G duration */ + unsigned char hg_thres; /* High-G threshold */ + unsigned char lg_hyst; /* Low-G hysterisis */ + unsigned char lg_dur; /* Low-G duration */ + unsigned char lg_thres; /* Low-G threshold */ + unsigned char range; /* BMA0150_RANGE_xxx (in G) */ + unsigned char bandwidth; /* BMA0150_BW_xxx (in Hz) */ +}; + +struct bma150_platform_data { + struct bma150_cfg cfg; + int (*irq_gpio_cfg)(void); +}; + +#endif /* _BMA150_H_ */ -- cgit v1.2.3-70-g09d2 From e9496746cc0954c43720de0c88fef95a9d229baa Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 23 Aug 2011 22:57:00 -0700 Subject: Input: wacom_w8001 - implement open and close Implement open() and close() methods for the input device so that we do not start the device unless there are users listening to the events. Acked-by: Chris Bagwell Tested-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wacom_w8001.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index c14412ef464..5ece6c1f329 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -367,6 +367,20 @@ static int w8001_command(struct w8001 *w8001, unsigned char command, return rc; } +static int w8001_open(struct input_dev *dev) +{ + struct w8001 *w8001 = input_get_drvdata(dev); + + return w8001_command(w8001, W8001_CMD_START, false); +} + +static void w8001_close(struct input_dev *dev) +{ + struct w8001 *w8001 = input_get_drvdata(dev); + + w8001_command(w8001, W8001_CMD_STOP, false); +} + static int w8001_setup(struct w8001 *w8001) { struct input_dev *dev = w8001->dev; @@ -474,7 +488,7 @@ static int w8001_setup(struct w8001 *w8001) strlcat(w8001->name, " Touchscreen", sizeof(w8001->name)); - return w8001_command(w8001, W8001_CMD_START, false); + return 0; } /* @@ -534,6 +548,11 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.version = 0x0100; input_dev->dev.parent = &serio->dev; + input_dev->open = w8001_open; + input_dev->close = w8001_close; + + input_set_drvdata(input_dev, w8001); + err = input_register_device(w8001->dev); if (err) goto fail3; -- cgit v1.2.3-70-g09d2 From 66fd9385ee9c582ee88031ba5028748cb38c986d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 23 Aug 2011 22:57:00 -0700 Subject: Input: wacom_w8001 - simplify w8001_remove Since touchscreen driver does not handle any events to be sent to the device we can close serio port first and then unregister the input device. Tested-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wacom_w8001.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 5ece6c1f329..1f42d91f755 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -499,12 +499,12 @@ static void w8001_disconnect(struct serio *serio) { struct w8001 *w8001 = serio_get_drvdata(serio); - input_get_device(w8001->dev); - input_unregister_device(w8001->dev); serio_close(serio); - serio_set_drvdata(serio, NULL); - input_put_device(w8001->dev); + + input_unregister_device(w8001->dev); kfree(w8001); + + serio_set_drvdata(serio, NULL); } /* -- cgit v1.2.3-70-g09d2 From 6de58dd625a7645008c5c450bf97a5793faf58c3 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:00:24 -0700 Subject: Input: synaptics - refactor y inversion Synaptics touchpads report increasing y from bottom to top. This is inverted from normal userspace "top of screen is 0" coordinates. Thus, the kernel driver reports inverted y coordinates to userspace. This patch refactors this inversion. Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 5538fc657af..b0008bcb26f 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -44,6 +44,16 @@ #define YMIN_NOMINAL 1408 #define YMAX_NOMINAL 4448 +/* + * Synaptics touchpads report the y coordinate from bottom to top, which is + * opposite from what userspace expects. + * This function is used to invert y before reporting. + */ +static int synaptics_invert_y(int y) +{ + return YMAX_NOMINAL + YMIN_NOMINAL - y; +} + /***************************************************************************** * Stuff we need even when we do not want native Synaptics support @@ -502,8 +512,7 @@ static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot, input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); if (active) { input_report_abs(dev, ABS_MT_POSITION_X, x); - input_report_abs(dev, ABS_MT_POSITION_Y, - YMAX_NOMINAL + YMIN_NOMINAL - y); + input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(y)); } } @@ -597,7 +606,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (num_fingers > 0) { input_report_abs(dev, ABS_X, hw.x); - input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); + input_report_abs(dev, ABS_Y, synaptics_invert_y(hw.y)); } input_report_abs(dev, ABS_PRESSURE, hw.z); -- cgit v1.2.3-70-g09d2 From 7afdb842d9fa8cd62c33e76a1efc62c59772216d Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:00:33 -0700 Subject: Input: synaptics - refactor agm packet parsing When a Synaptics touchpad is in "AGM" mode, and multiple fingers are detected, the touchpad sends alternating "Advanced Gesture Mode" (AGM) and "Simple Gesture Mode" (SGM) packets. The AGM packets have w=2, and contain reduced resolution finger data. The SGM packets have w={0,1} and contain full resolution finger data. Refactor the parsing of agm packets to its own function, and rename the synaptics_data.mt field to .agm to indicate that it contains the contents of the last agm packet. Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 19 ++++++++++++++----- drivers/input/mouse/synaptics.h | 6 +++++- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index b0008bcb26f..34bcc1fc59f 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -419,6 +419,17 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ +static void synaptics_parse_agm(const unsigned char buf[], + struct synaptics_data *priv) +{ + struct synaptics_hw_state *agm = &priv->agm; + + /* Gesture packet: (x, y, z) at half resolution */ + agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; + agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; + agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; +} + static int synaptics_parse_hw_state(const unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) @@ -453,10 +464,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], } if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) { - /* Gesture packet: (x, y, z) at half resolution */ - priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; - priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; - priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + synaptics_parse_agm(buf, priv); return 1; } @@ -595,7 +603,8 @@ static void synaptics_process_packet(struct psmouse *psmouse) } if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) - synaptics_report_semi_mt_data(dev, &hw, &priv->mt, num_fingers); + synaptics_report_semi_mt_data(dev, &hw, &priv->agm, + num_fingers); /* Post events * BTN_TOUCH has to be first as mousedev relies on it when doing diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index ca040aa80fa..a9efbf3e3ea 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -146,7 +146,11 @@ struct synaptics_data { struct serio *pt_port; /* Pass-through serio port */ - struct synaptics_hw_state mt; /* current gesture packet */ + /* + * Last received Advanced Gesture Mode (AGM) packet. An AGM packet + * contains position data for a second contact, at half resolution. + */ + struct synaptics_hw_state agm; }; void synaptics_module_init(void); -- cgit v1.2.3-70-g09d2 From 85615476e2039d2567075d7949a30f0c204f8103 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:00:41 -0700 Subject: Input: synaptics - refactor initialization of abs position axes Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 44 +++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 34bcc1fc59f..8e9360ab4ec 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -712,39 +712,38 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) /***************************************************************************** * Driver initialization/cleanup functions ****************************************************************************/ +static void set_abs_position_params(struct input_dev *dev, + struct synaptics_data *priv, int x_code, + int y_code) +{ + int x_min = priv->x_min ?: XMIN_NOMINAL; + int x_max = priv->x_max ?: XMAX_NOMINAL; + int y_min = priv->y_min ?: YMIN_NOMINAL; + int y_max = priv->y_max ?: YMAX_NOMINAL; + int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? + SYN_REDUCED_FILTER_FUZZ : 0; + + input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0); + input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0); + input_abs_set_res(dev, x_code, priv->x_res); + input_abs_set_res(dev, y_code, priv->y_res); +} + static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) { int i; - int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? - SYN_REDUCED_FILTER_FUZZ : 0; __set_bit(INPUT_PROP_POINTER, dev->propbit); __set_bit(EV_ABS, dev->evbit); - input_set_abs_params(dev, ABS_X, - priv->x_min ?: XMIN_NOMINAL, - priv->x_max ?: XMAX_NOMINAL, - fuzz, 0); - input_set_abs_params(dev, ABS_Y, - priv->y_min ?: YMIN_NOMINAL, - priv->y_max ?: YMAX_NOMINAL, - fuzz, 0); + set_abs_position_params(dev, priv, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); input_mt_init_slots(dev, 2); - input_set_abs_params(dev, ABS_MT_POSITION_X, - priv->x_min ?: XMIN_NOMINAL, - priv->x_max ?: XMAX_NOMINAL, - fuzz, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, - priv->y_min ?: YMIN_NOMINAL, - priv->y_max ?: YMAX_NOMINAL, - fuzz, 0); - - input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res); - input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res); + set_abs_position_params(dev, priv, ABS_MT_POSITION_X, + ABS_MT_POSITION_Y); } if (SYN_CAP_PALMDETECT(priv->capabilities)) @@ -777,9 +776,6 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) __clear_bit(REL_X, dev->relbit); __clear_bit(REL_Y, dev->relbit); - input_abs_set_res(dev, ABS_X, priv->x_res); - input_abs_set_res(dev, ABS_Y, priv->y_res); - if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); /* Clickpads report only left button */ -- cgit v1.2.3-70-g09d2 From 3cdfee9ea7e98eb6e8c3d4d66f2dfcfffe6afc4d Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:02:25 -0700 Subject: Input: synaptics - add image sensor support Synaptics makes (at least) two kinds of touchpad sensors: * Older pads use a profile sensor that could only infer the location of individual fingers based on the projection of their profiles onto row and column sensors. * Newer pads use an image sensor that can track true finger position using a two-dimensional sensor grid. Both sensor types support an "Advanced Gesture Mode": When multiple fingers are detected, the touchpad sends alternating "Advanced Gesture Mode" (AGM) and "Simple Gesture Mode" (SGM) packets. The AGM packets have w=2, and contain reduced resolution finger data The SGM packets have w={0,1} and contain full resolution finger data Profile sensors try to report the "upper" (larger y value) finger in the SGM packet, and the lower (smaller y value) in the AGM packet. However, due to the nature of the profile sensor, they easily get confused when fingers cross, and can start reporting the x-coordinate of one with the y-coordinate of the other. Thus, for profile sensors, "semi-mt" was created, which reports a "bounding box" created by pairing min and max coordinates of the two pairs of reported fingers. Image sensors can report the actual coordinates of two of the fingers present. This patch detects if the touchpad is an image sensor and reports finger data using the MT-B protocol. NOTE: This patch only adds partial support for 2-finger gestures. The proper interpretation of the slot contents when more than two fingers are present is left to later patches. Also, handling of 'number of fingers' transitions is incomplete. Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 124 ++++++++++++++++++++++++++++++++++------ drivers/input/mouse/synaptics.h | 3 + 2 files changed, 110 insertions(+), 17 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 8e9360ab4ec..e6e59c59391 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -304,7 +304,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static unsigned char param = 0xc8; struct synaptics_data *priv = psmouse->private; - if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) + if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))) return 0; if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) @@ -463,7 +464,9 @@ static int synaptics_parse_hw_state(const unsigned char buf[], hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) { + if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && + hw->w == 2) { synaptics_parse_agm(buf, priv); return 1; } @@ -543,6 +546,94 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev, } } +static void synaptics_report_buttons(struct psmouse *psmouse, + const struct synaptics_hw_state *hw) +{ + struct input_dev *dev = psmouse->dev; + struct synaptics_data *priv = psmouse->private; + int i; + + input_report_key(dev, BTN_LEFT, hw->left); + input_report_key(dev, BTN_RIGHT, hw->right); + + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + input_report_key(dev, BTN_MIDDLE, hw->middle); + + if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + input_report_key(dev, BTN_FORWARD, hw->up); + input_report_key(dev, BTN_BACK, hw->down); + } + + for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) + input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i)); +} + +static void synaptics_report_slot(struct input_dev *dev, int slot, + const struct synaptics_hw_state *hw) +{ + input_mt_slot(dev, slot); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL)); + if (!hw) + return; + + input_report_abs(dev, ABS_MT_POSITION_X, hw->x); + input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y)); + input_report_abs(dev, ABS_MT_PRESSURE, hw->z); +} + +static void synaptics_report_mt_data(struct psmouse *psmouse, + int count, + const struct synaptics_hw_state *sgm) +{ + struct input_dev *dev = psmouse->dev; + struct synaptics_data *priv = psmouse->private; + struct synaptics_hw_state *agm = &priv->agm; + + switch (count) { + case 0: + synaptics_report_slot(dev, 0, NULL); + synaptics_report_slot(dev, 1, NULL); + break; + case 1: + synaptics_report_slot(dev, 0, sgm); + synaptics_report_slot(dev, 1, NULL); + break; + case 2: + case 3: /* Fall-through case */ + synaptics_report_slot(dev, 0, sgm); + synaptics_report_slot(dev, 1, agm); + break; + } + + /* Don't use active slot count to generate BTN_TOOL events. */ + input_mt_report_pointer_emulation(dev, false); + + /* Send the number of fingers reported by touchpad itself. */ + input_mt_report_finger_count(dev, count); + + synaptics_report_buttons(psmouse, sgm); + + input_sync(dev); +} + +static void synaptics_image_sensor_process(struct psmouse *psmouse, + struct synaptics_hw_state *sgm) +{ + int count; + + if (sgm->z == 0) + count = 0; + else if (sgm->w >= 4) + count = 1; + else if (sgm->w == 0) + count = 2; + else + count = 3; + + /* Send resulting input events to user space */ + synaptics_report_mt_data(psmouse, count, sgm); +} + /* * called for each full received packet from the touchpad */ @@ -553,11 +644,15 @@ static void synaptics_process_packet(struct psmouse *psmouse) struct synaptics_hw_state hw; int num_fingers; int finger_width; - int i; if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) return; + if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { + synaptics_image_sensor_process(psmouse, &hw); + return; + } + if (hw.scroll) { priv->scroll += hw.scroll; @@ -623,24 +718,12 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); - input_report_key(dev, BTN_LEFT, hw.left); - input_report_key(dev, BTN_RIGHT, hw.right); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); } - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) - input_report_key(dev, BTN_MIDDLE, hw.middle); - - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { - input_report_key(dev, BTN_FORWARD, hw.up); - input_report_key(dev, BTN_BACK, hw.down); - } - - for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) - input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i)); + synaptics_report_buttons(psmouse, &hw); input_sync(dev); } @@ -739,7 +822,14 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) set_abs_position_params(dev, priv, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { + if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { + input_mt_init_slots(dev, 2); + set_abs_position_params(dev, priv, ABS_MT_POSITION_X, + ABS_MT_POSITION_Y); + /* Image sensors can report per-contact pressure */ + input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { + /* Non-image sensors with AGM use semi-mt */ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); input_mt_init_slots(dev, 2); set_abs_position_params(dev, priv, ABS_MT_POSITION_X, diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index a9efbf3e3ea..0ea7616e8fe 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -74,6 +74,8 @@ * 2 0x04 reduced filtering firmware does less filtering on * position data, driver should watch * for noise. + * 2 0x08 image sensor image sensor tracks 5 fingers, but only + * reports 2. * 2 0x20 report min query 0x0f gives min coord reported */ #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ @@ -82,6 +84,7 @@ #define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) #define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) +#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) -- cgit v1.2.3-70-g09d2 From a6ca40c11eb5d98e53176adf527e430f7037a8c9 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:02:31 -0700 Subject: Input: synaptics - decode AGM packet types A Synaptics image sensor tracks 5 fingers, but can only report 2. The algorithm for choosing which 2 fingers to report and in which packet: Touchpad maintains 5 slots, numbered 0 to 4 Initially all slots are empty As new fingers are detected, assign them to the lowest available slots The touchpad always reports: SGM: lowest numbered non-empty slot AGM: highest numbered non-empty slot, if there is one In addition, these touchpads have a special AGM packet type which reports the number of fingers currently being tracked, and which finger is in each of the two slots. Unfortunately, these "TYPE=2" packets are only used when more than 3 fingers are being tracked. When less than 4 fingers are present, the 'w' value must be used to track how many fingers are present, and knowing which fingers are being reported is much more difficult, if not impossible. Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 36 ++++++++++++++++++++++++++++++------ drivers/input/mouse/synaptics.h | 14 +++++++++++++- 2 files changed, 43 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index e6e59c59391..a7af8565e2d 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -420,15 +420,39 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ +static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count, + int sgm, int agm) +{ + state->count = count; + state->sgm = sgm; + state->agm = agm; +} + static void synaptics_parse_agm(const unsigned char buf[], - struct synaptics_data *priv) + struct synaptics_data *priv, + struct synaptics_hw_state *hw) { struct synaptics_hw_state *agm = &priv->agm; + int agm_packet_type; + + agm_packet_type = (buf[5] & 0x30) >> 4; + switch (agm_packet_type) { + case 1: + /* Gesture packet: (x, y, z) half resolution */ + agm->w = hw->w; + agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; + agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; + agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + break; - /* Gesture packet: (x, y, z) at half resolution */ - agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; - agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; - agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + case 2: + /* AGM-CONTACT packet: (count, sgm, agm) */ + synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]); + break; + + default: + break; + } } static int synaptics_parse_hw_state(const unsigned char buf[], @@ -467,7 +491,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && hw->w == 2) { - synaptics_parse_agm(buf, priv); + synaptics_parse_agm(buf, priv, hw); return 1; } diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 0ea7616e8fe..20f57dfebed 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -115,9 +115,18 @@ #define SYN_REDUCED_FILTER_FUZZ 8 /* - * A structure to describe the state of the touchpad hardware (buttons and pad) + * A structure to describe which internal touchpad finger slots are being + * reported in raw packets. */ +struct synaptics_mt_state { + int count; /* num fingers being tracked */ + int sgm; /* which slot is reported by sgm pkt */ + int agm; /* which slot is reported by agm pkt*/ +}; +/* + * A structure to describe the state of the touchpad hardware (buttons and pad) + */ struct synaptics_hw_state { int x; int y; @@ -130,6 +139,9 @@ struct synaptics_hw_state { unsigned int down:1; unsigned char ext_buttons; signed char scroll; + + /* As reported in last AGM-CONTACT packets */ + struct synaptics_mt_state mt_state; }; struct synaptics_data { -- cgit v1.2.3-70-g09d2 From 4dc772d274abdedcccbcebab42d4bf0016ec2e80 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:02:40 -0700 Subject: Input: synaptics - process finger (<=3) transitions Synaptics image sensor touchpads track 5 fingers, but only report 2. This patch attempts to deal with some idiosyncrasies of these touchpads: * When there are 3 or more fingers, only two are reported. * The touchpad tracks the 5 fingers in slot[0] through slot[4]. * It always reports the lowest and highest valid slots in SGM and AGM packets, respectively. * The number of fingers is only reported in the SGM packet. However, the number of fingers can change either before or after an AGM packet. * Thus, if an SGM reports a different number of fingers than the last SGM, it is impossible to tell whether the intervening AGM corresponds to the old number of fingers or the new number of fingers. * For example, when going from 2->3 fingers, it is not possible to tell whether tell AGM contains slot[1] (old 2nd finger) or slot[2] (new 3rd finger). * When fingers are added one at at time, from 1->2->3, it is possible to track which slots are contained in the SGM and AGM packets: 1 finger: SGM = slot[0], no AGM 2 fingers: SGM = slot[0], AGM = slot[1] 3 fingers: SGM = slot[0], AGM = slot[2] * It is also possible to track which slot is contained in the SGM when 1 of 2 fingers is removed. This is because the touchpad sends a special (0,0,0) AGM packet whenever all fingers are removed except slot[0]: Last AGM == (0,0,0): SGM contains slot[1] Else: SGM contains slot[0] * However, once there are 3 fingers, if exactly 1 finger is removed, it is impossible to tell which 2 slots are contained in SGM and AGM. The (SGM,AGM) could be (0,1), (0,2), or (1,2). There is no way to know. * Similarly, if two fingers are simultaneously removed (3->1), then it is only possible to know if SGM still contains slot[0]. * Since it is not possible to reliably track which slot is being reported, we invalidate the tracking_id every time the number of fingers changes until this ambiguity is resolved when: a) All fingers are removed. b) 4 or 5 fingers are touched, generates an AGM-CONTACT packet. c) All fingers are removed except slot[0]. In this special case, the ambiguity is resolved since by the (0,0,0) AGM packet. Behavior of the driver: When 2 or more fingers are present on the touchpad, the kernel reports up to two MT-B slots containing the position data for two of the fingers reported by the touchpad. If the identity of a finger cannot be tracked when the number-of-fingers changes, the corresponding MT-B slot will be invalidated (track_id set to -1), and a new track_id will be assigned in a subsequent input event report. The driver always reports the total number of fingers using one of the EV_KEY/BTN_TOOL_*TAP events. This could differ from the number of valid MT-B slots for two reasons: a) There are more than 2 fingers on the pad. b) During ambiguous number-of-fingers transitions, the correct track_id for one or both of the slots cannot be determined, so the slots are invalidated. Thus, this is a hybrid singletouch/MT-B scheme. Userspace can detect this behavior by noting that the driver supports more EV_KEY/BTN_TOOL_*TAP events than its maximum EV_ABS/ABS_MT_SLOT. Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 290 +++++++++++++++++++++++++++++++++++++--- drivers/input/mouse/synaptics.h | 4 + 2 files changed, 278 insertions(+), 16 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index a7af8565e2d..aec9cf7124f 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -453,6 +453,9 @@ static void synaptics_parse_agm(const unsigned char buf[], default: break; } + + /* Record that at least one AGM has been received since last SGM */ + priv->agm_pending = true; } static int synaptics_parse_hw_state(const unsigned char buf[], @@ -606,26 +609,53 @@ static void synaptics_report_slot(struct input_dev *dev, int slot, } static void synaptics_report_mt_data(struct psmouse *psmouse, - int count, + struct synaptics_mt_state *mt_state, const struct synaptics_hw_state *sgm) { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; struct synaptics_hw_state *agm = &priv->agm; + struct synaptics_mt_state *old = &priv->mt_state; - switch (count) { + switch (mt_state->count) { case 0: synaptics_report_slot(dev, 0, NULL); synaptics_report_slot(dev, 1, NULL); break; case 1: - synaptics_report_slot(dev, 0, sgm); - synaptics_report_slot(dev, 1, NULL); + if (mt_state->sgm == -1) { + synaptics_report_slot(dev, 0, NULL); + synaptics_report_slot(dev, 1, NULL); + } else if (mt_state->sgm == 0) { + synaptics_report_slot(dev, 0, sgm); + synaptics_report_slot(dev, 1, NULL); + } else { + synaptics_report_slot(dev, 0, NULL); + synaptics_report_slot(dev, 1, sgm); + } break; - case 2: - case 3: /* Fall-through case */ - synaptics_report_slot(dev, 0, sgm); - synaptics_report_slot(dev, 1, agm); + default: + /* + * If the finger slot contained in SGM is valid, and either + * hasn't changed, or is new, then report SGM in MTB slot 0. + * Otherwise, empty MTB slot 0. + */ + if (mt_state->sgm != -1 && + (mt_state->sgm == old->sgm || old->sgm == -1)) + synaptics_report_slot(dev, 0, sgm); + else + synaptics_report_slot(dev, 0, NULL); + + /* + * If the finger slot contained in AGM is valid, and either + * hasn't changed, or is new, then report AGM in MTB slot 1. + * Otherwise, empty MTB slot 1. + */ + if (mt_state->agm != -1 && + (mt_state->agm == old->agm || old->agm == -1)) + synaptics_report_slot(dev, 1, agm); + else + synaptics_report_slot(dev, 1, NULL); break; } @@ -633,29 +663,257 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, input_mt_report_pointer_emulation(dev, false); /* Send the number of fingers reported by touchpad itself. */ - input_mt_report_finger_count(dev, count); + input_mt_report_finger_count(dev, mt_state->count); synaptics_report_buttons(psmouse, sgm); input_sync(dev); } +/* Handle case where mt_state->count = 0 */ +static void synaptics_image_sensor_0f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + synaptics_mt_state_set(mt_state, 0, -1, -1); + priv->mt_state_lost = false; +} + +/* Handle case where mt_state->count = 1 */ +static void synaptics_image_sensor_1f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + struct synaptics_hw_state *agm = &priv->agm; + struct synaptics_mt_state *old = &priv->mt_state; + + /* + * If the last AGM was (0,0,0), and there is only one finger left, + * then we absolutely know that SGM contains slot 0, and all other + * fingers have been removed. + */ + if (priv->agm_pending && agm->z == 0) { + synaptics_mt_state_set(mt_state, 1, 0, -1); + priv->mt_state_lost = false; + return; + } + + switch (old->count) { + case 0: + synaptics_mt_state_set(mt_state, 1, 0, -1); + break; + case 1: + /* + * If mt_state_lost, then the previous transition was 3->1, + * and SGM now contains either slot 0 or 1, but we don't know + * which. So, we just assume that the SGM now contains slot 1. + * + * If pending AGM and either: + * (a) the previous SGM slot contains slot 0, or + * (b) there was no SGM slot + * then, the SGM now contains slot 1 + * + * Case (a) happens with very rapid "drum roll" gestures, where + * slot 0 finger is lifted and a new slot 1 finger touches + * within one reporting interval. + * + * Case (b) happens if initially two or more fingers tap + * briefly, and all but one lift before the end of the first + * reporting interval. + * + * (In both these cases, slot 0 will becomes empty, so SGM + * contains slot 1 with the new finger) + * + * Else, if there was no previous SGM, it now contains slot 0. + * + * Otherwise, SGM still contains the same slot. + */ + if (priv->mt_state_lost || + (priv->agm_pending && old->sgm <= 0)) + synaptics_mt_state_set(mt_state, 1, 1, -1); + else if (old->sgm == -1) + synaptics_mt_state_set(mt_state, 1, 0, -1); + break; + case 2: + /* + * If mt_state_lost, we don't know which finger SGM contains. + * + * So, report 1 finger, but with both slots empty. + * We will use slot 1 on subsequent 1->1 + */ + if (priv->mt_state_lost) { + synaptics_mt_state_set(mt_state, 1, -1, -1); + break; + } + /* + * Since the last AGM was NOT (0,0,0), it was the finger in + * slot 0 that has been removed. + * So, SGM now contains previous AGM's slot, and AGM is now + * empty. + */ + synaptics_mt_state_set(mt_state, 1, old->agm, -1); + break; + case 3: + /* + * Since last AGM was not (0,0,0), we don't know which finger + * is left. + * + * So, report 1 finger, but with both slots empty. + * We will use slot 1 on subsequent 1->1 + */ + synaptics_mt_state_set(mt_state, 1, -1, -1); + priv->mt_state_lost = true; + break; + } +} + +/* Handle case where mt_state->count = 2 */ +static void synaptics_image_sensor_2f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + struct synaptics_mt_state *old = &priv->mt_state; + + switch (old->count) { + case 0: + synaptics_mt_state_set(mt_state, 2, 0, 1); + break; + case 1: + /* + * If previous SGM contained slot 1 or higher, SGM now contains + * slot 0 (the newly touching finger) and AGM contains SGM's + * previous slot. + * + * Otherwise, SGM still contains slot 0 and AGM now contains + * slot 1. + */ + if (old->sgm >= 1) + synaptics_mt_state_set(mt_state, 2, 0, old->sgm); + else + synaptics_mt_state_set(mt_state, 2, 0, 1); + break; + case 2: + /* + * If mt_state_lost, SGM now contains either finger 1 or 2, but + * we don't know which. + * So, we just assume that the SGM contains slot 0 and AGM 1. + */ + if (priv->mt_state_lost) + synaptics_mt_state_set(mt_state, 2, 0, 1); + /* + * Otherwise, use the same mt_state, since it either hasn't + * changed, or was updated by a recently received AGM-CONTACT + * packet. + */ + break; + case 3: + /* + * 3->2 transitions have two unsolvable problems: + * 1) no indication is given which finger was removed + * 2) no way to tell if agm packet was for finger 3 + * before 3->2, or finger 2 after 3->2. + * + * So, report 2 fingers, but empty all slots. + * We will guess slots [0,1] on subsequent 2->2. + */ + synaptics_mt_state_set(mt_state, 2, -1, -1); + priv->mt_state_lost = true; + break; + } +} + +/* Handle case where mt_state->count = 3 */ +static void synaptics_image_sensor_3f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + struct synaptics_mt_state *old = &priv->mt_state; + + switch (old->count) { + case 0: + synaptics_mt_state_set(mt_state, 3, 0, 2); + break; + case 1: + /* + * If previous SGM contained slot 2 or higher, SGM now contains + * slot 0 (one of the newly touching fingers) and AGM contains + * SGM's previous slot. + * + * Otherwise, SGM now contains slot 0 and AGM contains slot 2. + */ + if (old->sgm >= 2) + synaptics_mt_state_set(mt_state, 3, 0, old->sgm); + else + synaptics_mt_state_set(mt_state, 3, 0, 2); + break; + case 2: + /* + * After some 3->1 and all 3->2 transitions, we lose track + * of which slot is reported by SGM and AGM. + * + * For 2->3 in this state, report 3 fingers, but empty all + * slots, and we will guess (0,2) on a subsequent 0->3. + * + * To userspace, the resulting transition will look like: + * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2] + */ + if (priv->mt_state_lost) { + synaptics_mt_state_set(mt_state, 3, -1, -1); + break; + } + + /* + * If the (SGM,AGM) really previously contained slots (0, 1), + * then we cannot know what slot was just reported by the AGM, + * because the 2->3 transition can occur either before or after + * the AGM packet. Thus, this most recent AGM could contain + * either the same old slot 1 or the new slot 2. + * Subsequent AGMs will be reporting slot 2. + * + * To userspace, the resulting transition will look like: + * 2:[0,1] -> 3:[0,-1] -> 3:[0,2] + */ + synaptics_mt_state_set(mt_state, 3, 0, -1); + break; + case 3: + /* + * If, for whatever reason, the previous agm was invalid, + * Assume SGM now contains slot 0, AGM now contains slot 2. + */ + if (old->agm <= 2) + synaptics_mt_state_set(mt_state, 3, 0, 2); + /* + * mt_state either hasn't changed, or was updated by a recently + * received AGM-CONTACT packet. + */ + break; + } +} + static void synaptics_image_sensor_process(struct psmouse *psmouse, struct synaptics_hw_state *sgm) { - int count; + struct synaptics_data *priv = psmouse->private; + struct synaptics_hw_state *agm = &priv->agm; + struct synaptics_mt_state mt_state; + /* Initialize using current mt_state (as updated by last agm) */ + mt_state = agm->mt_state; + + /* + * Update mt_state using the new finger count and current mt_state. + */ if (sgm->z == 0) - count = 0; + synaptics_image_sensor_0f(priv, &mt_state); else if (sgm->w >= 4) - count = 1; + synaptics_image_sensor_1f(priv, &mt_state); else if (sgm->w == 0) - count = 2; - else - count = 3; + synaptics_image_sensor_2f(priv, &mt_state); + else if (sgm->w == 1) + synaptics_image_sensor_3f(priv, &mt_state); /* Send resulting input events to user space */ - synaptics_report_mt_data(psmouse, count, sgm); + synaptics_report_mt_data(psmouse, &mt_state, sgm); + + /* Store updated mt_state */ + priv->mt_state = agm->mt_state = mt_state; + priv->agm_pending = false; } /* diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 20f57dfebed..622aea8dd7e 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -161,11 +161,15 @@ struct synaptics_data { struct serio *pt_port; /* Pass-through serio port */ + struct synaptics_mt_state mt_state; /* Current mt finger state */ + bool mt_state_lost; /* mt_state may be incorrect */ + /* * Last received Advanced Gesture Mode (AGM) packet. An AGM packet * contains position data for a second contact, at half resolution. */ struct synaptics_hw_state agm; + bool agm_pending; /* new AGM packet received */ }; void synaptics_module_init(void); -- cgit v1.2.3-70-g09d2 From d5051272fc4860e056e34c92080369a1b63c9378 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:02:48 -0700 Subject: Input: add BTN_TOOL_QUINTTAP for reporting 5 fingers on touchpad "4-finger scroll" is a gesture supported by some applications and operating systems. "Resting thumb" is when a clickpad user rests a finger (e.g., a thumb), in a "click zone" (typically the bottom of the touchpad) in anticipation of click+move=select gestures. Thus, "4-finger scroll + resting thumb" is a 5-finger gesture. To allow userspace to detect this gesture, we send BTN_TOOL_QUINTTAP. Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/input-mt.c | 1 + include/linux/input.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index c48c81f0308..9150ee78e00 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -117,6 +117,7 @@ void input_mt_report_finger_count(struct input_dev *dev, int count) input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2); input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3); input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4); + input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5); } EXPORT_SYMBOL(input_mt_report_finger_count); diff --git a/include/linux/input.h b/include/linux/input.h index 068784e1797..4de4b4661f8 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -503,6 +503,7 @@ struct input_keymap_entry { #define BTN_TOOL_FINGER 0x145 #define BTN_TOOL_MOUSE 0x146 #define BTN_TOOL_LENS 0x147 +#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ #define BTN_TOUCH 0x14a #define BTN_STYLUS 0x14b #define BTN_STYLUS2 0x14c -- cgit v1.2.3-70-g09d2 From 6b4b49fea15ea3034e22ad4ca85f23c000b88e92 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Tue, 23 Aug 2011 23:02:56 -0700 Subject: Input: synaptics - process finger (<=5) transitions Synaptics image sensor touchpads track up to 5 fingers, but only report 2. They use a special "TYPE=2" (AGM-CONTACT) packet type that reports the number of tracked fingers and which finger is reported in the SGM and AGM packets. With this new packet type, it is possible to tell userspace when 4 or 5 fingers are touching. Signed-off-by: Daniel Kurtz Acked-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 45 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index aec9cf7124f..30c85a5b718 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -762,6 +762,10 @@ static void synaptics_image_sensor_1f(struct synaptics_data *priv, synaptics_mt_state_set(mt_state, 1, -1, -1); priv->mt_state_lost = true; break; + case 4: + case 5: + /* mt_state was updated by AGM-CONTACT packet */ + break; } } @@ -816,6 +820,10 @@ static void synaptics_image_sensor_2f(struct synaptics_data *priv, synaptics_mt_state_set(mt_state, 2, -1, -1); priv->mt_state_lost = true; break; + case 4: + case 5: + /* mt_state was updated by AGM-CONTACT packet */ + break; } } @@ -843,6 +851,22 @@ static void synaptics_image_sensor_3f(struct synaptics_data *priv, synaptics_mt_state_set(mt_state, 3, 0, 2); break; case 2: + /* + * If the AGM previously contained slot 3 or higher, then the + * newly touching finger is in the lowest available slot. + * + * If SGM was previously 1 or higher, then the new SGM is + * now slot 0 (with a new finger), otherwise, the new finger + * is now in a hidden slot between 0 and AGM's slot. + * + * In all such cases, the SGM now contains slot 0, and the AGM + * continues to contain the same slot as before. + */ + if (old->agm >= 3) { + synaptics_mt_state_set(mt_state, 3, 0, old->agm); + break; + } + /* * After some 3->1 and all 3->2 transitions, we lose track * of which slot is reported by SGM and AGM. @@ -883,9 +907,22 @@ static void synaptics_image_sensor_3f(struct synaptics_data *priv, * received AGM-CONTACT packet. */ break; + + case 4: + case 5: + /* mt_state was updated by AGM-CONTACT packet */ + break; } } +/* Handle case where mt_state->count = 4, or = 5 */ +static void synaptics_image_sensor_45f(struct synaptics_data *priv, + struct synaptics_mt_state *mt_state) +{ + /* mt_state was updated correctly by AGM-CONTACT packet */ + priv->mt_state_lost = false; +} + static void synaptics_image_sensor_process(struct psmouse *psmouse, struct synaptics_hw_state *sgm) { @@ -905,8 +942,10 @@ static void synaptics_image_sensor_process(struct psmouse *psmouse, synaptics_image_sensor_1f(priv, &mt_state); else if (sgm->w == 0) synaptics_image_sensor_2f(priv, &mt_state); - else if (sgm->w == 1) + else if (sgm->w == 1 && mt_state.count <= 3) synaptics_image_sensor_3f(priv, &mt_state); + else + synaptics_image_sensor_45f(priv, &mt_state); /* Send resulting input events to user space */ synaptics_report_mt_data(psmouse, &mt_state, sgm); @@ -1110,6 +1149,10 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ABS_MT_POSITION_Y); /* Image sensors can report per-contact pressure */ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + + /* Image sensors can signal 4 and 5 finger clicks */ + __set_bit(BTN_TOOL_QUADTAP, dev->keybit); + __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { /* Non-image sensors with AGM use semi-mt */ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); -- cgit v1.2.3-70-g09d2 From 6a20baa9a40116715ebc99afe5b79b92f637ec23 Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Tue, 23 Aug 2011 23:15:29 -0700 Subject: Input: ad714x-i2c - change placement of __init/__exit annotations Change the placement of __init and __exit annotations to be consistent with the rest of the drivers. Signed-off-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ad714x-i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index e21deb1baa8..45a6c9168f0 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -121,13 +121,13 @@ static struct i2c_driver ad714x_i2c_driver = { .id_table = ad714x_id, }; -static __init int ad714x_i2c_init(void) +static int __init ad714x_i2c_init(void) { return i2c_add_driver(&ad714x_i2c_driver); } module_init(ad714x_i2c_init); -static __exit void ad714x_i2c_exit(void) +static void __exit ad714x_i2c_exit(void) { i2c_del_driver(&ad714x_i2c_driver); } -- cgit v1.2.3-70-g09d2 From 377dc5538c43052d2ee9bc89577cb07fe18f2520 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 25 Aug 2011 00:25:12 -0700 Subject: Input: tsc2007 - convert to threaded IRQ Instead of using hard IRQ and workqueue solution switch to using threaded interrupt handler to simplify the code and locking rules. Tested-by: Thierry Reding Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 150 ++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 84 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index fadc11545b1..e3aaf50ee8d 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -66,7 +66,6 @@ struct ts_event { struct tsc2007 { struct input_dev *input; char phys[32]; - struct delayed_work work; struct i2c_client *client; @@ -76,9 +75,11 @@ struct tsc2007 { unsigned long poll_delay; unsigned long poll_period; - bool pendown; int irq; + wait_queue_head_t wait; + bool stopped; + int (*get_pendown_state)(void); void (*clear_penirq)(void); }; @@ -141,25 +142,8 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) return rt; } -static void tsc2007_send_up_event(struct tsc2007 *tsc) -{ - struct input_dev *input = tsc->input; - - dev_dbg(&tsc->client->dev, "UP\n"); - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); -} - -static void tsc2007_work(struct work_struct *work) +static bool tsc2007_is_pen_down(struct tsc2007 *ts) { - struct tsc2007 *ts = - container_of(to_delayed_work(work), struct tsc2007, work); - bool debounced = false; - struct ts_event tc; - u32 rt; - /* * NOTE: We can't rely on the pressure to determine the pen down * state, even though this controller has a pressure sensor. @@ -170,79 +154,82 @@ static void tsc2007_work(struct work_struct *work) * The only safe way to check for the pen up condition is in the * work function by reading the pen signal state (it's a GPIO * and IRQ). Unfortunately such callback is not always available, - * in that case we have rely on the pressure anyway. + * in that case we assume that the pen is down and expect caller + * to fall back on the pressure reading. */ - if (ts->get_pendown_state) { - if (unlikely(!ts->get_pendown_state())) { - tsc2007_send_up_event(ts); - ts->pendown = false; - goto out; - } - dev_dbg(&ts->client->dev, "pen is still down\n"); - } + if (!ts->get_pendown_state) + return true; - tsc2007_read_values(ts, &tc); + return ts->get_pendown_state(); +} - rt = tsc2007_calculate_pressure(ts, &tc); - if (rt > ts->max_rt) { - /* - * Sample found inconsistent by debouncing or pressure is - * beyond the maximum. Don't report it to user space, - * repeat at least once more the measurement. - */ - dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - debounced = true; - goto out; +static irqreturn_t tsc2007_soft_irq(int irq, void *handle) +{ + struct tsc2007 *ts = handle; + struct input_dev *input = ts->input; + struct ts_event tc; + u32 rt; - } + while (!ts->stopped && tsc2007_is_pen_down(ts)) { + + /* pen is down, continue with the measurement */ + tsc2007_read_values(ts, &tc); - if (rt) { - struct input_dev *input = ts->input; + rt = tsc2007_calculate_pressure(ts, &tc); - if (!ts->pendown) { - dev_dbg(&ts->client->dev, "DOWN\n"); + if (rt == 0 && !ts->get_pendown_state) { + /* + * If pressure reported is 0 and we don't have + * callback to check pendown state, we have to + * assume that pen was lifted up. + */ + break; + } + + if (rt <= ts->max_rt) { + dev_dbg(&ts->client->dev, + "DOWN point(%4d,%4d), pressure (%4u)\n", + tc.x, tc.y, rt); input_report_key(input, BTN_TOUCH, 1); - ts->pendown = true; + input_report_abs(input, ABS_X, tc.x); + input_report_abs(input, ABS_Y, tc.y); + input_report_abs(input, ABS_PRESSURE, rt); + + input_sync(input); + + } else { + /* + * Sample found inconsistent by debouncing or pressure is + * beyond the maximum. Don't report it to user space, + * repeat at least once more the measurement. + */ + dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); } - input_report_abs(input, ABS_X, tc.x); - input_report_abs(input, ABS_Y, tc.y); - input_report_abs(input, ABS_PRESSURE, rt); + wait_event_timeout(ts->wait, ts->stopped, + msecs_to_jiffies(ts->poll_period)); + } - input_sync(input); + dev_dbg(&ts->client->dev, "UP\n"); - dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", - tc.x, tc.y, rt); + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); - } else if (!ts->get_pendown_state && ts->pendown) { - /* - * We don't have callback to check pendown state, so we - * have to assume that since pressure reported is 0 the - * pen was lifted up. - */ - tsc2007_send_up_event(ts); - ts->pendown = false; - } + if (ts->clear_penirq) + ts->clear_penirq(); - out: - if (ts->pendown || debounced) - schedule_delayed_work(&ts->work, - msecs_to_jiffies(ts->poll_period)); - else - enable_irq(ts->irq); + return IRQ_HANDLED; } -static irqreturn_t tsc2007_irq(int irq, void *handle) +static irqreturn_t tsc2007_hard_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - if (!ts->get_pendown_state || likely(ts->get_pendown_state())) { - disable_irq_nosync(ts->irq); - schedule_delayed_work(&ts->work, - msecs_to_jiffies(ts->poll_delay)); - } + if (!ts->get_pendown_state || likely(ts->get_pendown_state())) + return IRQ_WAKE_THREAD; if (ts->clear_penirq) ts->clear_penirq(); @@ -252,15 +239,10 @@ static irqreturn_t tsc2007_irq(int irq, void *handle) static void tsc2007_free_irq(struct tsc2007 *ts) { + ts->stopped = true; + mb(); + wake_up(&ts->wait); free_irq(ts->irq, ts); - if (cancel_delayed_work_sync(&ts->work)) { - /* - * Work was pending, therefore we need to enable - * IRQ here to balance the disable_irq() done in the - * interrupt handler. - */ - enable_irq(ts->irq); - } } static int __devinit tsc2007_probe(struct i2c_client *client, @@ -290,7 +272,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client, ts->client = client; ts->irq = client->irq; ts->input = input_dev; - INIT_DELAYED_WORK(&ts->work, tsc2007_work); + init_waitqueue_head(&ts->wait); ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; @@ -318,8 +300,8 @@ static int __devinit tsc2007_probe(struct i2c_client *client, if (pdata->init_platform_hw) pdata->init_platform_hw(); - err = request_irq(ts->irq, tsc2007_irq, 0, - client->dev.driver->name, ts); + err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, + IRQF_ONESHOT, client->dev.driver->name, ts); if (err < 0) { dev_err(&client->dev, "irq %d busy?\n", ts->irq); goto err_free_mem; -- cgit v1.2.3-70-g09d2 From d3654d7ef3adad0083525cfb6fe27be62cb83d0d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 25 Aug 2011 01:05:46 -0700 Subject: Input: tsc2007 - add open and close methods This will ensure that the device delivers input events only when there are users. Tested-by: Thierry Reding Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 46 ++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index e3aaf50ee8d..0acca68cc52 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -237,12 +237,40 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle) return IRQ_HANDLED; } -static void tsc2007_free_irq(struct tsc2007 *ts) +static void tsc2007_stop(struct tsc2007 *ts) { ts->stopped = true; mb(); wake_up(&ts->wait); - free_irq(ts->irq, ts); + + disable_irq(ts->irq); +} + +static int tsc2007_open(struct input_dev *input_dev) +{ + struct tsc2007 *ts = input_get_drvdata(input_dev); + int err; + + ts->stopped = false; + mb(); + + enable_irq(ts->irq); + + /* Prepare for touch readings - power down ADC and enable PENIRQ */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) { + tsc2007_stop(ts); + return err; + } + + return 0; +} + +static void tsc2007_close(struct input_dev *input_dev) +{ + struct tsc2007 *ts = input_get_drvdata(input_dev); + + tsc2007_stop(ts); } static int __devinit tsc2007_probe(struct i2c_client *client, @@ -289,6 +317,11 @@ static int __devinit tsc2007_probe(struct i2c_client *client, input_dev->phys = ts->phys; input_dev->id.bustype = BUS_I2C; + input_dev->open = tsc2007_open; + input_dev->close = tsc2007_close; + + input_set_drvdata(input_dev, ts); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); @@ -307,10 +340,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client, goto err_free_mem; } - /* Prepare for touch readings - power down ADC and enable PENIRQ */ - err = tsc2007_xfer(ts, PWRDOWN); - if (err < 0) - goto err_free_irq; + tsc2007_stop(ts); err = input_register_device(input_dev); if (err) @@ -321,7 +351,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client, return 0; err_free_irq: - tsc2007_free_irq(ts); + free_irq(ts->irq, ts); if (pdata->exit_platform_hw) pdata->exit_platform_hw(); err_free_mem: @@ -335,7 +365,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client) struct tsc2007 *ts = i2c_get_clientdata(client); struct tsc2007_platform_data *pdata = client->dev.platform_data; - tsc2007_free_irq(ts); + free_irq(ts->irq, ts); if (pdata->exit_platform_hw) pdata->exit_platform_hw(); -- cgit v1.2.3-70-g09d2 From 5d7e7d479856f23eebc272128905a7ecada367fb Mon Sep 17 00:00:00 2001 From: Eduard Hasenleithner Date: Wed, 7 Sep 2011 14:08:54 -0700 Subject: Input: wacom - add Intuos4 LED and OLED control This commit enables control of the LEDs and OLED displays found on the Wacom Intuos4 M, L, and XL. For this purpose, a new "wacom_led" attribute group is added to the sysfs entry of the USB device. This "wacom_led" group only shows up when the correct device (M, L, or XL) is detected. The attributes are described in Documentation/ABI/testing/sysfs-wacom Signed-off-by: Eduard Hasenleithner Signed-off-by: Dmitry Torokhov --- Documentation/ABI/testing/sysfs-driver-wacom | 64 ++++++ Documentation/ABI/testing/sysfs-wacom | 10 - drivers/input/tablet/wacom.h | 6 + drivers/input/tablet/wacom_sys.c | 301 ++++++++++++++++++++++++--- 4 files changed, 341 insertions(+), 40 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-wacom delete mode 100644 Documentation/ABI/testing/sysfs-wacom (limited to 'drivers/input') diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom new file mode 100644 index 00000000000..dfe1d460cf5 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -0,0 +1,64 @@ +What: /sys/class/hidraw/hidraw*/device/speed +Date: April 2010 +Kernel Version: 2.6.35 +Contact: linux-bluetooth@vger.kernel.org +Description: + The /sys/class/hidraw/hidraw*/device/speed file controls + reporting speed of Wacom bluetooth tablet. Reading from + this file returns 1 if tablet reports in high speed mode + or 0 otherwise. Writing to this file one of these values + switches reporting speed. + +What: /sys/bus/usb/devices/-:./wacom_led/led +Date: August 2011 +Contact: linux-input@vger.kernel.org +Description: + Attribute group for control of the status LEDs and the OLED + displays found on the Wacom Intuos 4 M, L, and XL tablets. This + attribute group is not available for other Wacom tablets. + Therefore its presence implicitly signifies the presence of + said LEDs and OLED displays on the tablet device. + +What: /sys/bus/usb/devices/-:./wacom_led/status0_luminance +Date: August 2011 +Contact: linux-input@vger.kernel.org +Description: + Writing to this file sets the status LED luminance (0..127) + when the stylus does not touch the tablet surface, and no + button is pressed on the stylus. + +What: /sys/bus/usb/devices/-:./wacom_led/status1_luminance +Date: August 2011 +Contact: linux-input@vger.kernel.org +Description: + Writing to this file sets the status LED luminance (0..127) + when the stylus touches the tablet surface, or any button is + pressed on the stylus. + +What: /sys/bus/usb/devices/-:./wacom_led/status_led_select +Date: August 2011 +Contact: linux-input@vger.kernel.org +Description: + Writing to this file sets which one of the four status LEDs is + active (0..3). The other three LEDs are always inactive. By + means of specifying "-1" it is possible to set all status LEDs + to inactive. + +What: /sys/bus/usb/devices/-:./wacom_led/buttons_luminance +Date: August 2011 +Contact: linux-input@vger.kernel.org +Description: + Writing to this file sets the overall luminance level (0..15) + of all eight button OLED displays. + +What: /sys/bus/usb/devices/-:./wacom_led/button_rawimg +Date: August 2011 +Contact: linux-input@vger.kernel.org +Description: + When writing a 1024 byte raw image in Wacom Intuos 4 + interleaving format to the file, the image shows up on Button N + of the device. The image is a 64x32 pixel 4-bit gray image. The + 1024 byte binary is split up into 16x 64 byte chunks. Each 64 + byte chunk encodes the image data for two consecutive lines on + the display. The low nibble of each byte contains the first + line, and the high nibble contains the second line. diff --git a/Documentation/ABI/testing/sysfs-wacom b/Documentation/ABI/testing/sysfs-wacom deleted file mode 100644 index 1517976e25c..00000000000 --- a/Documentation/ABI/testing/sysfs-wacom +++ /dev/null @@ -1,10 +0,0 @@ -What: /sys/class/hidraw/hidraw*/device/speed -Date: April 2010 -Kernel Version: 2.6.35 -Contact: linux-bluetooth@vger.kernel.org -Description: - The /sys/class/hidraw/hidraw*/device/speed file controls - reporting speed of wacom bluetooth tablet. Reading from - this file returns 1 if tablet reports in high speed mode - or 0 otherwise. Writing to this file one of these values - switches reporting speed. diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 23317bd09c8..00332d66bc4 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -114,6 +114,12 @@ struct wacom { struct mutex lock; bool open; char phys[32]; + struct wacom_led { + u8 select; /* status led selector (0..3, -1=none) */ + u8 llv; /* status led brightness no button */ + u8 hlv; /* status led brightness button pressed */ + u8 img_lum; /* OLED matrix display brightness */ + } led; }; extern const struct usb_device_id wacom_ids[]; diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index d27c9d91630..0eccf57df5c 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -48,27 +48,49 @@ struct hid_descriptor { /* defines to get/set USB message */ #define USB_REQ_GET_REPORT 0x01 #define USB_REQ_SET_REPORT 0x09 + #define WAC_HID_FEATURE_REPORT 0x03 #define WAC_MSG_RETRIES 5 -static int usb_get_report(struct usb_interface *intf, unsigned char type, - unsigned char id, void *buf, int size) +#define WAC_CMD_LED_CONTROL 0x20 +#define WAC_CMD_ICON_START 0x21 +#define WAC_CMD_ICON_XFER 0x23 +#define WAC_CMD_RETRIES 10 + +static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id, + void *buf, size_t size, unsigned int retries) { - return usb_control_msg(interface_to_usbdev(intf), - usb_rcvctrlpipe(interface_to_usbdev(intf), 0), - USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, - buf, size, 100); + struct usb_device *dev = interface_to_usbdev(intf); + int retval; + + do { + retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, + intf->altsetting[0].desc.bInterfaceNumber, + buf, size, 100); + } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); + + return retval; } -static int usb_set_report(struct usb_interface *intf, unsigned char type, - unsigned char id, void *buf, int size) +static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id, + void *buf, size_t size, unsigned int retries) { - return usb_control_msg(interface_to_usbdev(intf), - usb_sndctrlpipe(interface_to_usbdev(intf), 0), - USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, - buf, size, 1000); + struct usb_device *dev = interface_to_usbdev(intf); + int retval; + + do { + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, + intf->altsetting[0].desc.bInterfaceNumber, + buf, size, 1000); + } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); + + return retval; } static void wacom_sys_irq(struct urb *urb) @@ -333,23 +355,23 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat rep_data[2] = 0; rep_data[3] = 0; report_id = 3; - error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, - report_id, rep_data, 4); + error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, + report_id, rep_data, 4, 1); if (error >= 0) - error = usb_get_report(intf, - WAC_HID_FEATURE_REPORT, report_id, - rep_data, 4); + error = wacom_get_report(intf, + WAC_HID_FEATURE_REPORT, + report_id, rep_data, 4, 1); } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); } else if (features->type != TABLETPC) { do { rep_data[0] = 2; rep_data[1] = 2; - error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, - report_id, rep_data, 2); + error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, + report_id, rep_data, 2, 1); if (error >= 0) - error = usb_get_report(intf, - WAC_HID_FEATURE_REPORT, report_id, - rep_data, 2); + error = wacom_get_report(intf, + WAC_HID_FEATURE_REPORT, + report_id, rep_data, 2, 1); } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); } @@ -468,6 +490,220 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom) } } +static int wacom_led_control(struct wacom *wacom) +{ + unsigned char *buf; + int retval; + + buf = kzalloc(9, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = WAC_CMD_LED_CONTROL; + buf[1] = wacom->led.select >= 0 ? wacom->led.select | 4 : 0; + buf[2] = wacom->led.llv; + buf[3] = wacom->led.hlv; + buf[4] = wacom->led.img_lum; + + retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL, + buf, 9, WAC_CMD_RETRIES); + kfree(buf); + + return retval; +} + +static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img) +{ + unsigned char *buf; + int i, retval; + + buf = kzalloc(259, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Send 'start' command */ + buf[0] = WAC_CMD_ICON_START; + buf[1] = 1; + retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, + buf, 2, WAC_CMD_RETRIES); + if (retval < 0) + goto out; + + buf[0] = WAC_CMD_ICON_XFER; + buf[1] = button_id & 0x07; + for (i = 0; i < 4; i++) { + buf[2] = i; + memcpy(buf + 3, img + i * 256, 256); + + retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER, + buf, 259, WAC_CMD_RETRIES); + if (retval < 0) + break; + } + + /* Send 'stop' */ + buf[0] = WAC_CMD_ICON_START; + buf[1] = 0; + wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, + buf, 2, WAC_CMD_RETRIES); + +out: + kfree(buf); + return retval; +} + +static ssize_t wacom_led_select_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wacom *wacom = dev_get_drvdata(dev); + unsigned int id; + int err; + + err = kstrtouint(buf, 10, &id); + if (err) + return err; + + mutex_lock(&wacom->lock); + + wacom->led.select = id; + err = wacom_led_control(wacom); + + mutex_unlock(&wacom->lock); + + return err < 0 ? err : count; +} + +static DEVICE_ATTR(status_led_select, S_IWUSR, NULL, wacom_led_select_store); + +static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest, + const char *buf, size_t count) +{ + unsigned int value; + int err; + + err = kstrtouint(buf, 10, &value); + if (err) + return err; + + mutex_lock(&wacom->lock); + + *dest = value & 0x7f; + err = wacom_led_control(wacom); + + mutex_unlock(&wacom->lock); + + return err < 0 ? err : count; +} + +#define DEVICE_LUMINANCE_ATTR(name, field) \ +static ssize_t wacom_##name##_luminance_store(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct wacom *wacom = dev_get_drvdata(dev); \ + \ + return wacom_luminance_store(wacom, &wacom->led.field, \ + buf, count); \ +} \ +static DEVICE_ATTR(name##_luminance, S_IWUSR, \ + NULL, wacom_##name##_luminance_store) + +DEVICE_LUMINANCE_ATTR(status0, llv); +DEVICE_LUMINANCE_ATTR(status1, hlv); +DEVICE_LUMINANCE_ATTR(buttons, img_lum); + +static ssize_t wacom_button_image_store(struct device *dev, int button_id, + const char *buf, size_t count) +{ + struct wacom *wacom = dev_get_drvdata(dev); + int err; + + if (count != 1024) + return -EINVAL; + + mutex_lock(&wacom->lock); + + err = wacom_led_putimage(wacom, button_id, buf); + + mutex_unlock(&wacom->lock); + + return err < 0 ? err : count; +} + +#define DEVICE_BTNIMG_ATTR(BUTTON_ID) \ +static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return wacom_button_image_store(dev, BUTTON_ID, buf, count); \ +} \ +static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR, \ + NULL, wacom_btnimg##BUTTON_ID##_store) + +DEVICE_BTNIMG_ATTR(0); +DEVICE_BTNIMG_ATTR(1); +DEVICE_BTNIMG_ATTR(2); +DEVICE_BTNIMG_ATTR(3); +DEVICE_BTNIMG_ATTR(4); +DEVICE_BTNIMG_ATTR(5); +DEVICE_BTNIMG_ATTR(6); +DEVICE_BTNIMG_ATTR(7); + +static struct attribute *wacom_led_attrs[] = { + &dev_attr_status0_luminance.attr, + &dev_attr_status1_luminance.attr, + &dev_attr_status_led_select.attr, + &dev_attr_buttons_luminance.attr, + &dev_attr_button0_rawimg.attr, + &dev_attr_button1_rawimg.attr, + &dev_attr_button2_rawimg.attr, + &dev_attr_button3_rawimg.attr, + &dev_attr_button4_rawimg.attr, + &dev_attr_button5_rawimg.attr, + &dev_attr_button6_rawimg.attr, + &dev_attr_button7_rawimg.attr, + NULL +}; + +static struct attribute_group wacom_led_attr_group = { + .name = "wacom_led", + .attrs = wacom_led_attrs, +}; + +static int wacom_initialize_leds(struct wacom *wacom) +{ + int error; + + if (wacom->wacom_wac.features.type >= INTUOS4 && + wacom->wacom_wac.features.type <= INTUOS4L) { + + /* Initialize default values */ + wacom->led.select = 0; + wacom->led.llv = 30; + wacom->led.hlv = 20; + wacom->led.img_lum = 10; + wacom_led_control(wacom); + + error = sysfs_create_group(&wacom->intf->dev.kobj, + &wacom_led_attr_group); + if (error) { + dev_err(&wacom->intf->dev, + "cannot create sysfs group err: %d\n", error); + return error; + } + } + + return 0; +} + +static void wacom_destroy_leds(struct wacom *wacom) +{ + if (wacom->wacom_wac.features.type >= INTUOS4 && + wacom->wacom_wac.features.type <= INTUOS4L) { + sysfs_remove_group(&wacom->intf->dev.kobj, + &wacom_led_attr_group); + } +} + static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); @@ -556,16 +792,21 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - error = input_register_device(input_dev); + error = wacom_initialize_leds(wacom); if (error) goto fail4; + error = input_register_device(input_dev); + if (error) + goto fail5; + /* Note that if query fails it is not a hard failure */ wacom_query_tablet_data(intf, features); usb_set_intfdata(intf, wacom); return 0; + fail5: wacom_destroy_leds(wacom); fail4: wacom_remove_shared_data(wacom_wac); fail3: usb_free_urb(wacom->irq); fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); @@ -582,6 +823,7 @@ static void wacom_disconnect(struct usb_interface *intf) usb_kill_urb(wacom->irq); input_unregister_device(wacom->wacom_wac.input); + wacom_destroy_leds(wacom); usb_free_urb(wacom->irq); usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, wacom->wacom_wac.data, wacom->data_dma); @@ -604,17 +846,16 @@ static int wacom_resume(struct usb_interface *intf) { struct wacom *wacom = usb_get_intfdata(intf); struct wacom_features *features = &wacom->wacom_wac.features; - int rv; + int rv = 0; mutex_lock(&wacom->lock); /* switch to wacom mode first */ wacom_query_tablet_data(intf, features); + wacom_led_control(wacom); - if (wacom->open) - rv = usb_submit_urb(wacom->irq, GFP_NOIO); - else - rv = 0; + if (wacom->open && usb_submit_urb(wacom->irq, GFP_NOIO) < 0) + rv = -EIO; mutex_unlock(&wacom->lock); -- cgit v1.2.3-70-g09d2 From ec4665c46b11f6e444911ba73dddae6044dec909 Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Wed, 7 Sep 2011 14:04:16 -0700 Subject: Input: remove IRQF_DISABLED from drivers This flag is a NOOP and can be removed now. Signed-off-by: Yong Zhang Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5588-keys.c | 2 +- drivers/input/keyboard/davinci_keyscan.c | 2 +- drivers/input/keyboard/ep93xx_keypad.c | 2 +- drivers/input/keyboard/imx_keypad.c | 2 +- drivers/input/keyboard/jornada720_kbd.c | 2 +- drivers/input/keyboard/matrix_keypad.c | 1 - drivers/input/keyboard/pxa27x_keypad.c | 2 +- drivers/input/keyboard/pxa930_rotary.c | 2 +- drivers/input/keyboard/w90p910_keypad.c | 2 +- drivers/input/misc/ixp4xx-beeper.c | 2 +- drivers/input/mouse/pxa930_trkball.c | 2 +- drivers/input/mouse/synaptics_i2c.c | 2 +- drivers/input/touchscreen/atmel_tsadcc.c | 2 +- drivers/input/touchscreen/h3600_ts_input.c | 4 ++-- drivers/input/touchscreen/hp680_ts_input.c | 2 +- drivers/input/touchscreen/jornada720_ts.c | 2 +- drivers/input/touchscreen/lpc32xx_ts.c | 2 +- drivers/input/touchscreen/s3c2410_ts.c | 2 +- drivers/input/touchscreen/w90p910_ts.c | 2 +- 19 files changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 7b404e5443e..b570ed30e8a 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -550,7 +550,7 @@ static int __devinit adp5588_probe(struct i2c_client *client, } error = request_irq(client->irq, adp5588_irq, - IRQF_TRIGGER_FALLING | IRQF_DISABLED, + IRQF_TRIGGER_FALLING, client->dev.driver->name, kpad); if (error) { dev_err(&client->dev, "irq %d busy?\n", client->irq); diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index cd89d17162a..9d82b3aeff5 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -271,7 +271,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev) } error = request_irq(davinci_ks->irq, davinci_ks_interrupt, - IRQF_DISABLED, pdev->name, davinci_ks); + 0, pdev->name, davinci_ks); if (error < 0) { dev_err(dev, "unable to register davinci key scan interrupt\n"); goto fail5; diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index aa17e024d80..4662c5da801 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -323,7 +323,7 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) platform_set_drvdata(pdev, keypad); err = request_irq(keypad->irq, ep93xx_keypad_irq_handler, - IRQF_DISABLED, pdev->name, keypad); + 0, pdev->name, keypad); if (err) goto failed_free_dev; diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index d92c15c39e6..4b093faf578 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -510,7 +510,7 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev) /* Ensure that the keypad will stay dormant until opened */ imx_keypad_inhibit(keypad); - error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED, + error = request_irq(irq, imx_keypad_irq_handler, 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 2cd3e1d56ea..0aa6740e60d 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -129,7 +129,7 @@ static int __devinit jornada720_kbd_probe(struct platform_device *pdev) err = request_irq(IRQ_GPIO0, jornada720_kbd_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING, "jornadakbd", pdev); if (err) { printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b02e4268e18..e2ae657717e 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -343,7 +343,6 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev, for (i = 0; i < pdata->num_row_gpios; i++) { err = request_irq(gpio_to_irq(pdata->row_gpios[i]), matrix_keypad_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "matrix-keypad", keypad); diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 4b0ec35259a..eca6ae63de1 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -535,7 +535,7 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) input_dev->evbit[0] |= BIT_MASK(EV_REL); } - error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED, + error = request_irq(irq, pxa27x_keypad_irq_handler, 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index b7123a44b6e..35451bf780c 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -148,7 +148,7 @@ static int __devinit pxa930_rotary_probe(struct platform_device *pdev) r->input_dev = input_dev; input_set_drvdata(input_dev, r); - err = request_irq(irq, rotary_irq, IRQF_DISABLED, + err = request_irq(irq, rotary_irq, 0, "enhanced rotary", r); if (err) { dev_err(&pdev->dev, "failed to request IRQ\n"); diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index ee2bf6bcf29..318586dadac 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -203,7 +203,7 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) input_dev->keycode, input_dev->keybit); error = request_irq(keypad->irq, w90p910_keypad_irq_handler, - IRQF_DISABLED, pdev->name, keypad); + 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); goto failed_put_clk; diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 1f38302a595..302ab46ce75 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -111,7 +111,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev) input_dev->event = ixp4xx_spkr_event; err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt, - IRQF_DISABLED | IRQF_NO_SUSPEND, "ixp4xx-beeper", + IRQF_NO_SUSPEND, "ixp4xx-beeper", (void *) dev->id); if (err) goto err_free_device; diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index 6c5d84fcdea..ee3b0ca9d59 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -183,7 +183,7 @@ static int __devinit pxa930_trkball_probe(struct platform_device *pdev) /* held the module in reset, will be enabled in open() */ pxa930_trkball_disable(trkball); - error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED, + error = request_irq(irq, pxa930_trkball_interrupt, 0, pdev->name, trkball); if (error) { dev_err(&pdev->dev, "failed to request irq: %d\n", error); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index cba3c84d2f2..e28e9ce0f7e 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -570,7 +570,7 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client, "Requesting IRQ: %d\n", touch->client->irq); ret = request_irq(touch->client->irq, synaptics_i2c_irq, - IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_EDGE_FALLING, DRIVER_NAME, touch); if (ret) { dev_warn(&touch->client->dev, diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 432c69be6ac..122a8788365 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -229,7 +229,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) goto err_release_mem; } - err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, IRQF_DISABLED, + err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0, pdev->dev.driver->name, ts_dev); if (err) { dev_err(&pdev->dev, "failed to allocate irq.\n"); diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 211811ae552..6107e563e68 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE); if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler, - IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) { + IRQF_SHARED, "h3600_action", ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); err = -EBUSY; goto fail1; } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, - IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) { + IRQF_SHARED, "h3600_suspend", ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); err = -EBUSY; goto fail2; diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c index dd4e8f020b9..639a6044183 100644 --- a/drivers/input/touchscreen/hp680_ts_input.c +++ b/drivers/input/touchscreen/hp680_ts_input.c @@ -93,7 +93,7 @@ static int __init hp680_ts_init(void) hp680_ts_dev->phys = "hp680_ts/input0"; if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt, - IRQF_DISABLED, MODNAME, 0) < 0) { + 0, MODNAME, 0) < 0) { printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n", HP680_TS_IRQ); err = -EBUSY; diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 4b0a061811f..50076c2d59e 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -127,7 +127,7 @@ static int __devinit jornada720_ts_probe(struct platform_device *pdev) error = request_irq(IRQ_GPIO9, jornada720_ts_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING, "HP7XX Touchscreen driver", pdev); if (error) { printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n"); diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index dcf803f5a1f..0a484ed5295 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -276,7 +276,7 @@ static int __devinit lpc32xx_ts_probe(struct platform_device *pdev) input_set_drvdata(input, tsc); error = request_irq(tsc->irq, lpc32xx_ts_interrupt, - IRQF_DISABLED, pdev->name, tsc); + 0, pdev->name, tsc); if (error) { dev_err(&pdev->dev, "failed requesting interrupt\n"); goto err_put_clock; diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 8feb7f3c8be..64ce697a345 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -328,7 +328,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev) ts.shift = info->oversampling_shift; ts.features = platform_get_device_id(pdev)->driver_data; - ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED, + ret = request_irq(ts.irq_tc, stylus_irq, 0, "s3c2410_ts_pen", ts.input); if (ret) { dev_err(dev, "cannot get TC interrupt\n"); diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index 7a45d68c351..217aa51135c 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -279,7 +279,7 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) w90p910_ts->irq_num = platform_get_irq(pdev, 0); if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt, - IRQF_DISABLED, "w90p910ts", w90p910_ts)) { + 0, "w90p910ts", w90p910_ts)) { err = -EBUSY; goto fail4; } -- cgit v1.2.3-70-g09d2 From 9299c08d8bfc7256645f4bf3943f80d8943fe844 Mon Sep 17 00:00:00 2001 From: Harvey Yang Date: Thu, 8 Sep 2011 09:46:55 -0700 Subject: Input: tc3589x-keypad - fix section mismatch warning WARNING: drivers/input/keyboard/built-in.o(.text+0xb55b): Section mismatch in reference from the function tc3589x_keypad_open() to the function .devinit.text:tc3589x_keypad_init_key_hardware() The function tc3589x_keypad_open() references the function __devinit tc3589x_keypad_init_key_hardware(). This is often because tc3589x_keypad_open lacks a __devinit annotation or the annotation of tc3589x_keypad_init_key_hardware is wrong. Signed-off-by: Harvey Yang Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tc3589x-keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 99122f59e98..f60c9e82f20 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -90,7 +90,7 @@ struct tc_keypad { bool keypad_stopped; }; -static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) +static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) { int ret; struct tc3589x *tc3589x = keypad->tc3589x; -- cgit v1.2.3-70-g09d2 From d0d150ec28ab05eb2ec8cf9fcb7c9753ec95e0d4 Mon Sep 17 00:00:00 2001 From: Rakesh Iyer Date: Thu, 8 Sep 2011 15:34:11 -0700 Subject: Input: tegra-kbc - fix wakeup from suspend For wakeup to be reliable, kbc needs to be in interrupt mode before suspend. Created common routine to control the FIFO interrupt. Added synchronization to ensure orderly suspend. Signed-off-by: Rakesh Iyer Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tegra-kbc.c | 58 ++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index a5a77915c65..8fb474f0394 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -55,6 +55,7 @@ #define KBC_ROW_CFG0_0 0x8 #define KBC_COL_CFG0_0 0x18 +#define KBC_TO_CNT_0 0x24 #define KBC_INIT_DLY_0 0x28 #define KBC_RPT_DLY_0 0x2c #define KBC_KP_ENT0_0 0x30 @@ -70,6 +71,7 @@ struct tegra_kbc { spinlock_t lock; unsigned int repoll_dly; unsigned long cp_dly_jiffies; + unsigned int cp_to_wkup_dly; bool use_fn_map; bool use_ghost_filter; const struct tegra_kbc_platform_data *pdata; @@ -341,6 +343,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) kbc->num_pressed_keys = num_down; } +static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) +{ + u32 val; + + val = readl(kbc->mmio + KBC_CONTROL_0); + if (enable) + val |= KBC_CONTROL_FIFO_CNT_INT_EN; + else + val &= ~KBC_CONTROL_FIFO_CNT_INT_EN; + writel(val, kbc->mmio + KBC_CONTROL_0); +} + static void tegra_kbc_keypress_timer(unsigned long data) { struct tegra_kbc *kbc = (struct tegra_kbc *)data; @@ -370,9 +384,7 @@ static void tegra_kbc_keypress_timer(unsigned long data) /* All keys are released so enable the keypress interrupt */ spin_lock_irqsave(&kbc->lock, flags); - val = readl(kbc->mmio + KBC_CONTROL_0); - val |= KBC_CONTROL_FIFO_CNT_INT_EN; - writel(val, kbc->mmio + KBC_CONTROL_0); + tegra_kbc_set_fifo_interrupt(kbc, true); spin_unlock_irqrestore(&kbc->lock, flags); } } @@ -380,15 +392,13 @@ static void tegra_kbc_keypress_timer(unsigned long data) static irqreturn_t tegra_kbc_isr(int irq, void *args) { struct tegra_kbc *kbc = args; - u32 val, ctl; + u32 val; /* * Until all keys are released, defer further processing to * the polling loop in tegra_kbc_keypress_timer */ - ctl = readl(kbc->mmio + KBC_CONTROL_0); - ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN; - writel(ctl, kbc->mmio + KBC_CONTROL_0); + tegra_kbc_set_fifo_interrupt(kbc, false); /* * Quickly bail out & reenable interrupts if the fifo threshold @@ -404,8 +414,7 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args) */ mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); } else { - ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; - writel(ctl, kbc->mmio + KBC_CONTROL_0); + tegra_kbc_set_fifo_interrupt(kbc, true); } return IRQ_HANDLED; @@ -734,18 +743,30 @@ static int tegra_kbc_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct tegra_kbc *kbc = platform_get_drvdata(pdev); + mutex_lock(&kbc->idev->mutex); if (device_may_wakeup(&pdev->dev)) { - tegra_kbc_setup_wakekeys(kbc, true); - enable_irq_wake(kbc->irq); + disable_irq(kbc->irq); + del_timer_sync(&kbc->timer); + tegra_kbc_set_fifo_interrupt(kbc, false); + /* Forcefully clear the interrupt status */ writel(0x7, kbc->mmio + KBC_INT_0); + /* + * Store the previous resident time of continuous polling mode. + * Force the keyboard into interrupt mode. + */ + kbc->cp_to_wkup_dly = readl(kbc->mmio + KBC_TO_CNT_0); + writel(0, kbc->mmio + KBC_TO_CNT_0); + + tegra_kbc_setup_wakekeys(kbc, true); msleep(30); + + enable_irq_wake(kbc->irq); } else { - mutex_lock(&kbc->idev->mutex); if (kbc->idev->users) tegra_kbc_stop(kbc); - mutex_unlock(&kbc->idev->mutex); } + mutex_unlock(&kbc->idev->mutex); return 0; } @@ -756,15 +777,22 @@ static int tegra_kbc_resume(struct device *dev) struct tegra_kbc *kbc = platform_get_drvdata(pdev); int err = 0; + mutex_lock(&kbc->idev->mutex); if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(kbc->irq); tegra_kbc_setup_wakekeys(kbc, false); + + /* Restore the resident time of continuous polling mode. */ + writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0); + + tegra_kbc_set_fifo_interrupt(kbc, true); + + enable_irq(kbc->irq); } else { - mutex_lock(&kbc->idev->mutex); if (kbc->idev->users) err = tegra_kbc_start(kbc); - mutex_unlock(&kbc->idev->mutex); } + mutex_unlock(&kbc->idev->mutex); return err; } -- cgit v1.2.3-70-g09d2 From 95439cbad134de58d9ea256e37fd13fbcdc87d08 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 9 Sep 2011 09:24:20 -0700 Subject: Input: tegra-kbc - tighten locking Take spinlock when entering ISR and timer routine to ensure that we do not race while enabling/disabling FIFO interrupts. Also we do not need to take teh spinlock in tegra_kbc_startremove() since interrupt is completely disabled. Tested-by: Rakesh Iyer Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tegra-kbc.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 8fb474f0394..cf3228b0ab9 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -260,12 +260,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) u32 val = 0; unsigned int i; unsigned int num_down = 0; - unsigned long flags; bool fn_keypress = false; bool key_in_same_row = false; bool key_in_same_col = false; - spin_lock_irqsave(&kbc->lock, flags); for (i = 0; i < KBC_MAX_KPENT; i++) { if ((i % 4) == 0) val = readl(kbc->mmio + KBC_KP_ENT0_0 + i); @@ -294,7 +292,7 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) * any 2 of the 3 keys share a row, and any 2 of them share a column. * If so ignore the key presses for this iteration. */ - if ((kbc->use_ghost_filter) && (num_down >= 3)) { + if (kbc->use_ghost_filter && num_down >= 3) { for (i = 0; i < num_down; i++) { unsigned int j; u8 curr_col = scancodes[i] & 0x07; @@ -327,8 +325,6 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) } } - spin_unlock_irqrestore(&kbc->lock, flags); - /* Ignore the key presses for this iteration? */ if (key_in_same_col && key_in_same_row) return; @@ -362,6 +358,8 @@ static void tegra_kbc_keypress_timer(unsigned long data) u32 val; unsigned int i; + spin_lock_irqsave(&kbc->lock, flags); + val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; if (val) { unsigned long dly; @@ -383,22 +381,19 @@ static void tegra_kbc_keypress_timer(unsigned long data) kbc->num_pressed_keys = 0; /* All keys are released so enable the keypress interrupt */ - spin_lock_irqsave(&kbc->lock, flags); tegra_kbc_set_fifo_interrupt(kbc, true); - spin_unlock_irqrestore(&kbc->lock, flags); } + + spin_unlock_irqrestore(&kbc->lock, flags); } static irqreturn_t tegra_kbc_isr(int irq, void *args) { struct tegra_kbc *kbc = args; + unsigned long flags; u32 val; - /* - * Until all keys are released, defer further processing to - * the polling loop in tegra_kbc_keypress_timer - */ - tegra_kbc_set_fifo_interrupt(kbc, false); + spin_lock_irqsave(&kbc->lock, flags); /* * Quickly bail out & reenable interrupts if the fifo threshold @@ -409,14 +404,15 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args) if (val & KBC_INT_FIFO_CNT_INT_STATUS) { /* - * Schedule timer to run when hardware is in continuous - * polling mode. + * Until all keys are released, defer further processing to + * the polling loop in tegra_kbc_keypress_timer. */ + tegra_kbc_set_fifo_interrupt(kbc, false); mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); - } else { - tegra_kbc_set_fifo_interrupt(kbc, true); } + spin_unlock_irqrestore(&kbc->lock, flags); + return IRQ_HANDLED; } @@ -464,7 +460,6 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc) static int tegra_kbc_start(struct tegra_kbc *kbc) { const struct tegra_kbc_platform_data *pdata = kbc->pdata; - unsigned long flags; unsigned int debounce_cnt; u32 val = 0; @@ -502,7 +497,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) * Atomically clear out any remaining entries in the key FIFO * and enable keyboard interrupts. */ - spin_lock_irqsave(&kbc->lock, flags); while (1) { val = readl(kbc->mmio + KBC_INT_0); val >>= 4; @@ -513,7 +507,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) val = readl(kbc->mmio + KBC_KP_ENT1_0); } writel(0x7, kbc->mmio + KBC_INT_0); - spin_unlock_irqrestore(&kbc->lock, flags); enable_irq(kbc->irq); -- cgit v1.2.3-70-g09d2 From b6b1e927cec6b472578402f07f5befa79a96818d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 9 Sep 2011 10:15:29 -0700 Subject: Input: twl6040-vibra - fix compiler warning Fix warning from Geert's build summary emails by changing "if" to "ifdef". Thsi should fix the following: drivers/input/misc/twl6040-vibra.c:231:5: warning: "CONFIG_PM_SLEEP" is not defined Builds cleanly with CONFIG_PM_SLEEP enabled or disabled. Signed-off-by: Randy Dunlap Signed-off-by: Dmitry Torokhov --- drivers/input/misc/twl6040-vibra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index c43002e7ec7..23855e12a30 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -228,7 +228,7 @@ static void twl6040_vibra_close(struct input_dev *input) mutex_unlock(&info->mutex); } -#if CONFIG_PM_SLEEP +#ifdef CONFIG_PM_SLEEP static int twl6040_vibra_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); -- cgit v1.2.3-70-g09d2 From 1155961946f2c6ac0f2db2bc6318ec01c79fb3fa Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:22:19 -0700 Subject: Input: elantech - correct x, y value range for v2 hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x, y values are actually 12-bit long. Also update protocol document to reflect the change. Signed-off-by: JJ Ding Acked-by: Daniel Kurtz Acked-by: Éric Piel Signed-off-by: Dmitry Torokhov --- Documentation/input/elantech.txt | 8 ++++---- drivers/input/mouse/elantech.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt index db798af5ef9..bce9941ffa9 100644 --- a/Documentation/input/elantech.txt +++ b/Documentation/input/elantech.txt @@ -389,14 +389,14 @@ byte 0: byte 1: bit 7 6 5 4 3 2 1 0 - p7 p6 p5 p4 . x10 x9 x8 + p7 p6 p5 p4 x11 x10 x9 x8 byte 2: bit 7 6 5 4 3 2 1 0 x7 x6 x5 x4 x3 x2 x1 x0 - x10..x0 = absolute x value (horizontal) + x11..x0 = absolute x value (horizontal) byte 3: @@ -420,7 +420,7 @@ byte 3: byte 4: bit 7 6 5 4 3 2 1 0 - p3 p1 p2 p0 . . y9 y8 + p3 p1 p2 p0 y11 y10 y9 y8 p7..p0 = pressure (not EF113) @@ -429,7 +429,7 @@ byte 5: bit 7 6 5 4 3 2 1 0 y7 y6 y5 y4 y3 y2 y1 y0 - y9..y0 = absolute y value (vertical) + y11..y0 = absolute y value (vertical) 4.2.2 Two finger touch diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 32503565faf..da161dae350 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -290,15 +290,15 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) /* pass through... */ case 1: /* - * byte 1: . . . . . x10 x9 x8 + * byte 1: . . . . x11 x10 x9 x8 * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 */ - x1 = ((packet[1] & 0x07) << 8) | packet[2]; + x1 = ((packet[1] & 0x0f) << 8) | packet[2]; /* - * byte 4: . . . . . . y9 y8 + * byte 4: . . . . y11 y10 y9 y8 * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */ - y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]); + y1 = ETP_YMAX_V2 - (((packet[4] & 0x0f) << 8) | packet[5]); input_report_abs(dev, ABS_X, x1); input_report_abs(dev, ABS_Y, y1); -- cgit v1.2.3-70-g09d2 From 461a791765da501f73e3d5957788267101e800d2 Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:22:58 -0700 Subject: Input: elantech - get rid of ETP_2FT_* in elantech.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For two finger touches the coordinate of each finger gets reported separately but with reduced resolution. With this change, we now have the same range for ST and MT data and scale MT data because it has lower resolution to match ST. Suggested-by: Dmitry Torokhov Signed-off-by: JJ Ding Acked-by: Daniel Kurtz Acked-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 28 +++++++++++++--------------- drivers/input/mouse/elantech.h | 11 ----------- 2 files changed, 13 insertions(+), 26 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index da161dae350..cd8e2e5ced8 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -273,11 +273,11 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) struct elantech_data *etd = psmouse->private; struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; - unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0; + unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0; + unsigned int width = 0, pres = 0; /* byte 0: n1 n0 . . . . R L */ fingers = (packet[0] & 0xc0) >> 6; - input_report_key(dev, BTN_TOUCH, fingers != 0); switch (fingers) { case 3: @@ -300,9 +300,6 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) */ y1 = ETP_YMAX_V2 - (((packet[4] & 0x0f) << 8) | packet[5]); - input_report_abs(dev, ABS_X, x1); - input_report_abs(dev, ABS_Y, y1); - pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); break; @@ -314,22 +311,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) * byte 0: . . ay8 ax8 . . . . * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */ - x1 = ((packet[0] & 0x10) << 4) | packet[1]; + x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2; /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ - y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]); + y1 = ETP_YMAX_V2 - + ((((packet[0] & 0x20) << 3) | packet[2]) << 2); /* * byte 3: . . by8 bx8 . . . . * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 */ - x2 = ((packet[3] & 0x10) << 4) | packet[4]; + x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2; /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */ - y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]); - /* - * For compatibility with the X Synaptics driver scale up - * one coordinate and report as ordinary mouse movent - */ - input_report_abs(dev, ABS_X, x1 << 2); - input_report_abs(dev, ABS_Y, y1 << 2); + y2 = ETP_YMAX_V2 - + ((((packet[3] & 0x20) << 3) | packet[5]) << 2); /* Unknown so just report sensible values */ pres = 127; @@ -337,6 +330,11 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) break; } + input_report_key(dev, BTN_TOUCH, fingers != 0); + if (fingers != 0) { + input_report_abs(dev, ABS_X, x1); + input_report_abs(dev, ABS_Y, y1); + } elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index fabb2b99615..1c5894efda5 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -82,17 +82,6 @@ #define ETP_WMIN_V2 0 #define ETP_WMAX_V2 15 -/* - * For two finger touches the coordinate of each finger gets reported - * separately but with reduced resolution. - */ -#define ETP_2FT_FUZZ 4 - -#define ETP_2FT_XMIN ( 0 + ETP_2FT_FUZZ) -#define ETP_2FT_XMAX (288 - ETP_2FT_FUZZ) -#define ETP_2FT_YMIN ( 0 + ETP_2FT_FUZZ) -#define ETP_2FT_YMAX (192 - ETP_2FT_FUZZ) - struct elantech_data { unsigned char reg_10; unsigned char reg_11; -- cgit v1.2.3-70-g09d2 From 230282a77bcec97f4d0a54e50a44caab5eb39d5c Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:26:16 -0700 Subject: Input: elantech - use firmware provided x, y ranges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With newer hardware, the touchpad provides range info. Let's use it. Signed-off-by: JJ Ding Acked-by: Daniel Kurtz Acked-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 71 +++++++++++++++++++++++++++++++++--------- drivers/input/mouse/elantech.h | 3 +- 2 files changed, 58 insertions(+), 16 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index cd8e2e5ced8..296b6a6250f 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -223,7 +223,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) input_report_abs(dev, ABS_X, ((packet[1] & 0x0c) << 6) | packet[2]); input_report_abs(dev, ABS_Y, - ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3])); + etd->y_max - (((packet[1] & 0x03) << 8) | packet[3])); } input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); @@ -233,7 +233,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); if (etd->fw_version < 0x020000 && - (etd->capabilities & ETP_CAP_HAS_ROCKER)) { + (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { /* rocker up */ input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); /* rocker down */ @@ -298,7 +298,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) * byte 4: . . . . y11 y10 y9 y8 * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */ - y1 = ETP_YMAX_V2 - (((packet[4] & 0x0f) << 8) | packet[5]); + y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); @@ -313,7 +313,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) */ x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2; /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ - y1 = ETP_YMAX_V2 - + y1 = etd->y_max - ((((packet[0] & 0x20) << 3) | packet[2]) << 2); /* * byte 3: . . by8 bx8 . . . . @@ -321,7 +321,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) */ x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2; /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */ - y2 = ETP_YMAX_V2 - + y2 = etd->y_max - ((((packet[3] & 0x20) << 3) | packet[5]) << 2); /* Unknown so just report sensible values */ @@ -468,6 +468,41 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) return rc; } +static void elantech_set_range(struct psmouse *psmouse, + unsigned int *x_min, unsigned int *y_min, + unsigned int *x_max, unsigned int *y_max) +{ + struct elantech_data *etd = psmouse->private; + int i; + + switch (etd->hw_version) { + case 1: + *x_min = ETP_XMIN_V1; + *y_min = ETP_YMIN_V1; + *x_max = ETP_XMAX_V1; + *y_max = ETP_YMAX_V1; + break; + + case 2: + if (etd->fw_version == 0x020800 || + etd->fw_version == 0x020b00 || + etd->fw_version == 0x020030) { + *x_min = ETP_XMIN_V2; + *y_min = ETP_YMIN_V2; + *x_max = ETP_XMAX_V2; + *y_max = ETP_YMAX_V2; + } else { + i = (etd->fw_version > 0x020800 && + etd->fw_version < 0x020900) ? 1 : 2; + *x_min = 0; + *y_min = 0; + *x_max = (etd->capabilities[1] - i) * 64; + *y_max = (etd->capabilities[2] - i) * 64; + } + break; + } +} + /* * Set the appropriate event bits for the input subsystem */ @@ -475,6 +510,9 @@ static void elantech_set_input_params(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; + unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0; + + elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max); __set_bit(EV_KEY, dev->evbit); __set_bit(EV_ABS, dev->evbit); @@ -492,18 +530,18 @@ static void elantech_set_input_params(struct psmouse *psmouse) case 1: /* Rocker button */ if (etd->fw_version < 0x020000 && - (etd->capabilities & ETP_CAP_HAS_ROCKER)) { + (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { __set_bit(BTN_FORWARD, dev->keybit); __set_bit(BTN_BACK, dev->keybit); } - input_set_abs_params(dev, ABS_X, ETP_XMIN_V1, ETP_XMAX_V1, 0, 0); - input_set_abs_params(dev, ABS_Y, ETP_YMIN_V1, ETP_YMAX_V1, 0, 0); + input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); break; case 2: __set_bit(BTN_TOOL_QUADTAP, dev->keybit); - input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); - input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); + input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); if (etd->reports_pressure) { input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, ETP_PMAX_V2, 0, 0); @@ -512,10 +550,12 @@ static void elantech_set_input_params(struct psmouse *psmouse) } __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); input_mt_init_slots(dev, 2); - input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); break; } + + etd->y_max = y_max; } struct elantech_attr_data { @@ -769,13 +809,14 @@ int elantech_init(struct psmouse *psmouse) pr_info("assuming hardware version %d, firmware version %d.%d.%d\n", etd->hw_version, param[0], param[1], param[2]); - if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) { + if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, + etd->capabilities)) { pr_err("failed to query capabilities.\n"); goto init_fail; } pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", - param[0], param[1], param[2]); - etd->capabilities = param[0]; + etd->capabilities[0], etd->capabilities[1], + etd->capabilities[2]); /* * This firmware suffers from misreporting coordinates when diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 1c5894efda5..b54ea27d10a 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -93,13 +93,14 @@ struct elantech_data { unsigned char reg_25; unsigned char reg_26; unsigned char debug; - unsigned char capabilities; + unsigned char capabilities[3]; bool paritycheck; bool jumpy_cursor; bool reports_pressure; unsigned char hw_version; unsigned int fw_version; unsigned int single_finger_reports; + unsigned int y_max; unsigned char parity[256]; }; -- cgit v1.2.3-70-g09d2 From 8a360d09b14514139b883d970cd3a1b0b63e6717 Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:27:42 -0700 Subject: Input: elantech - remove ETP_EDGE_FUZZ_V2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't try to be too clever and remove ETP_EDGE_FUZZ_V2. X, Y ranges should be just the raw resolution of the device. Otherwise, they can cause underflow on the Y axis. Suggested-by: Éric Piel Signed-off-by: JJ Ding Acked-by: Daniel Kurtz Acked-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index b54ea27d10a..d9e614409f9 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -66,16 +66,13 @@ #define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1) /* - * It seems the resolution for hardware version 2 doubled. - * Hence the X and Y ranges are doubled too. - * The bezel around the pad also appears to be smaller + * The resolution for older v2 hardware doubled. + * (newer v2's firmware provides command so we can query) */ -#define ETP_EDGE_FUZZ_V2 8 - -#define ETP_XMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2) -#define ETP_XMAX_V2 (1152 - ETP_EDGE_FUZZ_V2) -#define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2) -#define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2) +#define ETP_XMIN_V2 0 +#define ETP_XMAX_V2 1152 +#define ETP_YMIN_V2 0 +#define ETP_YMAX_V2 768 #define ETP_PMIN_V2 0 #define ETP_PMAX_V2 255 -- cgit v1.2.3-70-g09d2 From 7894f21b109848130be7547448af89dc33d0f268 Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:28:04 -0700 Subject: Input: elantech - packet checking for v2 hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For v2 hardware, there is no real parity check, but we can still check some constant bits for data integrity. Also rename elantech_check_parity_v1 to elantech_packet_check_v1 to make these packet checking function names consistent. Signed-off-by: JJ Ding Acked-by: Daniel Kurtz Acked-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 296b6a6250f..f2e3a2be041 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -350,7 +350,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) input_sync(dev); } -static int elantech_check_parity_v1(struct psmouse *psmouse) +static int elantech_packet_check_v1(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; unsigned char *packet = psmouse->packet; @@ -374,6 +374,34 @@ static int elantech_check_parity_v1(struct psmouse *psmouse) etd->parity[packet[3]] == p3; } +static int elantech_packet_check_v2(struct psmouse *psmouse) +{ + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + + /* + * V2 hardware has two flavors. Older ones that do not report pressure, + * and newer ones that reports pressure and width. With newer ones, all + * packets (1, 2, 3 finger touch) have the same constant bits. With + * older ones, 1/3 finger touch packets and 2 finger touch packets + * have different constant bits. + * With all three cases, if the constant bits are not exactly what I + * expected, I consider them invalid. + */ + if (etd->reports_pressure) + return (packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x0f) == 0x02; + + if ((packet[0] & 0xc0) == 0x80) + return (packet[0] & 0x0c) == 0x0c && + (packet[3] & 0x0e) == 0x08; + + return (packet[0] & 0x3c) == 0x3c && + (packet[1] & 0xf0) == 0x00 && + (packet[3] & 0x3e) == 0x38 && + (packet[4] & 0xf0) == 0x00; +} + /* * Process byte stream from mouse and handle complete packets */ @@ -389,14 +417,16 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) switch (etd->hw_version) { case 1: - if (etd->paritycheck && !elantech_check_parity_v1(psmouse)) + if (etd->paritycheck && !elantech_packet_check_v1(psmouse)) return PSMOUSE_BAD_DATA; elantech_report_absolute_v1(psmouse); break; case 2: - /* We don't know how to check parity in protocol v2 */ + if (etd->paritycheck && !elantech_packet_check_v2(psmouse)) + return PSMOUSE_BAD_DATA; + elantech_report_absolute_v2(psmouse); break; } @@ -795,8 +825,7 @@ int elantech_init(struct psmouse *psmouse) etd->hw_version = 2; /* For now show extra debug information */ etd->debug = 1; - /* Don't know how to do parity checking for version 2 */ - etd->paritycheck = 0; + etd->paritycheck = 1; if (etd->fw_version >= 0x020800) etd->reports_pressure = true; -- cgit v1.2.3-70-g09d2 From 3c8bbb951ab23dc1192473ccad76cde89c172d27 Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:28:19 -0700 Subject: Input: elantech - clean up elantech_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group property setting code into elantech_set_properties. Signed-off-by: JJ Ding Acked-by: Daniel Kurtz Acked-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 69 ++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 30 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index f2e3a2be041..1ab1c14449d 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -790,6 +790,42 @@ static int elantech_reconnect(struct psmouse *psmouse) return 0; } +/* + * determine hardware version and set some properties according to it. + */ +static void elantech_set_properties(struct elantech_data *etd) +{ + /* + * Assume every version greater than 0x020030 is new EeePC style + * hardware with 6 byte packets, except 0x020600 + */ + if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) + etd->hw_version = 1; + else + etd->hw_version = 2; + + /* + * Turn on packet checking by default. + */ + etd->paritycheck = 1; + + /* + * This firmware suffers from misreporting coordinates when + * a touch action starts causing the mouse cursor or scrolled page + * to jump. Enable a workaround. + */ + etd->jumpy_cursor = + (etd->fw_version == 0x020022 || etd->fw_version == 0x020600); + + if (etd->hw_version == 2) { + /* For now show extra debug information */ + etd->debug = 1; + + if (etd->fw_version >= 0x020800) + etd->reports_pressure = true; + } +} + /* * Initialize the touchpad and create sysfs entries */ @@ -816,26 +852,9 @@ int elantech_init(struct psmouse *psmouse) } etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; - - /* - * Assume every version greater than this is new EeePC style - * hardware with 6 byte packets - */ - if (etd->fw_version >= 0x020030) { - etd->hw_version = 2; - /* For now show extra debug information */ - etd->debug = 1; - etd->paritycheck = 1; - - if (etd->fw_version >= 0x020800) - etd->reports_pressure = true; - - } else { - etd->hw_version = 1; - etd->paritycheck = 1; - } - - pr_info("assuming hardware version %d, firmware version %d.%d.%d\n", + elantech_set_properties(etd); + pr_info("assuming hardware version %d " + "(with firmware version 0x%02x%02x%02x)\n", etd->hw_version, param[0], param[1], param[2]); if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, @@ -847,16 +866,6 @@ int elantech_init(struct psmouse *psmouse) etd->capabilities[0], etd->capabilities[1], etd->capabilities[2]); - /* - * This firmware suffers from misreporting coordinates when - * a touch action starts causing the mouse cursor or scrolled page - * to jump. Enable a workaround. - */ - if (etd->fw_version == 0x020022 || etd->fw_version == 0x020600) { - pr_info("firmware version 2.0.34/2.6.0 detected, enabling jumpy cursor workaround\n"); - etd->jumpy_cursor = true; - } - if (elantech_set_absolute_mode(psmouse)) { pr_err("failed to put touchpad into absolute mode.\n"); goto init_fail; -- cgit v1.2.3-70-g09d2 From 28f49616113f3a1fbef789319bfd2122d0c3663f Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:30:31 -0700 Subject: Input: elantech - add v3 hardware support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v3 hardware's packet format is almost identical to v2 (one/three finger touch), except when sensing two finger touch, the hardware sends 12 bytes of data. Signed-off-by: JJ Ding Acked-by: Daniel Kurtz Acked-by: Éric Piel Signed-off-by: Dmitry Torokhov --- Documentation/input/elantech.txt | 117 +++++++++++++++++++--- drivers/input/mouse/elantech.c | 208 +++++++++++++++++++++++++++++++++++---- drivers/input/mouse/elantech.h | 12 +++ 3 files changed, 306 insertions(+), 31 deletions(-) (limited to 'drivers/input') diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt index bce9941ffa9..cee08eecda4 100644 --- a/Documentation/input/elantech.txt +++ b/Documentation/input/elantech.txt @@ -16,15 +16,22 @@ Contents 1. Introduction 2. Extra knobs - 3. Hardware version 1 - 3.1 Registers - 3.2 Native relative mode 4 byte packet format - 3.3 Native absolute mode 4 byte packet format - 4. Hardware version 2 + 3. Differentiating hardware versions + 4. Hardware version 1 4.1 Registers - 4.2 Native absolute mode 6 byte packet format - 4.2.1 One finger touch - 4.2.2 Two finger touch + 4.2 Native relative mode 4 byte packet format + 4.3 Native absolute mode 4 byte packet format + 5. Hardware version 2 + 5.1 Registers + 5.2 Native absolute mode 6 byte packet format + 5.2.1 Parity checking and packet re-synchronization + 5.2.2 One/Three finger touch + 5.2.3 Two finger touch + 6. Hardware version 3 + 6.1 Registers + 6.2 Native absolute mode 6 byte packet format + 6.2.1 One/Three finger touch + 6.2.2 Two finger touch @@ -375,7 +382,7 @@ For all the other ones, there are just a few constant bits: In case an error is detected, all the packets are shifted by one (and packet[0] is discarded). -5.2.1 One/Three finger touch +5.2.2 One/Three finger touch ~~~~~~~~~~~~~~~~ byte 0: @@ -384,7 +391,7 @@ byte 0: n1 n0 w3 w2 . . R L L, R = 1 when Left, Right mouse button pressed - n1..n0 = numbers of fingers on touchpad + n1..n0 = number of fingers on touchpad byte 1: @@ -432,7 +439,7 @@ byte 5: y11..y0 = absolute y value (vertical) -4.2.2 Two finger touch +5.2.3 Two finger touch ~~~~~~~~~~~~~~~~ Note that the two pairs of coordinates are not exactly the coordinates of the @@ -446,7 +453,7 @@ byte 0: n1 n0 ay8 ax8 . . R L L, R = 1 when Left, Right mouse button pressed - n1..n0 = numbers of fingers on touchpad + n1..n0 = number of fingers on touchpad byte 1: @@ -480,3 +487,89 @@ byte 5: by7 by8 by5 by4 by3 by2 by1 by0 by8..by0 = upper-right finger absolute y value + +///////////////////////////////////////////////////////////////////////////// + +6. Hardware version 3 + ================== + +6.1 Registers + ~~~~~~~~~ +* reg_10 + + bit 7 6 5 4 3 2 1 0 + 0 0 0 0 0 0 0 A + + A: 1 = enable absolute tracking + +6.2 Native absolute mode 6 byte packet format + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1 and 3 finger touch shares the same 6-byte packet format, except that +3 finger touch only reports the position of the center of all three fingers. + +Firmware would send 12 bytes of data for 2 finger touch. + +Note on debounce: +In case the box has unstable power supply or other electricity issues, or +when number of finger changes, F/W would send "debounce packet" to inform +driver that the hardware is in debounce status. +The debouce packet has the following signature: + byte 0: 0xc4 + byte 1: 0xff + byte 2: 0xff + byte 3: 0x02 + byte 4: 0xff + byte 5: 0xff +When we encounter this kind of packet, we just ignore it. + +6.2.1 One/Three finger touch + ~~~~~~~~~~~~~~~~~~~~~~ + +byte 0: + + bit 7 6 5 4 3 2 1 0 + n1 n0 w3 w2 0 1 R L + + L, R = 1 when Left, Right mouse button pressed + n1..n0 = number of fingers on touchpad + +byte 1: + + bit 7 6 5 4 3 2 1 0 + p7 p6 p5 p4 x11 x10 x9 x8 + +byte 2: + + bit 7 6 5 4 3 2 1 0 + x7 x6 x5 x4 x3 x2 x1 x0 + + x11..x0 = absolute x value (horizontal) + +byte 3: + + bit 7 6 5 4 3 2 1 0 + 0 0 w1 w0 0 0 1 0 + + w3..w0 = width of the finger touch + +byte 4: + + bit 7 6 5 4 3 2 1 0 + p3 p1 p2 p0 y11 y10 y9 y8 + + p7..p0 = pressure + +byte 5: + + bit 7 6 5 4 3 2 1 0 + y7 y6 y5 y4 y3 y2 y1 y0 + + y11..y0 = absolute y value (vertical) + +6.2.2 Two finger touch + ~~~~~~~~~~~~~~~~ + +The packet format is exactly the same for two finger touch, except the hardware +sends two 6 byte packets. The first packet contains data for the first finger, +the second packet has data for the second finger. So for two finger touch a +total of 12 bytes are sent. diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 1ab1c14449d..9cfc70ae83f 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -108,6 +108,16 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, rc = -1; } break; + + case 3: + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { + rc = -1; + } + break; } if (rc) @@ -154,6 +164,18 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, rc = -1; } break; + + case 3: + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, val) || + elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { + rc = -1; + } + break; } if (rc) @@ -350,6 +372,84 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) input_sync(dev); } +/* + * Interpret complete data packets and report absolute mode input events for + * hardware version 3. (12 byte packets for two fingers) + */ +static void elantech_report_absolute_v3(struct psmouse *psmouse, + int packet_type) +{ + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; + unsigned int width = 0, pres = 0; + + /* byte 0: n1 n0 . . . . R L */ + fingers = (packet[0] & 0xc0) >> 6; + + switch (fingers) { + case 3: + case 1: + /* + * byte 1: . . . . x11 x10 x9 x8 + * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 + */ + x1 = ((packet[1] & 0x0f) << 8) | packet[2]; + /* + * byte 4: . . . . y11 y10 y9 y8 + * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 + */ + y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + break; + + case 2: + if (packet_type == PACKET_V3_HEAD) { + /* + * byte 1: . . . . ax11 ax10 ax9 ax8 + * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 + */ + etd->prev_x = ((packet[1] & 0x0f) << 8) | packet[2]; + /* + * byte 4: . . . . ay11 ay10 ay9 ay8 + * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 + */ + etd->prev_y = etd->y_max - + (((packet[4] & 0x0f) << 8) | packet[5]); + /* + * wait for next packet + */ + return; + } + + /* packet_type == PACKET_V3_TAIL */ + x1 = etd->prev_x; + y1 = etd->prev_y; + x2 = ((packet[1] & 0x0f) << 8) | packet[2]; + y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + break; + } + + pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); + width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); + + input_report_key(dev, BTN_TOUCH, fingers != 0); + if (fingers != 0) { + input_report_abs(dev, ABS_X, x1); + input_report_abs(dev, ABS_Y, y1); + } + elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); + input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); + input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); + input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); + input_report_key(dev, BTN_LEFT, packet[0] & 0x01); + input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); + input_report_abs(dev, ABS_PRESSURE, pres); + input_report_abs(dev, ABS_TOOL_WIDTH, width); + + input_sync(dev); +} + static int elantech_packet_check_v1(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; @@ -402,12 +502,38 @@ static int elantech_packet_check_v2(struct psmouse *psmouse) (packet[4] & 0xf0) == 0x00; } +/* + * We check the constant bits to determine what packet type we get, + * so packet checking is mandatory for v3 hardware. + */ +static int elantech_packet_check_v3(struct psmouse *psmouse) +{ + const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; + unsigned char *packet = psmouse->packet; + + /* + * check debounce first, it has the same signature in byte 0 + * and byte 3 as PACKET_V3_HEAD. + */ + if (!memcmp(packet, debounce_packet, sizeof(debounce_packet))) + return PACKET_DEBOUNCE; + + if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02) + return PACKET_V3_HEAD; + + if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) + return PACKET_V3_TAIL; + + return PACKET_UNKNOWN; +} + /* * Process byte stream from mouse and handle complete packets */ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; + int packet_type; if (psmouse->pktcnt < psmouse->pktsize) return PSMOUSE_GOOD_DATA; @@ -429,6 +555,18 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) elantech_report_absolute_v2(psmouse); break; + + case 3: + packet_type = elantech_packet_check_v3(psmouse); + /* ignore debounce */ + if (packet_type == PACKET_DEBOUNCE) + return PSMOUSE_FULL_PACKET; + + if (packet_type == PACKET_UNKNOWN) + return PSMOUSE_BAD_DATA; + + elantech_report_absolute_v3(psmouse, packet_type); + break; } return PSMOUSE_FULL_PACKET; @@ -463,8 +601,15 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) elantech_write_reg(psmouse, 0x11, etd->reg_11) || elantech_write_reg(psmouse, 0x21, etd->reg_21)) { rc = -1; - break; } + break; + + case 3: + etd->reg_10 = 0x0b; + if (elantech_write_reg(psmouse, 0x10, etd->reg_10)) + rc = -1; + + break; } if (rc == 0) { @@ -498,11 +643,12 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) return rc; } -static void elantech_set_range(struct psmouse *psmouse, - unsigned int *x_min, unsigned int *y_min, - unsigned int *x_max, unsigned int *y_max) +static int elantech_set_range(struct psmouse *psmouse, + unsigned int *x_min, unsigned int *y_min, + unsigned int *x_max, unsigned int *y_max) { struct elantech_data *etd = psmouse->private; + unsigned char param[3]; int i; switch (etd->hw_version) { @@ -530,19 +676,30 @@ static void elantech_set_range(struct psmouse *psmouse, *y_max = (etd->capabilities[2] - i) * 64; } break; + + case 3: + if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -1; + + *x_max = (0x0f & param[0]) << 8 | param[1]; + *y_max = (0xf0 & param[0]) << 4 | param[2]; + break; } + + return 0; } /* * Set the appropriate event bits for the input subsystem */ -static void elantech_set_input_params(struct psmouse *psmouse) +static int elantech_set_input_params(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0; - elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max); + if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max)) + return -1; __set_bit(EV_KEY, dev->evbit); __set_bit(EV_ABS, dev->evbit); @@ -570,6 +727,9 @@ static void elantech_set_input_params(struct psmouse *psmouse) case 2: __set_bit(BTN_TOOL_QUADTAP, dev->keybit); + __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); + /* fall through */ + case 3: input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); if (etd->reports_pressure) { @@ -578,7 +738,6 @@ static void elantech_set_input_params(struct psmouse *psmouse) input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, ETP_WMAX_V2, 0, 0); } - __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); input_mt_init_slots(dev, 2); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); @@ -586,6 +745,8 @@ static void elantech_set_input_params(struct psmouse *psmouse) } etd->y_max = y_max; + + return 0; } struct elantech_attr_data { @@ -727,7 +888,8 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) * Report this in case there are Elantech models that use a different * set of magic numbers */ - if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) { + if (param[0] != 0x3c || param[1] != 0x03 || + (param[2] != 0xc8 && param[2] != 0x00)) { pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", param[0], param[1], param[2]); return -1; @@ -793,16 +955,16 @@ static int elantech_reconnect(struct psmouse *psmouse) /* * determine hardware version and set some properties according to it. */ -static void elantech_set_properties(struct elantech_data *etd) +static int elantech_set_properties(struct elantech_data *etd) { - /* - * Assume every version greater than 0x020030 is new EeePC style - * hardware with 6 byte packets, except 0x020600 - */ if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) etd->hw_version = 1; - else + else if (etd->fw_version < 0x150600) etd->hw_version = 2; + else if ((etd->fw_version & 0x0f0000) >> 16 == 5) + etd->hw_version = 3; + else + return -1; /* * Turn on packet checking by default. @@ -817,13 +979,15 @@ static void elantech_set_properties(struct elantech_data *etd) etd->jumpy_cursor = (etd->fw_version == 0x020022 || etd->fw_version == 0x020600); - if (etd->hw_version == 2) { + if (etd->hw_version > 1) { /* For now show extra debug information */ etd->debug = 1; if (etd->fw_version >= 0x020800) etd->reports_pressure = true; } + + return 0; } /* @@ -850,9 +1014,12 @@ int elantech_init(struct psmouse *psmouse) pr_err("failed to query firmware version.\n"); goto init_fail; } - etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; - elantech_set_properties(etd); + + if (elantech_set_properties(etd)) { + pr_err("unknown hardware version, aborting...\n"); + goto init_fail; + } pr_info("assuming hardware version %d " "(with firmware version 0x%02x%02x%02x)\n", etd->hw_version, param[0], param[1], param[2]); @@ -871,7 +1038,10 @@ int elantech_init(struct psmouse *psmouse) goto init_fail; } - elantech_set_input_params(psmouse); + if (elantech_set_input_params(psmouse)) { + pr_err("failed to query touchpad range.\n"); + goto init_fail; + } error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, &elantech_attr_group); @@ -883,7 +1053,7 @@ int elantech_init(struct psmouse *psmouse) psmouse->protocol_handler = elantech_process_byte; psmouse->disconnect = elantech_disconnect; psmouse->reconnect = elantech_reconnect; - psmouse->pktsize = etd->hw_version == 2 ? 6 : 4; + psmouse->pktsize = etd->hw_version > 1 ? 6 : 4; return 0; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index d9e614409f9..236c33cdc70 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -16,6 +16,7 @@ /* * Command values for Synaptics style queries */ +#define ETP_FW_ID_QUERY 0x00 #define ETP_FW_VERSION_QUERY 0x01 #define ETP_CAPABILITIES_QUERY 0x02 @@ -24,6 +25,7 @@ */ #define ETP_REGISTER_READ 0x10 #define ETP_REGISTER_WRITE 0x11 +#define ETP_REGISTER_READWRITE 0x00 /* * Hardware version 2 custom PS/2 command value @@ -79,6 +81,14 @@ #define ETP_WMIN_V2 0 #define ETP_WMAX_V2 15 +/* + * v3 hardware has 2 kinds of packet types. + */ +#define PACKET_UNKNOWN 0x01 +#define PACKET_DEBOUNCE 0x02 +#define PACKET_V3_HEAD 0x03 +#define PACKET_V3_TAIL 0x04 + struct elantech_data { unsigned char reg_10; unsigned char reg_11; @@ -98,6 +108,8 @@ struct elantech_data { unsigned int fw_version; unsigned int single_finger_reports; unsigned int y_max; + unsigned int prev_x; + unsigned int prev_y; unsigned char parity[256]; }; -- cgit v1.2.3-70-g09d2 From 1dc6edec127e1fdb89d246189c232fe635d2f921 Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Fri, 9 Sep 2011 10:31:58 -0700 Subject: Input: elantech - add v4 hardware support v4 hardware is a true multitouch capable touchpad (up to 5 fingers). The packet format is quite complex, please see protocol document for reference. Signed-off-by: JJ Ding Signed-off-by: Dmitry Torokhov --- Documentation/input/elantech.txt | 170 ++++++++++++++++++++++++++ drivers/input/mouse/elantech.c | 249 +++++++++++++++++++++++++++++++++++++-- drivers/input/mouse/elantech.h | 29 ++++- 3 files changed, 432 insertions(+), 16 deletions(-) (limited to 'drivers/input') diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt index cee08eecda4..5602eb71ad5 100644 --- a/Documentation/input/elantech.txt +++ b/Documentation/input/elantech.txt @@ -32,6 +32,12 @@ Contents 6.2 Native absolute mode 6 byte packet format 6.2.1 One/Three finger touch 6.2.2 Two finger touch + 7. Hardware version 4 + 7.1 Registers + 7.2 Native absolute mode 6 byte packet format + 7.2.1 Status packet + 7.2.2 Head packet + 7.2.3 Motion packet @@ -573,3 +579,167 @@ The packet format is exactly the same for two finger touch, except the hardware sends two 6 byte packets. The first packet contains data for the first finger, the second packet has data for the second finger. So for two finger touch a total of 12 bytes are sent. + +///////////////////////////////////////////////////////////////////////////// + +7. Hardware version 4 + ================== + +7.1 Registers + ~~~~~~~~~ +* reg_07 + + bit 7 6 5 4 3 2 1 0 + 0 0 0 0 0 0 0 A + + A: 1 = enable absolute tracking + +7.2 Native absolute mode 6 byte packet format + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +v4 hardware is a true multitouch touchpad, capable of tracking up to 5 fingers. +Unfortunately, due to PS/2's limited bandwidth, its packet format is rather +complex. + +Whenever the numbers or identities of the fingers changes, the hardware sends a +status packet to indicate how many and which fingers is on touchpad, followed by +head packets or motion packets. A head packet contains data of finger id, finger +position (absolute x, y values), width, and pressure. A motion packet contains +two fingers' position delta. + +For example, when status packet tells there are 2 fingers on touchpad, then we +can expect two following head packets. If the finger status doesn't change, +the following packets would be motion packets, only sending delta of finger +position, until we receive a status packet. + +One exception is one finger touch. when a status packet tells us there is only +one finger, the hardware would just send head packets afterwards. + +7.2.1 Status packet + ~~~~~~~~~~~~~ + +byte 0: + + bit 7 6 5 4 3 2 1 0 + . . . . 0 1 R L + + L, R = 1 when Left, Right mouse button pressed + +byte 1: + + bit 7 6 5 4 3 2 1 0 + . . . ft4 ft3 ft2 ft1 ft0 + + ft4 ft3 ft2 ft1 ft0 ftn = 1 when finger n is on touchpad + +byte 2: not used + +byte 3: + + bit 7 6 5 4 3 2 1 0 + . . . 1 0 0 0 0 + + constant bits + +byte 4: + + bit 7 6 5 4 3 2 1 0 + p . . . . . . . + + p = 1 for palm + +byte 5: not used + +7.2.2 Head packet + ~~~~~~~~~~~ + +byte 0: + + bit 7 6 5 4 3 2 1 0 + w3 w2 w1 w0 0 1 R L + + L, R = 1 when Left, Right mouse button pressed + w3..w0 = finger width (spans how many trace lines) + +byte 1: + + bit 7 6 5 4 3 2 1 0 + p7 p6 p5 p4 x11 x10 x9 x8 + +byte 2: + + bit 7 6 5 4 3 2 1 0 + x7 x6 x5 x4 x3 x2 x1 x0 + + x11..x0 = absolute x value (horizontal) + +byte 3: + + bit 7 6 5 4 3 2 1 0 + id2 id1 id0 1 0 0 0 1 + + id2..id0 = finger id + +byte 4: + + bit 7 6 5 4 3 2 1 0 + p3 p1 p2 p0 y11 y10 y9 y8 + + p7..p0 = pressure + +byte 5: + + bit 7 6 5 4 3 2 1 0 + y7 y6 y5 y4 y3 y2 y1 y0 + + y11..y0 = absolute y value (vertical) + +7.2.3 Motion packet + ~~~~~~~~~~~~~ + +byte 0: + + bit 7 6 5 4 3 2 1 0 + id2 id1 id0 w 0 1 R L + + L, R = 1 when Left, Right mouse button pressed + id2..id0 = finger id + w = 1 when delta overflows (> 127 or < -128), in this case + firmware sends us (delta x / 5) and (delta y / 5) + +byte 1: + + bit 7 6 5 4 3 2 1 0 + x7 x6 x5 x4 x3 x2 x1 x0 + + x7..x0 = delta x (two's complement) + +byte 2: + + bit 7 6 5 4 3 2 1 0 + y7 y6 y5 y4 y3 y2 y1 y0 + + y7..y0 = delta y (two's complement) + +byte 3: + + bit 7 6 5 4 3 2 1 0 + id2 id1 id0 1 0 0 1 0 + + id2..id0 = finger id + +byte 4: + + bit 7 6 5 4 3 2 1 0 + x7 x6 x5 x4 x3 x2 x1 x0 + + x7..x0 = delta x (two's complement) + +byte 5: + + bit 7 6 5 4 3 2 1 0 + y7 y6 y5 y4 y3 y2 y1 y0 + + y7..y0 = delta y (two's complement) + + byte 0 ~ 2 for one finger + byte 3 ~ 5 for another diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 9cfc70ae83f..b8733b37726 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -84,7 +84,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, unsigned char param[3]; int rc = 0; - if (reg < 0x10 || reg > 0x26) + if (reg < 0x07 || reg > 0x26) return -1; if (reg > 0x11 && reg < 0x20) @@ -109,7 +109,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, } break; - case 3: + case 3 ... 4: if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || @@ -122,8 +122,10 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, if (rc) pr_err("failed to read register 0x%02x.\n", reg); - else + else if (etd->hw_version != 4) *val = param[0]; + else + *val = param[1]; return rc; } @@ -137,7 +139,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, struct elantech_data *etd = psmouse->private; int rc = 0; - if (reg < 0x10 || reg > 0x26) + if (reg < 0x07 || reg > 0x26) return -1; if (reg > 0x11 && reg < 0x20) @@ -176,6 +178,20 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, rc = -1; } break; + + case 4: + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, val) || + elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { + rc = -1; + } + break; } if (rc) @@ -409,12 +425,12 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, * byte 1: . . . . ax11 ax10 ax9 ax8 * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */ - etd->prev_x = ((packet[1] & 0x0f) << 8) | packet[2]; + etd->mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2]; /* * byte 4: . . . . ay11 ay10 ay9 ay8 * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ - etd->prev_y = etd->y_max - + etd->mt[0].y = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); /* * wait for next packet @@ -423,8 +439,8 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, } /* packet_type == PACKET_V3_TAIL */ - x1 = etd->prev_x; - y1 = etd->prev_y; + x1 = etd->mt[0].x; + y1 = etd->mt[0].y; x2 = ((packet[1] & 0x0f) << 8) | packet[2]; y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); break; @@ -450,6 +466,129 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, input_sync(dev); } +static void elantech_input_sync_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + unsigned char *packet = psmouse->packet; + + input_report_key(dev, BTN_LEFT, packet[0] & 0x01); + input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); + input_mt_report_pointer_emulation(dev, true); + input_sync(dev); +} + +static void process_packet_status_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + unsigned char *packet = psmouse->packet; + unsigned fingers; + int i; + + /* notify finger state change */ + fingers = packet[1] & 0x1f; + for (i = 0; i < ETP_MAX_FINGERS; i++) { + if ((fingers & (1 << i)) == 0) { + input_mt_slot(dev, i); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, false); + } + } + + elantech_input_sync_v4(psmouse); +} + +static void process_packet_head_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + int id = ((packet[3] & 0xe0) >> 5) - 1; + int pres, traces; + + if (id < 0) + return; + + etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2]; + etd->mt[id].y = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); + traces = (packet[0] & 0xf0) >> 4; + + input_mt_slot(dev, id); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); + + input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); + input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); + input_report_abs(dev, ABS_MT_PRESSURE, pres); + input_report_abs(dev, ABS_MT_TOUCH_MAJOR, traces * etd->width); + /* report this for backwards compatibility */ + input_report_abs(dev, ABS_TOOL_WIDTH, traces); + + elantech_input_sync_v4(psmouse); +} + +static void process_packet_motion_v4(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; + int weight, delta_x1 = 0, delta_y1 = 0, delta_x2 = 0, delta_y2 = 0; + int id, sid; + + id = ((packet[0] & 0xe0) >> 5) - 1; + if (id < 0) + return; + + sid = ((packet[3] & 0xe0) >> 5) - 1; + weight = (packet[0] & 0x10) ? ETP_WEIGHT_VALUE : 1; + /* + * Motion packets give us the delta of x, y values of specific fingers, + * but in two's complement. Let the compiler do the conversion for us. + * Also _enlarge_ the numbers to int, in case of overflow. + */ + delta_x1 = (signed char)packet[1]; + delta_y1 = (signed char)packet[2]; + delta_x2 = (signed char)packet[4]; + delta_y2 = (signed char)packet[5]; + + etd->mt[id].x += delta_x1 * weight; + etd->mt[id].y -= delta_y1 * weight; + input_mt_slot(dev, id); + input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); + input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); + + if (sid >= 0) { + etd->mt[sid].x += delta_x2 * weight; + etd->mt[sid].y -= delta_y2 * weight; + input_mt_slot(dev, sid); + input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[sid].x); + input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[sid].y); + } + + elantech_input_sync_v4(psmouse); +} + +static void elantech_report_absolute_v4(struct psmouse *psmouse, + int packet_type) +{ + switch (packet_type) { + case PACKET_V4_STATUS: + process_packet_status_v4(psmouse); + break; + + case PACKET_V4_HEAD: + process_packet_head_v4(psmouse); + break; + + case PACKET_V4_MOTION: + process_packet_motion_v4(psmouse); + break; + + case PACKET_UNKNOWN: + default: + /* impossible to get here */ + break; + } +} + static int elantech_packet_check_v1(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; @@ -504,7 +643,7 @@ static int elantech_packet_check_v2(struct psmouse *psmouse) /* * We check the constant bits to determine what packet type we get, - * so packet checking is mandatory for v3 hardware. + * so packet checking is mandatory for v3 and later hardware. */ static int elantech_packet_check_v3(struct psmouse *psmouse) { @@ -527,6 +666,25 @@ static int elantech_packet_check_v3(struct psmouse *psmouse) return PACKET_UNKNOWN; } +static int elantech_packet_check_v4(struct psmouse *psmouse) +{ + unsigned char *packet = psmouse->packet; + + if ((packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x1f) == 0x11) + return PACKET_V4_HEAD; + + if ((packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x1f) == 0x12) + return PACKET_V4_MOTION; + + if ((packet[0] & 0x0c) == 0x04 && + (packet[3] & 0x1f) == 0x10) + return PACKET_V4_STATUS; + + return PACKET_UNKNOWN; +} + /* * Process byte stream from mouse and handle complete packets */ @@ -567,6 +725,14 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) elantech_report_absolute_v3(psmouse, packet_type); break; + + case 4: + packet_type = elantech_packet_check_v4(psmouse); + if (packet_type == PACKET_UNKNOWN) + return PSMOUSE_BAD_DATA; + + elantech_report_absolute_v4(psmouse, packet_type); + break; } return PSMOUSE_FULL_PACKET; @@ -610,6 +776,13 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) rc = -1; break; + + case 4: + etd->reg_07 = 0x01; + if (elantech_write_reg(psmouse, 0x07, etd->reg_07)) + rc = -1; + + goto skip_readback_reg_10; /* v4 has no reg 0x10 to read */ } if (rc == 0) { @@ -637,6 +810,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) } } + skip_readback_reg_10: if (rc) pr_err("failed to initialise registers.\n"); @@ -645,10 +819,12 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) static int elantech_set_range(struct psmouse *psmouse, unsigned int *x_min, unsigned int *y_min, - unsigned int *x_max, unsigned int *y_max) + unsigned int *x_max, unsigned int *y_max, + unsigned int *width) { struct elantech_data *etd = psmouse->private; unsigned char param[3]; + unsigned char traces; int i; switch (etd->hw_version) { @@ -684,6 +860,19 @@ static int elantech_set_range(struct psmouse *psmouse, *x_max = (0x0f & param[0]) << 8 | param[1]; *y_max = (0xf0 & param[0]) << 4 | param[2]; break; + + case 4: + if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -1; + + *x_max = (0x0f & param[0]) << 8 | param[1]; + *y_max = (0xf0 & param[0]) << 4 | param[2]; + traces = etd->capabilities[1]; + if ((traces < 2) || (traces > *x_max)) + return -1; + + *width = *x_max / (traces - 1); + break; } return 0; @@ -696,9 +885,9 @@ static int elantech_set_input_params(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; - unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0; + unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; - if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max)) + if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) return -1; __set_bit(EV_KEY, dev->evbit); @@ -742,9 +931,37 @@ static int elantech_set_input_params(struct psmouse *psmouse) input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); break; + + case 4: + __set_bit(BTN_TOOL_QUADTAP, dev->keybit); + /* For X to recognize me as touchpad. */ + input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); + /* + * range of pressure and width is the same as v2, + * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility. + */ + input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, + ETP_PMAX_V2, 0, 0); + input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, + ETP_WMAX_V2, 0, 0); + /* Multitouch capable pad, up to 5 fingers. */ + input_mt_init_slots(dev, ETP_MAX_FINGERS); + input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); + input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2, + ETP_PMAX_V2, 0, 0); + /* + * The firmware reports how many trace lines the finger spans, + * convert to surface unit as Protocol-B requires. + */ + input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, + ETP_WMAX_V2 * width, 0, 0); + break; } etd->y_max = y_max; + etd->width = width; return 0; } @@ -816,6 +1033,7 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse, elantech_show_int_attr, \ elantech_set_int_attr) +ELANTECH_INT_ATTR(reg_07, 0x07); ELANTECH_INT_ATTR(reg_10, 0x10); ELANTECH_INT_ATTR(reg_11, 0x11); ELANTECH_INT_ATTR(reg_20, 0x20); @@ -829,6 +1047,7 @@ ELANTECH_INT_ATTR(debug, 0); ELANTECH_INT_ATTR(paritycheck, 0); static struct attribute *elantech_attrs[] = { + &psmouse_attr_reg_07.dattr.attr, &psmouse_attr_reg_10.dattr.attr, &psmouse_attr_reg_11.dattr.attr, &psmouse_attr_reg_20.dattr.attr, @@ -957,12 +1176,16 @@ static int elantech_reconnect(struct psmouse *psmouse) */ static int elantech_set_properties(struct elantech_data *etd) { + int ver = (etd->fw_version & 0x0f0000) >> 16; + if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) etd->hw_version = 1; else if (etd->fw_version < 0x150600) etd->hw_version = 2; - else if ((etd->fw_version & 0x0f0000) >> 16 == 5) + else if (ver == 5) etd->hw_version = 3; + else if (ver == 6) + etd->hw_version = 4; else return -1; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 236c33cdc70..7ecaef0c07c 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -82,14 +82,37 @@ #define ETP_WMAX_V2 15 /* - * v3 hardware has 2 kinds of packet types. + * v3 hardware has 2 kinds of packet types, + * v4 hardware has 3. */ #define PACKET_UNKNOWN 0x01 #define PACKET_DEBOUNCE 0x02 #define PACKET_V3_HEAD 0x03 #define PACKET_V3_TAIL 0x04 +#define PACKET_V4_HEAD 0x05 +#define PACKET_V4_MOTION 0x06 +#define PACKET_V4_STATUS 0x07 + +/* + * track up to 5 fingers for v4 hardware + */ +#define ETP_MAX_FINGERS 5 + +/* + * weight value for v4 hardware + */ +#define ETP_WEIGHT_VALUE 5 + +/* + * The base position for one finger, v4 hardware + */ +struct finger_pos { + unsigned int x; + unsigned int y; +}; struct elantech_data { + unsigned char reg_07; unsigned char reg_10; unsigned char reg_11; unsigned char reg_20; @@ -108,8 +131,8 @@ struct elantech_data { unsigned int fw_version; unsigned int single_finger_reports; unsigned int y_max; - unsigned int prev_x; - unsigned int prev_y; + unsigned int width; + struct finger_pos mt[ETP_MAX_FINGERS]; unsigned char parity[256]; }; -- cgit v1.2.3-70-g09d2 From 84a90b610a1473d732818ec5d041ab18eae77f14 Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Tue, 20 Sep 2011 22:42:51 -0700 Subject: Input: elantech - better support all those v2 variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V2 hardware has many variants. This patch adddresses two issues: - some model also has debounce packets, but with a different signature than v3. Now we just check debounce for all v2 hardware. - due to different scanning methods the hardware uses, x and y ranges have to be calculated differently. And for some specific versions, we can just see them as custom-made, so set {x, y} the same values as Windows driver does. Signed-off-by: JJ Ding Tested-by: Richard Schütz Reviewed-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 46 +++++++++++++++++++++++++++++++++++++----- drivers/input/mouse/elantech.h | 1 + 2 files changed, 42 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index b8733b37726..c2d91ebbadf 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -613,6 +613,18 @@ static int elantech_packet_check_v1(struct psmouse *psmouse) etd->parity[packet[3]] == p3; } +static int elantech_debounce_check_v2(struct psmouse *psmouse) +{ + /* + * When we encounter packet that matches this exactly, it means the + * hardware is in debounce status. Just ignore the whole packet. + */ + const u8 debounce_packet[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff }; + unsigned char *packet = psmouse->packet; + + return !memcmp(packet, debounce_packet, sizeof(debounce_packet)); +} + static int elantech_packet_check_v2(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; @@ -708,6 +720,10 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) break; case 2: + /* ignore debounce */ + if (elantech_debounce_check_v2(psmouse)) + return PSMOUSE_FULL_PACKET; + if (etd->paritycheck && !elantech_packet_check_v2(psmouse)) return PSMOUSE_BAD_DATA; @@ -825,7 +841,6 @@ static int elantech_set_range(struct psmouse *psmouse, struct elantech_data *etd = psmouse->private; unsigned char param[3]; unsigned char traces; - int i; switch (etd->hw_version) { case 1: @@ -844,12 +859,33 @@ static int elantech_set_range(struct psmouse *psmouse, *x_max = ETP_XMAX_V2; *y_max = ETP_YMAX_V2; } else { + int i; + int fixed_dpi; + i = (etd->fw_version > 0x020800 && etd->fw_version < 0x020900) ? 1 : 2; - *x_min = 0; - *y_min = 0; - *x_max = (etd->capabilities[1] - i) * 64; - *y_max = (etd->capabilities[2] - i) * 64; + + if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -1; + + fixed_dpi = param[1] & 0x10; + + if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) { + if (synaptics_send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) + return -1; + + *x_max = (etd->capabilities[1] - i) * param[1] / 2; + *y_max = (etd->capabilities[2] - i) * param[2] / 2; + } else if (etd->fw_version == 0x040216) { + *x_max = 819; + *y_max = 405; + } else if (etd->fw_version == 0x040219 || etd->fw_version == 0x040215) { + *x_max = 900; + *y_max = 500; + } else { + *x_max = (etd->capabilities[1] - i) * 64; + *y_max = (etd->capabilities[2] - i) * 64; + } } break; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 7ecaef0c07c..9e5f1aabea7 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -19,6 +19,7 @@ #define ETP_FW_ID_QUERY 0x00 #define ETP_FW_VERSION_QUERY 0x01 #define ETP_CAPABILITIES_QUERY 0x02 +#define ETP_SAMPLE_QUERY 0x03 /* * Command values for register reading or writing -- cgit v1.2.3-70-g09d2 From 4af61e90270e35bafa9e99a3c48fb3f363da592d Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Tue, 20 Sep 2011 22:42:51 -0700 Subject: Input: elantech - remove module parameter force_elantech MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This essentially reverts commit f81bc788ff91d4efd4baf88b2c29713838caa8e5. With recent work on elantech driver, I believe we now have complete support for all elantech touchpads. So remove this hack. Signed-off-by: JJ Ding Reviewed-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index c2d91ebbadf..25290b395c8 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -28,10 +28,6 @@ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ } while (0) -static bool force_elantech; -module_param_named(force_elantech, force_elantech, bool, 0644); -MODULE_PARM_DESC(force_elantech, "Force the Elantech PS/2 protocol extension to be used, 1 = enabled, 0 = disabled (default)."); - /* * Send a Synaptics style sliced query command */ @@ -1164,12 +1160,8 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) param[0], param[1], param[2]); if (!elantech_is_signature_valid(param)) { - if (!force_elantech) { - pr_debug("Probably not a real Elantech touchpad. Aborting.\n"); - return -1; - } - - pr_debug("Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n"); + pr_debug("Probably not a real Elantech touchpad. Aborting.\n"); + return -1; } if (set_properties) { -- cgit v1.2.3-70-g09d2 From 21ae508bab28c2b0ae8709c95a36739b6f1ae5be Mon Sep 17 00:00:00 2001 From: John Sung Date: Fri, 9 Sep 2011 13:33:12 -0700 Subject: Input: penmount - fix the protocol The MSB and LSB of the XY axis value are switched according to the PenMount 9000 protocol. The driver name is also changed from penmountlpc, since it is not for LPC interface at all. Signed-off-by: John Sung Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/penmount.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index c7f9cebebbb..3342c6d8e57 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -2,6 +2,7 @@ * Penmount serial touchscreen driver * * Copyright (c) 2006 Rick Koch + * Copyright (c) 2011 John Sung * * Based on ELO driver (drivers/input/touchscreen/elo.c) * Copyright (c) 2004 Vojtech Pavlik @@ -21,9 +22,10 @@ #include #include -#define DRIVER_DESC "Penmount serial touchscreen driver" +#define DRIVER_DESC "PenMount serial touchscreen driver" MODULE_AUTHOR("Rick Koch "); +MODULE_AUTHOR("John Sung "); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); @@ -55,8 +57,8 @@ static irqreturn_t pm_interrupt(struct serio *serio, if (pm->data[0] & 0x80) { if (PM_MAX_LENGTH == ++pm->idx) { - input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]); - input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]); + input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]); + input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]); input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); input_sync(dev); pm->idx = 0; @@ -84,7 +86,7 @@ static void pm_disconnect(struct serio *serio) /* * pm_connect() is the routine that is called when someone adds a - * new serio device that supports Gunze protocol and registers it as + * new serio device that supports PenMount protocol and registers it as * an input device. */ @@ -105,7 +107,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) pm->dev = input_dev; snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); - input_dev->name = "Penmount Serial TouchScreen"; + input_dev->name = "PenMount Serial TouchScreen"; input_dev->phys = pm->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_PENMOUNT; @@ -155,7 +157,7 @@ MODULE_DEVICE_TABLE(serio, pm_serio_ids); static struct serio_driver pm_drv = { .driver = { - .name = "penmountlpc", + .name = "serio-penmount", }, .description = DRIVER_DESC, .id_table = pm_serio_ids, -- cgit v1.2.3-70-g09d2 From c42e2e406ad49f320947ba044d3bbf9b05703089 Mon Sep 17 00:00:00 2001 From: John Sung Date: Fri, 9 Sep 2011 13:33:12 -0700 Subject: Input: penmount - add PenMount 6000 support Add support for PenMount 6000 touch controller. Signed-off-by: John Sung Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/penmount.c | 65 +++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index 3342c6d8e57..e9117adcf6d 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -33,7 +33,7 @@ MODULE_LICENSE("GPL"); * Definitions & global arrays. */ -#define PM_MAX_LENGTH 5 +#define PM_MAX_LENGTH 6 /* * Per-touchscreen data. @@ -45,8 +45,24 @@ struct pm { int idx; unsigned char data[PM_MAX_LENGTH]; char phys[32]; + unsigned char packetsize; }; +/* + * pm_checkpacket() checks if data packet is valid + */ + +static bool pm_checkpacket(unsigned char *packet) +{ + int total = 0; + int i; + + for (i = 0; i < 5; i++) + total += packet[i]; + + return packet[5] == (unsigned char)~(total & 0xff); +} + static irqreturn_t pm_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { @@ -55,14 +71,34 @@ static irqreturn_t pm_interrupt(struct serio *serio, pm->data[pm->idx] = data; - if (pm->data[0] & 0x80) { - if (PM_MAX_LENGTH == ++pm->idx) { - input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]); - input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]); - input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); - input_sync(dev); - pm->idx = 0; + switch (pm->dev->id.product) { + case 0x9000: + if (pm->data[0] & 0x80) { + if (pm->packetsize == ++pm->idx) { + input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]); + input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]); + input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); + input_sync(dev); + pm->idx = 0; + } + } + break; + + case 0x6000: + if ((pm->data[0] & 0xbf) == 0x30) { + if (pm->packetsize == ++pm->idx) { + if (pm_checkpacket(pm->data)) { + input_report_abs(dev, ABS_X, + pm->data[2] * 256 + pm->data[1]); + input_report_abs(dev, ABS_Y, + pm->data[4] * 256 + pm->data[3]); + input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); + input_sync(dev); + } + pm->idx = 0; + } } + break; } return IRQ_HANDLED; @@ -120,6 +156,19 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0); input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0); + switch (serio->id.id) { + default: + case 0: + pm->packetsize = 5; + input_dev->id.product = 0x9000; + break; + + case 1: + pm->packetsize = 6; + input_dev->id.product = 0x6000; + break; + } + serio_set_drvdata(serio, pm); err = serio_open(serio, drv); -- cgit v1.2.3-70-g09d2 From 90aba7d8b155c2c39e269608e4a446190e3cd704 Mon Sep 17 00:00:00 2001 From: John Sung Date: Fri, 9 Sep 2011 13:33:12 -0700 Subject: Input: penmount - add PenMount 3000 support Add dual touch support for PenMount 3000 touch controller. Signed-off-by: John Sung Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/penmount.c | 79 ++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index e9117adcf6d..71422b91dc4 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,17 @@ MODULE_LICENSE("GPL"); */ #define PM_MAX_LENGTH 6 +#define PM_MAX_MTSLOT 16 +#define PM_3000_MTSLOT 2 + +/* + * Multi-touch slot + */ + +struct mt_slot { + unsigned short x, y; + bool active; /* is the touch valid? */ +}; /* * Per-touchscreen data. @@ -46,8 +58,32 @@ struct pm { unsigned char data[PM_MAX_LENGTH]; char phys[32]; unsigned char packetsize; + unsigned char maxcontacts; + struct mt_slot slots[PM_MAX_MTSLOT]; }; +/* + * pm_mtevent() sends mt events and also emulates pointer movement + */ + +static void pm_mtevent(struct pm *pm, struct input_dev *input) +{ + int i; + + for (i = 0; i < pm->maxcontacts; ++i) { + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, + pm->slots[i].active); + if (pm->slots[i].active) { + input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y); + } + } + + input_mt_report_pointer_emulation(input, true); + input_sync(input); +} + /* * pm_checkpacket() checks if data packet is valid */ @@ -99,6 +135,21 @@ static irqreturn_t pm_interrupt(struct serio *serio, } } break; + + case 0x3000: + if ((pm->data[0] & 0xce) == 0x40) { + if (pm->packetsize == ++pm->idx) { + if (pm_checkpacket(pm->data)) { + int slotnum = pm->data[0] & 0x0f; + pm->slots[slotnum].active = pm->data[0] & 0x30; + pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1]; + pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3]; + pm_mtevent(pm, dev); + } + pm->idx = 0; + } + } + break; } return IRQ_HANDLED; @@ -130,6 +181,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) { struct pm *pm; struct input_dev *input_dev; + int max_x, max_y; int err; pm = kzalloc(sizeof(struct pm), GFP_KERNEL); @@ -142,6 +194,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) pm->serio = serio; pm->dev = input_dev; snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); + pm->maxcontacts = 1; input_dev->name = "PenMount Serial TouchScreen"; input_dev->phys = pm->phys; @@ -151,24 +204,42 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.version = 0x0100; input_dev->dev.parent = &serio->dev; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0); - input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); switch (serio->id.id) { default: case 0: pm->packetsize = 5; input_dev->id.product = 0x9000; + max_x = max_y = 0x3ff; break; case 1: pm->packetsize = 6; input_dev->id.product = 0x6000; + max_x = max_y = 0x3ff; + break; + + case 2: + pm->packetsize = 6; + input_dev->id.product = 0x3000; + max_x = max_y = 0x7ff; + pm->maxcontacts = PM_3000_MTSLOT; break; } + input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0); + input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0); + + if (pm->maxcontacts > 1) { + input_mt_init_slots(pm->dev, pm->maxcontacts); + input_set_abs_params(pm->dev, + ABS_MT_POSITION_X, 0, max_x, 0, 0); + input_set_abs_params(pm->dev, + ABS_MT_POSITION_Y, 0, max_y, 0, 0); + } + serio_set_drvdata(serio, pm); err = serio_open(serio, drv); -- cgit v1.2.3-70-g09d2 From bd8f6d2ed416d6c70fc3d4f98b165a56e025331c Mon Sep 17 00:00:00 2001 From: John Sung Date: Fri, 9 Sep 2011 13:33:12 -0700 Subject: Input: penmount - add PenMount 6250 support Add multi touch support for PenMount 6250 touch controller. Signed-off-by: John Sung Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/penmount.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index 71422b91dc4..a047850e38b 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -37,6 +37,7 @@ MODULE_LICENSE("GPL"); #define PM_MAX_LENGTH 6 #define PM_MAX_MTSLOT 16 #define PM_3000_MTSLOT 2 +#define PM_6250_MTSLOT 12 /* * Multi-touch slot @@ -150,6 +151,21 @@ static irqreturn_t pm_interrupt(struct serio *serio, } } break; + + case 0x6250: + if ((pm->data[0] & 0xb0) == 0x30) { + if (pm->packetsize == ++pm->idx) { + if (pm_checkpacket(pm->data)) { + int slotnum = pm->data[0] & 0x0f; + pm->slots[slotnum].active = pm->data[0] & 0x40; + pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1]; + pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3]; + pm_mtevent(pm, dev); + } + pm->idx = 0; + } + } + break; } return IRQ_HANDLED; @@ -227,6 +243,13 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) max_x = max_y = 0x7ff; pm->maxcontacts = PM_3000_MTSLOT; break; + + case 3: + pm->packetsize = 6; + input_dev->id.product = 0x6250; + max_x = max_y = 0x3ff; + pm->maxcontacts = PM_6250_MTSLOT; + break; } input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0); -- cgit v1.2.3-70-g09d2 From 98b013eb7a94cfd29fcc782f3b7d9f9fe06ac50d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 12 Sep 2011 22:12:58 -0700 Subject: Input: penmount - rework handling of different protocols Instead of having one large switch based on product ID use pointer to function actually doing protocol decoding. Tested-by: John Sung Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/penmount.c | 120 +++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 56 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index a047850e38b..7fc556295c0 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -61,6 +61,7 @@ struct pm { unsigned char packetsize; unsigned char maxcontacts; struct mt_slot slots[PM_MAX_MTSLOT]; + void (*parse_packet)(struct pm *); }; /* @@ -100,73 +101,76 @@ static bool pm_checkpacket(unsigned char *packet) return packet[5] == (unsigned char)~(total & 0xff); } -static irqreturn_t pm_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) +static void pm_parse_9000(struct pm *pm) { - struct pm *pm = serio_get_drvdata(serio); struct input_dev *dev = pm->dev; - pm->data[pm->idx] = data; + if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) { + input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]); + input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]); + input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); + input_sync(dev); + pm->idx = 0; + } +} - switch (pm->dev->id.product) { - case 0x9000: - if (pm->data[0] & 0x80) { - if (pm->packetsize == ++pm->idx) { - input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]); - input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]); - input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); - input_sync(dev); - pm->idx = 0; - } - } - break; +static void pm_parse_6000(struct pm *pm) +{ + struct input_dev *dev = pm->dev; - case 0x6000: - if ((pm->data[0] & 0xbf) == 0x30) { - if (pm->packetsize == ++pm->idx) { - if (pm_checkpacket(pm->data)) { - input_report_abs(dev, ABS_X, - pm->data[2] * 256 + pm->data[1]); - input_report_abs(dev, ABS_Y, - pm->data[4] * 256 + pm->data[3]); - input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); - input_sync(dev); - } - pm->idx = 0; - } + if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) { + if (pm_checkpacket(pm->data)) { + input_report_abs(dev, ABS_X, + pm->data[2] * 256 + pm->data[1]); + input_report_abs(dev, ABS_Y, + pm->data[4] * 256 + pm->data[3]); + input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40); + input_sync(dev); } - break; + pm->idx = 0; + } +} + +static void pm_parse_3000(struct pm *pm) +{ + struct input_dev *dev = pm->dev; - case 0x3000: - if ((pm->data[0] & 0xce) == 0x40) { - if (pm->packetsize == ++pm->idx) { - if (pm_checkpacket(pm->data)) { - int slotnum = pm->data[0] & 0x0f; - pm->slots[slotnum].active = pm->data[0] & 0x30; - pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1]; - pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3]; - pm_mtevent(pm, dev); - } - pm->idx = 0; - } + if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) { + if (pm_checkpacket(pm->data)) { + int slotnum = pm->data[0] & 0x0f; + pm->slots[slotnum].active = pm->data[0] & 0x30; + pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1]; + pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3]; + pm_mtevent(pm, dev); } - break; + pm->idx = 0; + } +} + +static void pm_parse_6250(struct pm *pm) +{ + struct input_dev *dev = pm->dev; - case 0x6250: - if ((pm->data[0] & 0xb0) == 0x30) { - if (pm->packetsize == ++pm->idx) { - if (pm_checkpacket(pm->data)) { - int slotnum = pm->data[0] & 0x0f; - pm->slots[slotnum].active = pm->data[0] & 0x40; - pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1]; - pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3]; - pm_mtevent(pm, dev); - } - pm->idx = 0; - } + if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) { + if (pm_checkpacket(pm->data)) { + int slotnum = pm->data[0] & 0x0f; + pm->slots[slotnum].active = pm->data[0] & 0x40; + pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1]; + pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3]; + pm_mtevent(pm, dev); } - break; + pm->idx = 0; } +} + +static irqreturn_t pm_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) +{ + struct pm *pm = serio_get_drvdata(serio); + + pm->data[pm->idx] = data; + + pm->parse_packet(pm); return IRQ_HANDLED; } @@ -227,18 +231,21 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) default: case 0: pm->packetsize = 5; + pm->parse_packet = pm_parse_9000; input_dev->id.product = 0x9000; max_x = max_y = 0x3ff; break; case 1: pm->packetsize = 6; + pm->parse_packet = pm_parse_6000; input_dev->id.product = 0x6000; max_x = max_y = 0x3ff; break; case 2: pm->packetsize = 6; + pm->parse_packet = pm_parse_3000; input_dev->id.product = 0x3000; max_x = max_y = 0x7ff; pm->maxcontacts = PM_3000_MTSLOT; @@ -246,6 +253,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) case 3: pm->packetsize = 6; + pm->parse_packet = pm_parse_6250; input_dev->id.product = 0x6250; max_x = max_y = 0x3ff; pm->maxcontacts = PM_6250_MTSLOT; -- cgit v1.2.3-70-g09d2 From c3a01ba9e45f01c6505a41efb33c420a0c959eb3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 12 Sep 2011 22:13:00 -0700 Subject: Input: penmount - simplify unregister procedure Since touchscreen driver does not handle any events to be sent to the device we can close serio port first and then unregister the input device. Tested-by: John Sung Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/penmount.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index 7fc556295c0..4c012fb2b01 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -183,12 +183,12 @@ static void pm_disconnect(struct serio *serio) { struct pm *pm = serio_get_drvdata(serio); - input_get_device(pm->dev); - input_unregister_device(pm->dev); serio_close(serio); - serio_set_drvdata(serio, NULL); - input_put_device(pm->dev); + + input_unregister_device(pm->dev); kfree(pm); + + serio_set_drvdata(serio, NULL); } /* -- cgit v1.2.3-70-g09d2 From cca84699a079a91b0a0cb4f2da8548e56859376a Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 9 Sep 2011 11:09:50 -0700 Subject: Input: gpio_keys - use of_property_read_u32() Use the of_property_read_u32() helper function to retrieve u32 values from the device tree. Also do not pass the len parameter to of_get_property if it isn't checked afterwards. Signed-off-by: Tobias Klauser Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 67df91af842..ed1ed469d08 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -461,8 +461,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, struct device_node *node, *pp; int i; struct gpio_keys_button *buttons; - const u32 *reg; - int len; + u32 reg; node = dev->of_node; if (node == NULL) @@ -470,7 +469,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, memset(pdata, 0, sizeof *pdata); - pdata->rep = !!of_get_property(node, "autorepeat", &len); + pdata->rep = !!of_get_property(node, "autorepeat", NULL); /* First count the subnodes */ pdata->nbuttons = 0; @@ -498,22 +497,25 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags); buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW; - reg = of_get_property(pp, "linux,code", &len); - if (!reg) { + if (of_property_read_u32(pp, "linux,code", ®)) { dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio); goto out_fail; } - buttons[i].code = be32_to_cpup(reg); + buttons[i].code = reg; - buttons[i].desc = of_get_property(pp, "label", &len); + buttons[i].desc = of_get_property(pp, "label", NULL); - reg = of_get_property(pp, "linux,input-type", &len); - buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY; + if (of_property_read_u32(pp, "linux,input-type", ®) == 0) + buttons[i].type = reg; + else + buttons[i].type = EV_KEY; buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); - reg = of_get_property(pp, "debounce-interval", &len); - buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5; + if (of_property_read_u32(pp, "debounce-interval", ®) == 0) + buttons[i].debounce_interval = reg; + else + buttons[i].debounce_interval = 5; i++; } -- cgit v1.2.3-70-g09d2 From f01536e3d68bacaf827325b716c743c542d20b64 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 28 Sep 2011 10:04:21 -0700 Subject: Input: add a driver for TSC-40 serial touchscreen This patch adds the TSC-40 serial touchscreen driver and should be compatible with TSC-10 and TSC-25. The driver was written by Linutronix on behalf of Bachmann electronic GmbH. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Christian Gmeiner Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 +++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/tsc40.c | 184 +++++++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 198 insertions(+) create mode 100644 drivers/input/touchscreen/tsc40.c (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index cabd9e54863..3488ffe1fa0 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -651,6 +651,18 @@ config TOUCHSCREEN_TOUCHIT213 To compile this driver as a module, choose M here: the module will be called touchit213. +config TOUCHSCREEN_TSC_SERIO + tristate "TSC-10/25/40 serial touchscreen support" + select SERIO + help + Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected + to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called tsc40. + config TOUCHSCREEN_TSC2005 tristate "TSC2005 based touchscreens" depends on SPI_MASTER && GENERIC_HARDIRQS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 282d6f76ae2..f957676035a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o +obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c new file mode 100644 index 00000000000..29d5ed4dd31 --- /dev/null +++ b/drivers/input/touchscreen/tsc40.c @@ -0,0 +1,184 @@ +/* + * TSC-40 serial touchscreen driver. It should be compatible with + * TSC-10 and 25. + * + * Author: Sebastian Andrzej Siewior + * License: GPLv2 as published by the FSF. + */ + +#include +#include +#include +#include +#include +#include + +#define PACKET_LENGTH 5 +struct tsc_ser { + struct input_dev *dev; + struct serio *serio; + u32 idx; + unsigned char data[PACKET_LENGTH]; + char phys[32]; +}; + +static void tsc_process_data(struct tsc_ser *ptsc) +{ + struct input_dev *dev = ptsc->dev; + u8 *data = ptsc->data; + u32 x; + u32 y; + + x = ((data[1] & 0x03) << 8) | data[2]; + y = ((data[3] & 0x03) << 8) | data[4]; + + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_key(dev, BTN_TOUCH, 1); + + input_sync(dev); +} + +static irqreturn_t tsc_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) +{ + struct tsc_ser *ptsc = serio_get_drvdata(serio); + struct input_dev *dev = ptsc->dev; + + ptsc->data[ptsc->idx] = data; + switch (ptsc->idx++) { + case 0: + if (unlikely((data & 0x3e) != 0x10)) { + dev_dbg(&serio->dev, + "unsynchronized packet start (0x%02x)\n", data); + ptsc->idx = 0; + } else if (!(data & 0x01)) { + input_report_key(dev, BTN_TOUCH, 0); + input_sync(dev); + ptsc->idx = 0; + } + break; + + case 1: + case 3: + if (unlikely(data & 0xfc)) { + dev_dbg(&serio->dev, + "unsynchronized data 0x%02x at offset %d\n", + data, ptsc->idx - 1); + ptsc->idx = 0; + } + break; + + case 4: + tsc_process_data(ptsc); + ptsc->idx = 0; + break; + } + + return IRQ_HANDLED; +} + +static int tsc_connect(struct serio *serio, struct serio_driver *drv) +{ + struct tsc_ser *ptsc; + struct input_dev *input_dev; + int error; + + ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ptsc || !input_dev) { + error = -ENOMEM; + goto fail1; + } + + ptsc->serio = serio; + ptsc->dev = input_dev; + snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys); + + input_dev->name = "TSC-10/25/40 Serial TouchScreen"; + input_dev->phys = ptsc->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_TSC40; + input_dev->id.product = 40; + input_dev->id.version = 0x0001; + input_dev->dev.parent = &serio->dev; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + __set_bit(BTN_TOUCH, input_dev->keybit); + input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0); + input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0); + input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0); + + serio_set_drvdata(serio, ptsc); + + error = serio_open(serio, drv); + if (error) + goto fail2; + + error = input_register_device(ptsc->dev); + if (error) + goto fail3; + + return 0; + +fail3: + serio_close(serio); +fail2: + serio_set_drvdata(serio, NULL); +fail1: + input_free_device(input_dev); + kfree(ptsc); + return error; +} + +static void tsc_disconnect(struct serio *serio) +{ + struct tsc_ser *ptsc = serio_get_drvdata(serio); + + serio_close(serio); + + input_unregister_device(ptsc->dev); + kfree(ptsc); + + serio_set_drvdata(serio, NULL); +} + +static struct serio_device_id tsc_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_TSC40, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; +MODULE_DEVICE_TABLE(serio, tsc_serio_ids); + +#define DRIVER_DESC "TSC-10/25/40 serial touchscreen driver" + +static struct serio_driver tsc_drv = { + .driver = { + .name = "tsc40", + }, + .description = DRIVER_DESC, + .id_table = tsc_serio_ids, + .interrupt = tsc_interrupt, + .connect = tsc_connect, + .disconnect = tsc_disconnect, +}; + +static int __init tsc_ser_init(void) +{ + return serio_register_driver(&tsc_drv); +} +module_init(tsc_ser_init); + +static void __exit tsc_exit(void) +{ + serio_unregister_driver(&tsc_drv); +} +module_exit(tsc_exit); + +MODULE_AUTHOR("Sebastian Andrzej Siewior "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/serio.h b/include/linux/serio.h index e26f4788845..be7dfb0f12d 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -199,5 +199,6 @@ static inline void serio_continue_rx(struct serio *serio) #define SERIO_DYNAPRO 0x3a #define SERIO_HAMPSHIRE 0x3b #define SERIO_PS2MULT 0x3c +#define SERIO_TSC40 0x3d #endif -- cgit v1.2.3-70-g09d2 From f4fa9a6d80a61e5ae01e41262ff8b913deb92378 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 4 Oct 2011 23:49:42 -0700 Subject: Input: wacom - lower the LED luminance The LED luminance level is normally lower when no button is pressed. Reviewed-by: Eduard Hasenleithner Tested-by: Eduard Hasenleithner Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- Documentation/ABI/testing/sysfs-driver-wacom | 3 ++- drivers/input/tablet/wacom_sys.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index dfe1d460cf5..b1d5c17dd67 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -25,7 +25,8 @@ Contact: linux-input@vger.kernel.org Description: Writing to this file sets the status LED luminance (0..127) when the stylus does not touch the tablet surface, and no - button is pressed on the stylus. + button is pressed on the stylus. This luminance level is + normally lower than the level when a button is pressed. What: /sys/bus/usb/devices/-:./wacom_led/status1_luminance Date: August 2011 diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 0eccf57df5c..4f5e62a1621 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -678,7 +678,7 @@ static int wacom_initialize_leds(struct wacom *wacom) /* Initialize default values */ wacom->led.select = 0; - wacom->led.llv = 30; + wacom->led.llv = 10; wacom->led.hlv = 20; wacom->led.img_lum = 10; wacom_led_control(wacom); -- cgit v1.2.3-70-g09d2 From 77e82516a69ad7dd10ada425930ba35e933abcfb Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 4 Oct 2011 23:50:42 -0700 Subject: Input: wacom - don't expose LED inactive option The LED also indicates the status of the tablet. Don't turn it off. Reviewed-by: Eduard Hasenleithner Tested-by: Eduard Hasenleithner Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- Documentation/ABI/testing/sysfs-driver-wacom | 8 +++----- drivers/input/tablet/wacom.h | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index b1d5c17dd67..b5601859de5 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -23,7 +23,7 @@ What: /sys/bus/usb/devices/-:./wacom_led/status0_lum Date: August 2011 Contact: linux-input@vger.kernel.org Description: - Writing to this file sets the status LED luminance (0..127) + Writing to this file sets the status LED luminance (1..127) when the stylus does not touch the tablet surface, and no button is pressed on the stylus. This luminance level is normally lower than the level when a button is pressed. @@ -32,7 +32,7 @@ What: /sys/bus/usb/devices/-:./wacom_led/status1_lum Date: August 2011 Contact: linux-input@vger.kernel.org Description: - Writing to this file sets the status LED luminance (0..127) + Writing to this file sets the status LED luminance (1..127) when the stylus touches the tablet surface, or any button is pressed on the stylus. @@ -41,9 +41,7 @@ Date: August 2011 Contact: linux-input@vger.kernel.org Description: Writing to this file sets which one of the four status LEDs is - active (0..3). The other three LEDs are always inactive. By - means of specifying "-1" it is possible to set all status LEDs - to inactive. + active (0..3). The other three LEDs are always inactive. What: /sys/bus/usb/devices/-:./wacom_led/buttons_luminance Date: August 2011 diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 00332d66bc4..561f1072343 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -115,9 +115,9 @@ struct wacom { bool open; char phys[32]; struct wacom_led { - u8 select; /* status led selector (0..3, -1=none) */ - u8 llv; /* status led brightness no button */ - u8 hlv; /* status led brightness button pressed */ + u8 select; /* status led selector (0..3) */ + u8 llv; /* status led brightness no button (1..127) */ + u8 hlv; /* status led brightness button pressed (1..127) */ u8 img_lum; /* OLED matrix display brightness */ } led; }; -- cgit v1.2.3-70-g09d2 From 09e7d9410764f96f83ebf4a435028ac5e6240af6 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 4 Oct 2011 23:51:14 -0700 Subject: Input: wacom - add LED support for Cintiq 21ux2 Cintiq 21ux2 has two sets of four LEDs on right and left side of the tablet, respectively. Reviewed-by: Eduard Hasenleithner Tested-by: Eduard Hasenleithner Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- Documentation/ABI/testing/sysfs-driver-wacom | 23 +++++-- drivers/input/tablet/wacom.h | 10 +-- drivers/input/tablet/wacom_sys.c | 98 +++++++++++++++++++++------- 3 files changed, 94 insertions(+), 37 deletions(-) (limited to 'drivers/input') diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index b5601859de5..82d4df13644 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -13,11 +13,11 @@ What: /sys/bus/usb/devices/-:./wacom_led/led Date: August 2011 Contact: linux-input@vger.kernel.org Description: - Attribute group for control of the status LEDs and the OLED - displays found on the Wacom Intuos 4 M, L, and XL tablets. This - attribute group is not available for other Wacom tablets. + Attribute group for control of the status LEDs and the OLEDs. + This attribute group is only available for Intuos 4 M, L, + and XL (with LEDs and OLEDs) and Cintiq 21UX2 (LEDs only). Therefore its presence implicitly signifies the presence of - said LEDs and OLED displays on the tablet device. + said LEDs and OLEDs on the tablet device. What: /sys/bus/usb/devices/-:./wacom_led/status0_luminance Date: August 2011 @@ -36,12 +36,21 @@ Description: when the stylus touches the tablet surface, or any button is pressed on the stylus. -What: /sys/bus/usb/devices/-:./wacom_led/status_led_select +What: /sys/bus/usb/devices/-:./wacom_led/status_led0_select Date: August 2011 Contact: linux-input@vger.kernel.org Description: - Writing to this file sets which one of the four status LEDs is - active (0..3). The other three LEDs are always inactive. + Writing to this file sets which one of the four (for Intuos 4) + or of the right four (for Cintiq 21UX2) status LEDs is active (0..3). + The other three LEDs on the same side are always inactive. + +What: /sys/bus/usb/devices/-:./wacom_led/status_led1_select +Date: September 2011 +Contact: linux-input@vger.kernel.org +Description: + Writing to this file sets which one of the left four (for Cintiq 21UX2) + status LEDs is active (0..3). The other three LEDs on the left are always + inactive. What: /sys/bus/usb/devices/-:./wacom_led/buttons_luminance Date: August 2011 diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 561f1072343..0783864a7dc 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -11,7 +11,7 @@ * Copyright (c) 2000 Daniel Egger * Copyright (c) 2001 Frederic Lepied * Copyright (c) 2004 Panagiotis Issaris - * Copyright (c) 2002-2009 Ping Cheng + * Copyright (c) 2002-2011 Ping Cheng * * ChangeLog: * v0.1 (vp) - Initial release @@ -93,7 +93,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.52" +#define DRIVER_VERSION "v1.53" #define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB Wacom tablet driver" #define DRIVER_LICENSE "GPL" @@ -115,9 +115,9 @@ struct wacom { bool open; char phys[32]; struct wacom_led { - u8 select; /* status led selector (0..3) */ - u8 llv; /* status led brightness no button (1..127) */ - u8 hlv; /* status led brightness button pressed (1..127) */ + u8 select[2]; /* status led selector (0..3) */ + u8 llv; /* status led brightness no button (1..127) */ + u8 hlv; /* status led brightness button pressed (1..127) */ u8 img_lum; /* OLED matrix display brightness */ } led; }; diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 4f5e62a1621..abe5920e2cd 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -493,14 +493,19 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom) static int wacom_led_control(struct wacom *wacom) { unsigned char *buf; - int retval; + int retval, led = 0; buf = kzalloc(9, GFP_KERNEL); if (!buf) return -ENOMEM; + if (wacom->wacom_wac.features.type == WACOM_21UX2) + led = (wacom->led.select[1] << 4) | 0x40; + + led |= wacom->led.select[0] | 0x4; + buf[0] = WAC_CMD_LED_CONTROL; - buf[1] = wacom->led.select >= 0 ? wacom->led.select | 4 : 0; + buf[1] = led; buf[2] = wacom->led.llv; buf[3] = wacom->led.hlv; buf[4] = wacom->led.img_lum; @@ -552,8 +557,7 @@ out: return retval; } -static ssize_t wacom_led_select_store(struct device *dev, - struct device_attribute *attr, +static ssize_t wacom_led_select_store(struct device *dev, int set_id, const char *buf, size_t count) { struct wacom *wacom = dev_get_drvdata(dev); @@ -566,7 +570,7 @@ static ssize_t wacom_led_select_store(struct device *dev, mutex_lock(&wacom->lock); - wacom->led.select = id; + wacom->led.select[set_id] = id & 0x3; err = wacom_led_control(wacom); mutex_unlock(&wacom->lock); @@ -574,7 +578,17 @@ static ssize_t wacom_led_select_store(struct device *dev, return err < 0 ? err : count; } -static DEVICE_ATTR(status_led_select, S_IWUSR, NULL, wacom_led_select_store); +#define DEVICE_LED_SELECT_ATTR(SET_ID) \ +static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return wacom_led_select_store(dev, SET_ID, buf, count); \ +} \ +static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR, NULL, \ + wacom_led##SET_ID##_select_store) + +DEVICE_LED_SELECT_ATTR(0); +DEVICE_LED_SELECT_ATTR(1); static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest, const char *buf, size_t count) @@ -648,10 +662,21 @@ DEVICE_BTNIMG_ATTR(5); DEVICE_BTNIMG_ATTR(6); DEVICE_BTNIMG_ATTR(7); -static struct attribute *wacom_led_attrs[] = { +static struct attribute *cintiq_led_attrs[] = { + &dev_attr_status_led0_select.attr, + &dev_attr_status_led1_select.attr, + NULL +}; + +static struct attribute_group cintiq_led_attr_group = { + .name = "wacom_led", + .attrs = cintiq_led_attrs, +}; + +static struct attribute *intuos4_led_attrs[] = { &dev_attr_status0_luminance.attr, &dev_attr_status1_luminance.attr, - &dev_attr_status_led_select.attr, + &dev_attr_status_led0_select.attr, &dev_attr_buttons_luminance.attr, &dev_attr_button0_rawimg.attr, &dev_attr_button1_rawimg.attr, @@ -664,43 +689,66 @@ static struct attribute *wacom_led_attrs[] = { NULL }; -static struct attribute_group wacom_led_attr_group = { +static struct attribute_group intuos4_led_attr_group = { .name = "wacom_led", - .attrs = wacom_led_attrs, + .attrs = intuos4_led_attrs, }; static int wacom_initialize_leds(struct wacom *wacom) { int error; - if (wacom->wacom_wac.features.type >= INTUOS4 && - wacom->wacom_wac.features.type <= INTUOS4L) { - - /* Initialize default values */ - wacom->led.select = 0; + /* Initialize default values */ + switch (wacom->wacom_wac.features.type) { + case INTUOS4: + case INTUOS4L: + wacom->led.select[0] = 0; + wacom->led.select[1] = 0; wacom->led.llv = 10; wacom->led.hlv = 20; wacom->led.img_lum = 10; - wacom_led_control(wacom); + error = sysfs_create_group(&wacom->intf->dev.kobj, + &intuos4_led_attr_group); + break; + + case WACOM_21UX2: + wacom->led.select[0] = 0; + wacom->led.select[1] = 0; + wacom->led.llv = 0; + wacom->led.hlv = 0; + wacom->led.img_lum = 0; error = sysfs_create_group(&wacom->intf->dev.kobj, - &wacom_led_attr_group); - if (error) { - dev_err(&wacom->intf->dev, - "cannot create sysfs group err: %d\n", error); - return error; - } + &cintiq_led_attr_group); + break; + + default: + return 0; + } + + if (error) { + dev_err(&wacom->intf->dev, + "cannot create sysfs group err: %d\n", error); + return error; } + wacom_led_control(wacom); return 0; } static void wacom_destroy_leds(struct wacom *wacom) { - if (wacom->wacom_wac.features.type >= INTUOS4 && - wacom->wacom_wac.features.type <= INTUOS4L) { + switch (wacom->wacom_wac.features.type) { + case INTUOS4: + case INTUOS4L: sysfs_remove_group(&wacom->intf->dev.kobj, - &wacom_led_attr_group); + &intuos4_led_attr_group); + break; + + case WACOM_21UX2: + sysfs_remove_group(&wacom->intf->dev.kobj, + &cintiq_led_attr_group); + break; } } -- cgit v1.2.3-70-g09d2 From 04c59abd3c053f9a42437d5db3af4383cf68659c Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 4 Oct 2011 23:51:49 -0700 Subject: Input: wacom - make LED status readable through sysfs Reviewed-by: Eduard Hasenleithner Tested-by: Eduard Hasenleithner Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_sys.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index abe5920e2cd..a205055a4c5 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -584,7 +584,14 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \ { \ return wacom_led_select_store(dev, SET_ID, buf, count); \ } \ -static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR, NULL, \ +static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct wacom *wacom = dev_get_drvdata(dev); \ + return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \ +} \ +static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \ + wacom_led##SET_ID##_select_show, \ wacom_led##SET_ID##_select_store) DEVICE_LED_SELECT_ATTR(0); -- cgit v1.2.3-70-g09d2 From 626af8611211c55595cd316103abd2419cd4d861 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 6 Oct 2011 15:43:20 -0700 Subject: Input: atmel_mxt_ts - use snprintf for sysfs attribute show method Sysfs attribute show methods are always passed a buffer of length PAGE_SIZE. To keep from overwriting this buffer and causing havoc, use snprintf() to guarantee we never write more than the buffer can hold. In addition, at least for my touchscreen, the number and size of objects was far too big to fit in a single 4K page. Therefore, this patch also trims some redundant framing text to leave more room for actual data. Signed-off-by: Daniel Kurtz Acked-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index f5d66859f23..a596c2775d1 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -910,12 +910,17 @@ static ssize_t mxt_object_show(struct device *dev, for (i = 0; i < data->info.object_num; i++) { object = data->object_table + i; - count += sprintf(buf + count, - "Object Table Element %d(Type %d)\n", + count += snprintf(buf + count, PAGE_SIZE - count, + "Object[%d] (Type %d)\n", i + 1, object->type); + if (count >= PAGE_SIZE) + return PAGE_SIZE - 1; if (!mxt_object_readable(object->type)) { - count += sprintf(buf + count, "\n"); + count += snprintf(buf + count, PAGE_SIZE - count, + "\n"); + if (count >= PAGE_SIZE) + return PAGE_SIZE - 1; continue; } @@ -925,11 +930,15 @@ static ssize_t mxt_object_show(struct device *dev, if (error) return error; - count += sprintf(buf + count, - " Byte %d: 0x%x (%d)\n", j, val, val); + count += snprintf(buf + count, PAGE_SIZE - count, + "\t[%2d]: %02x (%d)\n", j, val, val); + if (count >= PAGE_SIZE) + return PAGE_SIZE - 1; } - count += sprintf(buf + count, "\n"); + count += snprintf(buf + count, PAGE_SIZE - count, "\n"); + if (count >= PAGE_SIZE) + return PAGE_SIZE - 1; } return count; -- cgit v1.2.3-70-g09d2 From cb31f898cc0dac9585f7665945bb50fc442c2109 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Oct 2011 15:26:50 -0700 Subject: Input: mma8450 - silence some 'uninitialized variable' warnings Sometimes GCC is not smart enough to recognize that x, y and z are always used properly initialized in mma8450_poll(). Let's rearrange the code a bit to help GCC. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/mma8450.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index 0794778295f..4d60080bb5d 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -88,13 +88,13 @@ static int mma8450_write(struct mma8450 *m, unsigned off, u8 v) return 0; } -static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z) +static int mma8450_read_block(struct mma8450 *m, unsigned off, + u8 *buf, size_t size) { struct i2c_client *c = m->client; - u8 buff[6]; int err; - err = i2c_smbus_read_i2c_block_data(c, MMA8450_OUT_X_LSB, 6, buff); + err = i2c_smbus_read_i2c_block_data(c, off, size, buf); if (err < 0) { dev_err(&c->dev, "failed to read block data at 0x%02x, error %d\n", @@ -102,10 +102,6 @@ static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z) return err; } - *x = ((buff[1] << 4) & 0xff0) | (buff[0] & 0xf); - *y = ((buff[3] << 4) & 0xff0) | (buff[2] & 0xf); - *z = ((buff[5] << 4) & 0xff0) | (buff[4] & 0xf); - return 0; } @@ -114,7 +110,7 @@ static void mma8450_poll(struct input_polled_dev *dev) struct mma8450 *m = dev->private; int x, y, z; int ret; - int err; + u8 buf[6]; ret = mma8450_read(m, MMA8450_STATUS); if (ret < 0) @@ -123,10 +119,14 @@ static void mma8450_poll(struct input_polled_dev *dev) if (!(ret & MMA8450_STATUS_ZXYDR)) return; - err = mma8450_read_xyz(m, &x, &y, &z); - if (err) + ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf)); + if (ret < 0) return; + x = ((buf[1] << 4) & 0xff0) | (buf[0] & 0xf); + y = ((buf[3] << 4) & 0xff0) | (buf[2] & 0xf); + z = ((buf[5] << 4) & 0xff0) | (buf[4] & 0xf); + input_report_abs(dev->input, ABS_X, x); input_report_abs(dev->input, ABS_Y, y); input_report_abs(dev->input, ABS_Z, z); -- cgit v1.2.3-70-g09d2 From 26e56eb2bfccdd6bcec0c298d40e12e3daea0188 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Oct 2011 15:26:51 -0700 Subject: Input: synaptics_i2c - wrap suspend and resume in CONFIG_PM_SLEEP CONFIG_PM is defined when CONFIG_PM_SLEEP or CONFIG_PM_RUNTIME is defined, however suspend and resume methods are only valid in context of CONFIG_PM_SLEEP. If only CONFIG_PM_RUNTIME is defined we get the following warning (courtesy of Geerts randconfig builds): synaptics_i2c.c: warning: 'synaptics_i2c_resume' defined but not used Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index e28e9ce0f7e..4b755cb5b38 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -619,7 +619,7 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int synaptics_i2c_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); -- cgit v1.2.3-70-g09d2 From d4f4158dcda2f75ba8024e540d0bba070af1e67a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Oct 2011 15:26:52 -0700 Subject: Input: ad7879-i2c - wrap suspend and resume in CONFIG_PM_SLEEP CONFIG_PM is defined when CONFIG_PM_SLEEP or CONFIG_PM_RUNTIME is defined, however suspend and resume methods are only valid in the context of CONFIG_PM_SLEEP. If only CONFIG_PM_RUNTIME is defined we get the following warning (courtesy of Geerts randconfig builds): ad7879-i2c.c: warning: 'ad7879_i2c_resume' defined but not used Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-i2c.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 4e4e58cec6c..c789b974c79 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -16,7 +16,7 @@ #define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ad7879_i2c_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -36,9 +36,9 @@ static int ad7879_i2c_resume(struct device *dev) return 0; } +#endif static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume); -#endif /* All registers are word-sized. * AD7879 uses a high-byte first convention. @@ -119,9 +119,7 @@ static struct i2c_driver ad7879_i2c_driver = { .driver = { .name = "ad7879", .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &ad7879_i2c_pm, -#endif }, .probe = ad7879_i2c_probe, .remove = __devexit_p(ad7879_i2c_remove), -- cgit v1.2.3-70-g09d2 From f80aee7fd095d9014a92a250c688ff5dbc0a6649 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Oct 2011 15:26:52 -0700 Subject: Input: lm8323 - wrap suspend and resume in CONFIG_PM_SLEEP CONFIG_PM is defined when CONFIG_PM_SLEEP or CONFIG_PM_RUNTIME is defined, however suspend and resume methods are only valid in the context of CONFIG_PM_SLEEP. If only CONFIG_PM_RUNTIME is defined we get the following warning (courtesy of Geerts randconfig builds): lm8323.c: warning: 'lm8323_resume' defined but not used Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lm8323.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 756348a7f93..82d1dc8badd 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -788,7 +788,7 @@ static int __devexit lm8323_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP /* * We don't need to explicitly suspend the chip, as it already switches off * when there's no activity. -- cgit v1.2.3-70-g09d2 From 3d11ae8190c1b273d655b4d8d82be36754587910 Mon Sep 17 00:00:00 2001 From: Chris Bagwell Date: Mon, 10 Oct 2011 08:51:52 -0700 Subject: Input: wacom - remove unneeded touch pressure initialization These were left in during removal of touch pressure reports but not needed now. Signed-off-by: Chris Bagwell Reviewed-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index c1c2f7b28d8..f4206b5236c 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1029,8 +1029,6 @@ void wacom_setup_device_quirks(struct wacom_features *features) features->y_max <<= 5; features->x_fuzz <<= 5; features->y_fuzz <<= 5; - features->pressure_max = 256; - features->pressure_fuzz = 16; features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES; } } @@ -1219,9 +1217,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, features->y_max, features->y_fuzz, 0); - input_set_abs_params(input_dev, ABS_MT_PRESSURE, - 0, features->pressure_max, - features->pressure_fuzz, 0); } else if (features->device_type == BTN_TOOL_PEN) { __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); -- cgit v1.2.3-70-g09d2 From c18c2cec31881130c591ea60590859002945cd96 Mon Sep 17 00:00:00 2001 From: Chris Bagwell Date: Mon, 10 Oct 2011 08:52:13 -0700 Subject: Input: wacom - add ABS_DISTANCE to Bamboo Pen reports Tablet reports a distance of 0 right at highest point possible to be in proximity and distance_max when touching tablet. Inverse the distance since user land has no way of knowing ABS_DISTANCE is not distance from tablet. Signed-off-by: Chris Bagwell Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index f4206b5236c..6f94b4593ad 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -873,7 +873,15 @@ static int wacom_bpt_pen(struct wacom_wac *wacom) x = le16_to_cpup((__le16 *)&data[2]); y = le16_to_cpup((__le16 *)&data[4]); p = le16_to_cpup((__le16 *)&data[6]); - d = data[8]; + /* + * Convert distance from out prox to distance from tablet. + * distance will be greater than distance_max once + * touching and applying pressure; do not report negative + * distance. + */ + if (data[8] <= wacom->features.distance_max) + d = wacom->features.distance_max - data[8]; + pen = data[1] & 0x01; btn1 = data[1] & 0x02; btn2 = data[1] & 0x04; @@ -1222,6 +1230,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_STYLUS, input_dev->keybit); __set_bit(BTN_STYLUS2, input_dev->keybit); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, + features->distance_max, + 0, 0); } break; } @@ -1442,37 +1453,37 @@ static const struct wacom_features wacom_features_0x47 = 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD0 = { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD1 = { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD4 = { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD5 = { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD6 = { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD7 = { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD8 = { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xDA = { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static struct wacom_features wacom_features_0xDB = { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, - 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x6004 = { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -- cgit v1.2.3-70-g09d2 From ae927560a7d3055618ccc73a5d057cdd91b63740 Mon Sep 17 00:00:00 2001 From: Chris Bagwell Date: Mon, 10 Oct 2011 08:52:32 -0700 Subject: Input: wacom - correct max Y value on medium bamboos Medium size Bamboo P&T driver reused max X/Y form older Bamboo 1 medium size tablets and never updated to real value. Actual active area of tablet is slightly larger in Y direction. Signed-off-by: Chris Bagwell Acked-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 6f94b4593ad..7fefd93596e 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1461,13 +1461,13 @@ static const struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD3 = - { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD4 = { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD5 = - { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD6 = { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, @@ -1476,13 +1476,13 @@ static const struct wacom_features wacom_features_0xD7 = { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD8 = - { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xDA = { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static struct wacom_features wacom_features_0xDB = - { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x6004 = { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, -- cgit v1.2.3-70-g09d2 From b5d21704361eefe337a36ebbb57a1d9927132511 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:27:03 -0700 Subject: Input: psmouse - switch to using dev_*() for messages This will ensure our reporting is consistent with the rest of the system and we do not refer to obsolete source file names. Reviewed-by: Wanlong Gao Reviewed-by: JJ Ding Reviewed-by: Daniel Kurtz Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 52 ++++++++++++----------- drivers/input/mouse/elantech.c | 84 +++++++++++++++++++++----------------- drivers/input/mouse/hgpk.c | 84 +++++++++++++++++++------------------- drivers/input/mouse/hgpk.h | 11 ----- drivers/input/mouse/lifebook.c | 6 +-- drivers/input/mouse/logips2pp.c | 16 ++++---- drivers/input/mouse/psmouse-base.c | 67 +++++++++++++++++------------- drivers/input/mouse/psmouse.h | 25 ++++++++++++ drivers/input/mouse/sentelic.c | 13 +++--- drivers/input/mouse/synaptics.c | 83 ++++++++++++++++++++----------------- 10 files changed, 243 insertions(+), 198 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 99d58764ef0..003587c71f4 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -23,13 +23,6 @@ #include "psmouse.h" #include "alps.h" -#undef DEBUG -#ifdef DEBUG -#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif - #define ALPS_OLDPROTO 0x01 /* old style input */ #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ #define ALPS_PASS 0x04 /* device has a pass-through port */ @@ -297,10 +290,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) psmouse->packet[4] | psmouse->packet[5]) & 0x80) || (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { - dbg("refusing packet %x %x %x %x " - "(suspected interleaved ps/2)\n", - psmouse->packet[3], psmouse->packet[4], - psmouse->packet[5], psmouse->packet[6]); + psmouse_dbg(psmouse, + "refusing packet %x %x %x %x (suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5], psmouse->packet[6]); return PSMOUSE_BAD_DATA; } @@ -319,13 +312,13 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) * There is also possibility that we got 6-byte ALPS * packet followed by 3-byte packet from trackpoint. We * can not distinguish between these 2 scenarios but - * becase the latter is unlikely to happen in course of + * because the latter is unlikely to happen in course of * normal operation (user would need to press all * buttons on the pad and start moving trackpoint * without touching the pad surface) we assume former. * Even if we are wrong the wost thing that would happen * the cursor would jump but we should not get protocol - * desynchronization. + * de-synchronization. */ alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], @@ -361,10 +354,10 @@ static void alps_flush_packet(unsigned long data) if ((psmouse->packet[3] | psmouse->packet[4] | psmouse->packet[5]) & 0x80) { - dbg("refusing packet %x %x %x " - "(suspected interleaved ps/2)\n", - psmouse->packet[3], psmouse->packet[4], - psmouse->packet[5]); + psmouse_dbg(psmouse, + "refusing packet %x %x %x (suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5]); } else { alps_process_packet(psmouse); } @@ -396,16 +389,18 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) } if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { - dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", - psmouse->packet[0], model->mask0, model->byte0); + psmouse_dbg(psmouse, + "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", + psmouse->packet[0], model->mask0, model->byte0); return PSMOUSE_BAD_DATA; } /* Bytes 2 - 6 should have 0 in the highest bit */ if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { - dbg("refusing packet[%i] = %x\n", - psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]); + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", + psmouse->pktcnt - 1, + psmouse->packet[psmouse->pktcnt - 1]); return PSMOUSE_BAD_DATA; } @@ -439,7 +434,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) return NULL; - dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x", + param[0], param[1], param[2]); if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100)) return NULL; @@ -459,7 +455,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) return NULL; - dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x", + param[0], param[1], param[2]); if (version) { for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++) @@ -527,7 +524,8 @@ static int alps_get_status(struct psmouse *psmouse, char *param) ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) return -1; - dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x", + param[0], param[1], param[2]); return 0; } @@ -605,12 +603,12 @@ static int alps_hw_init(struct psmouse *psmouse) } if (alps_tap_mode(psmouse, true)) { - printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); + psmouse_warn(psmouse, "Failed to enable hardware tapping\n"); return -1; } if (alps_absolute_mode(psmouse)) { - printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); + psmouse_err(psmouse, "Failed to enable absolute mode\n"); return -1; } @@ -621,7 +619,7 @@ static int alps_hw_init(struct psmouse *psmouse) /* ALPS needs stream mode, otherwise it won't report any data */ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { - printk(KERN_ERR "alps.c: Failed to enable stream mode\n"); + psmouse_err(psmouse, "Failed to enable stream mode\n"); return -1; } diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 25290b395c8..09b93b11a27 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -10,8 +10,6 @@ * Trademarks are the property of their respective owners. */ -#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt - #include #include #include @@ -25,7 +23,8 @@ #define elantech_debug(fmt, ...) \ do { \ if (etd->debug) \ - printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ + psmouse_printk(KERN_DEBUG, psmouse, \ + fmt, ##__VA_ARGS__); \ } while (0) /* @@ -36,7 +35,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, { if (psmouse_sliced_command(psmouse, c) || ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { - pr_err("synaptics_send_cmd query 0x%02x failed.\n", c); + psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c); return -1; } @@ -65,7 +64,7 @@ static int elantech_ps2_command(struct psmouse *psmouse, } while (tries > 0); if (rc) - pr_err("ps2 command 0x%02x failed.\n", command); + psmouse_err(psmouse, "ps2 command 0x%02x failed.\n", command); return rc; } @@ -117,7 +116,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, } if (rc) - pr_err("failed to read register 0x%02x.\n", reg); + psmouse_err(psmouse, "failed to read register 0x%02x.\n", reg); else if (etd->hw_version != 4) *val = param[0]; else @@ -191,8 +190,9 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, } if (rc) - pr_err("failed to write register 0x%02x with value 0x%02x.\n", - reg, val); + psmouse_err(psmouse, + "failed to write register 0x%02x with value 0x%02x.\n", + reg, val); return rc; } @@ -200,13 +200,13 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, /* * Dump a complete mouse movement packet to the syslog */ -static void elantech_packet_dump(unsigned char *packet, int size) +static void elantech_packet_dump(struct psmouse *psmouse) { int i; - printk(KERN_DEBUG pr_fmt("PS/2 packet [")); - for (i = 0; i < size; i++) - printk("%s0x%02x ", (i) ? ", " : " ", packet[i]); + psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet ["); + for (i = 0; i < psmouse->pktsize; i++) + printk("%s0x%02x ", i ? ", " : " ", psmouse->packet[i]); printk("]\n"); } @@ -705,7 +705,7 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) return PSMOUSE_GOOD_DATA; if (etd->debug > 1) - elantech_packet_dump(psmouse->packet, psmouse->pktsize); + elantech_packet_dump(psmouse); switch (etd->hw_version) { case 1: @@ -801,7 +801,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) /* * Read back reg 0x10. For hardware version 1 we must make * sure the absolute mode bit is set. For hardware version 2 - * the touchpad is probably initalising and not ready until + * the touchpad is probably initializing and not ready until * we read back the value we just wrote. */ do { @@ -814,17 +814,19 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) } while (tries > 0); if (rc) { - pr_err("failed to read back register 0x10.\n"); + psmouse_err(psmouse, + "failed to read back register 0x10.\n"); } else if (etd->hw_version == 1 && !(val & ETP_R10_ABSOLUTE_MODE)) { - pr_err("touchpad refuses to switch to absolute mode.\n"); + psmouse_err(psmouse, + "touchpad refuses to switch to absolute mode.\n"); rc = -1; } } skip_readback_reg_10: if (rc) - pr_err("failed to initialise registers.\n"); + psmouse_err(psmouse, "failed to initialise registers.\n"); return rc; } @@ -1131,7 +1133,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { - pr_debug("sending Elantech magic knock failed.\n"); + psmouse_dbg(psmouse, "sending Elantech magic knock failed.\n"); return -1; } @@ -1141,8 +1143,9 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) */ if (param[0] != 0x3c || param[1] != 0x03 || (param[2] != 0xc8 && param[2] != 0x00)) { - pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", - param[0], param[1], param[2]); + psmouse_dbg(psmouse, + "unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", + param[0], param[1], param[2]); return -1; } @@ -1152,15 +1155,17 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) * to Elantech magic knock and there might be more. */ if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { - pr_debug("failed to query firmware version.\n"); + psmouse_dbg(psmouse, "failed to query firmware version.\n"); return -1; } - pr_debug("Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", - param[0], param[1], param[2]); + psmouse_dbg(psmouse, + "Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", + param[0], param[1], param[2]); if (!elantech_is_signature_valid(param)) { - pr_debug("Probably not a real Elantech touchpad. Aborting.\n"); + psmouse_dbg(psmouse, + "Probably not a real Elantech touchpad. Aborting.\n"); return -1; } @@ -1192,7 +1197,8 @@ static int elantech_reconnect(struct psmouse *psmouse) return -1; if (elantech_set_absolute_mode(psmouse)) { - pr_err("failed to put touchpad back into absolute mode.\n"); + psmouse_err(psmouse, + "failed to put touchpad back into absolute mode.\n"); return -1; } @@ -1262,42 +1268,46 @@ int elantech_init(struct psmouse *psmouse) * Do the version query again so we can store the result */ if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { - pr_err("failed to query firmware version.\n"); + psmouse_err(psmouse, "failed to query firmware version.\n"); goto init_fail; } etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; if (elantech_set_properties(etd)) { - pr_err("unknown hardware version, aborting...\n"); + psmouse_err(psmouse, "unknown hardware version, aborting...\n"); goto init_fail; } - pr_info("assuming hardware version %d " - "(with firmware version 0x%02x%02x%02x)\n", - etd->hw_version, param[0], param[1], param[2]); + psmouse_info(psmouse, + "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n", + etd->hw_version, param[0], param[1], param[2]); if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, etd->capabilities)) { - pr_err("failed to query capabilities.\n"); + psmouse_err(psmouse, "failed to query capabilities.\n"); goto init_fail; } - pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", - etd->capabilities[0], etd->capabilities[1], - etd->capabilities[2]); + psmouse_info(psmouse, + "Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", + etd->capabilities[0], etd->capabilities[1], + etd->capabilities[2]); if (elantech_set_absolute_mode(psmouse)) { - pr_err("failed to put touchpad into absolute mode.\n"); + psmouse_err(psmouse, + "failed to put touchpad into absolute mode.\n"); goto init_fail; } if (elantech_set_input_params(psmouse)) { - pr_err("failed to query touchpad range.\n"); + psmouse_err(psmouse, "failed to query touchpad range.\n"); goto init_fail; } error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, &elantech_attr_group); if (error) { - pr_err("failed to create sysfs attributes, error: %d.\n", error); + psmouse_err(psmouse, + "failed to create sysfs attributes, error: %d.\n", + error); goto init_fail; } diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 4d17d9f3320..0470dd46b56 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -136,10 +136,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) /* discard if too big, or half that but > 4 times the prev delta */ if (avx > recalib_delta || (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) { - hgpk_err(psmouse, "detected %dpx jump in x\n", x); + psmouse_warn(psmouse, "detected %dpx jump in x\n", x); priv->xbigj = avx; } else if (approx_half(avx, priv->xbigj)) { - hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x); + psmouse_warn(psmouse, "detected secondary %dpx jump in x\n", x); priv->xbigj = avx; priv->xsaw_secondary++; } else { @@ -151,10 +151,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) if (avy > recalib_delta || (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) { - hgpk_err(psmouse, "detected %dpx jump in y\n", y); + psmouse_warn(psmouse, "detected %dpx jump in y\n", y); priv->ybigj = avy; } else if (approx_half(avy, priv->ybigj)) { - hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y); + psmouse_warn(psmouse, "detected secondary %dpx jump in y\n", y); priv->ybigj = avy; priv->ysaw_secondary++; } else { @@ -168,7 +168,7 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) priv->ylast = avy; if (do_recal && jumpy_delay) { - hgpk_err(psmouse, "scheduling recalibration\n"); + psmouse_warn(psmouse, "scheduling recalibration\n"); psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(jumpy_delay)); } @@ -260,8 +260,8 @@ static void hgpk_spewing_hack(struct psmouse *psmouse, * movement, it is probably a case of the user moving the * cursor very slowly across the screen. */ if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) { - hgpk_err(psmouse, "packet spew detected (%d,%d)\n", - priv->x_tally, priv->y_tally); + psmouse_warn(psmouse, "packet spew detected (%d,%d)\n", + priv->x_tally, priv->y_tally); priv->spew_flag = RECALIBRATING; psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(spew_delay)); @@ -333,12 +333,12 @@ static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet) } if (!valid) - hgpk_dbg(psmouse, - "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n", - priv->mode, pktcnt, - psmouse->packet[0], psmouse->packet[1], - psmouse->packet[2], psmouse->packet[3], - psmouse->packet[4], psmouse->packet[5]); + psmouse_dbg(psmouse, + "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n", + priv->mode, pktcnt, + psmouse->packet[0], psmouse->packet[1], + psmouse->packet[2], psmouse->packet[3], + psmouse->packet[4], psmouse->packet[5]); return valid; } @@ -361,19 +361,20 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) input_report_abs(idev, ABS_PRESSURE, z); if (tpdebug) - hgpk_dbg(psmouse, "pd=%d fd=%d z=%d", - pt_down, finger_down, z); + psmouse_dbg(psmouse, "pd=%d fd=%d z=%d", + pt_down, finger_down, z); } else { /* * PenTablet mode does not report pressure, so we don't * report it here */ if (tpdebug) - hgpk_dbg(psmouse, "pd=%d ", down); + psmouse_dbg(psmouse, "pd=%d ", down); } if (tpdebug) - hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y); + psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", + left, right, x, y); input_report_key(idev, BTN_TOUCH, down); input_report_key(idev, BTN_LEFT, left); @@ -395,7 +396,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) if (x == priv->abs_x && y == priv->abs_y) { if (++priv->dupe_count > SPEW_WATCH_COUNT) { if (tpdebug) - hgpk_dbg(psmouse, "hard spew detected\n"); + psmouse_dbg(psmouse, "hard spew detected\n"); priv->spew_flag = RECALIBRATING; psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(spew_delay)); @@ -412,7 +413,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse) int y_diff = priv->abs_y - y; if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) { if (tpdebug) - hgpk_dbg(psmouse, "discarding\n"); + psmouse_dbg(psmouse, "discarding\n"); goto done; } hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff); @@ -437,20 +438,21 @@ static void hgpk_process_simple_packet(struct psmouse *psmouse) int y = ((packet[0] << 3) & 0x100) - packet[2]; if (packet[0] & 0xc0) - hgpk_dbg(psmouse, - "overflow -- 0x%02x 0x%02x 0x%02x\n", - packet[0], packet[1], packet[2]); + psmouse_dbg(psmouse, + "overflow -- 0x%02x 0x%02x 0x%02x\n", + packet[0], packet[1], packet[2]); if (hgpk_discard_decay_hack(psmouse, x, y)) { if (tpdebug) - hgpk_dbg(psmouse, "discarding\n"); + psmouse_dbg(psmouse, "discarding\n"); return; } hgpk_spewing_hack(psmouse, left, right, x, y); if (tpdebug) - hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y); + psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", + left, right, x, y); input_report_key(dev, BTN_LEFT, left); input_report_key(dev, BTN_RIGHT, right); @@ -482,9 +484,8 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) * ugh, got a packet inside our recalibration * window, schedule another recalibration. */ - hgpk_dbg(psmouse, - "packet inside calibration window, " - "queueing another recalibration\n"); + psmouse_dbg(psmouse, + "packet inside calibration window, queueing another recalibration\n"); psmouse_queue_work(psmouse, &priv->recalib_wq, msecs_to_jiffies(post_interrupt_delay)); } @@ -628,7 +629,7 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) err = hgpk_select_mode(psmouse); if (err) { - hgpk_err(psmouse, "failed to select mode\n"); + psmouse_err(psmouse, "failed to select mode\n"); return err; } @@ -648,11 +649,11 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) return 0; if (!autorecal) { - hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n"); + psmouse_dbg(psmouse, "recalibration disabled, ignoring\n"); return 0; } - hgpk_dbg(psmouse, "recalibrating touchpad..\n"); + psmouse_dbg(psmouse, "recalibrating touchpad..\n"); /* we don't want to race with the irq handler, nor with resyncs */ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); @@ -675,7 +676,7 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); if (tpdebug) - hgpk_dbg(psmouse, "touchpad reactivated\n"); + psmouse_dbg(psmouse, "touchpad reactivated\n"); /* * If we get packets right away after recalibrating, it's likely @@ -727,16 +728,16 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable) err = hgpk_reset_device(psmouse, false); if (err) { - hgpk_err(psmouse, "Failed to reset device!\n"); + psmouse_err(psmouse, "Failed to reset device!\n"); return err; } /* should be all set, enable the touchpad */ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); - hgpk_dbg(psmouse, "Touchpad powered up.\n"); + psmouse_dbg(psmouse, "Touchpad powered up.\n"); } else { - hgpk_dbg(psmouse, "Powering off touchpad.\n"); + psmouse_dbg(psmouse, "Powering off touchpad.\n"); if (ps2_command(ps2dev, NULL, 0xec) || ps2_command(ps2dev, NULL, 0xec) || @@ -923,7 +924,7 @@ static void hgpk_recalib_work(struct work_struct *work) struct psmouse *psmouse = priv->psmouse; if (hgpk_force_recalibrate(psmouse)) - hgpk_err(psmouse, "recalibration failed!\n"); + psmouse_err(psmouse, "recalibration failed!\n"); } static int hgpk_register(struct psmouse *psmouse) @@ -947,14 +948,15 @@ static int hgpk_register(struct psmouse *psmouse) err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); if (err) { - hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n"); + psmouse_err(psmouse, "Failed creating 'powered' sysfs node\n"); return err; } err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_hgpk_mode.dattr); if (err) { - hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n"); + psmouse_err(psmouse, + "Failed creating 'hgpk_mode' sysfs node\n"); goto err_remove_powered; } @@ -963,8 +965,8 @@ static int hgpk_register(struct psmouse *psmouse) err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_recalibrate.dattr); if (err) { - hgpk_err(psmouse, - "Failed creating 'recalibrate' sysfs node\n"); + psmouse_err(psmouse, + "Failed creating 'recalibrate' sysfs node\n"); goto err_remove_mode; } } @@ -1027,13 +1029,13 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse) return -EIO; } - hgpk_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]); + psmouse_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]); /* HGPK signature: 0x67, 0x00, 0x */ if (param[0] != 0x67 || param[1] != 0x00) return -ENODEV; - hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]); + psmouse_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]); return param[2]; } diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h index 311c0e87fcb..dd686771cfe 100644 --- a/drivers/input/mouse/hgpk.h +++ b/drivers/input/mouse/hgpk.h @@ -46,17 +46,6 @@ struct hgpk_data { int xsaw_secondary, ysaw_secondary; /* jumpiness detection */ }; -#define hgpk_dbg(psmouse, format, arg...) \ - dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_err(psmouse, format, arg...) \ - dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_info(psmouse, format, arg...) \ - dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_warn(psmouse, format, arg...) \ - dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg) -#define hgpk_notice(psmouse, format, arg...) \ - dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg) - #ifdef CONFIG_MOUSE_PS2_OLPC void hgpk_module_init(void); int hgpk_detect(struct psmouse *psmouse, bool set_properties); diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 83bcaba96b8..2c4db636de6 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -169,8 +169,8 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) if (relative_packet) { if (!dev2) - printk(KERN_WARNING "lifebook.c: got relative packet " - "but no relative device set up\n"); + psmouse_warn(psmouse, + "got relative packet but no relative device set up\n"); } else { if (lifebook_use_6byte_proto) { input_report_abs(dev1, ABS_X, @@ -212,7 +212,7 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) /* * Enable absolute output -- ps2_command fails always but if - * you leave this call out the touchsreen will never send + * you leave this call out the touchscreen will never send * absolute coordinates */ param = lifebook_use_6byte_proto ? 0x08 : 0x07; diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index c9983aee908..faac2c3bef7 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -82,11 +82,11 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) packet[0] = packet[2] | 0x08; break; -#ifdef DEBUG default: - printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", - (packet[1] >> 4) | (packet[0] & 0x30)); -#endif + psmouse_dbg(psmouse, + "Received PS2++ packet #%x, but don't know how to handle.\n", + (packet[1] >> 4) | (packet[0] & 0x30)); + break; } } else { /* Standard PS/2 motion data */ @@ -382,7 +382,7 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) } } else { - printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); + psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model); } if (set_properties) { @@ -400,9 +400,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) error = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); if (error) { - printk(KERN_ERR - "logips2pp.c: failed to create smartscroll " - "sysfs attribute, error: %d\n", error); + psmouse_err(psmouse, + "failed to create smartscroll sysfs attribute, error: %d\n", + error); return -1; } } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 3f74baee102..9f352fbd7b4 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -11,6 +11,9 @@ * the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define psmouse_fmt(fmt) fmt + #include #include #include @@ -251,11 +254,14 @@ static int psmouse_handle_byte(struct psmouse *psmouse) switch (rc) { case PSMOUSE_BAD_DATA: if (psmouse->state == PSMOUSE_ACTIVATED) { - printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); + psmouse_warn(psmouse, + "%s at %s lost sync at byte %d\n", + psmouse->name, psmouse->phys, + psmouse->pktcnt); if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); - printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); + psmouse_notice(psmouse, + "issuing reconnect request\n"); serio_reconnect(psmouse->ps2dev.serio); return -1; } @@ -267,8 +273,9 @@ static int psmouse_handle_byte(struct psmouse *psmouse) psmouse->pktcnt = 0; if (psmouse->out_of_sync_cnt) { psmouse->out_of_sync_cnt = 0; - printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", - psmouse->name, psmouse->phys); + psmouse_notice(psmouse, + "%s at %s - driver resynced.\n", + psmouse->name, psmouse->phys); } break; @@ -295,9 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) { if (psmouse->state == PSMOUSE_ACTIVATED) - printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", - flags & SERIO_TIMEOUT ? " timeout" : "", - flags & SERIO_PARITY ? " bad parity" : ""); + psmouse_warn(psmouse, + "bad data from KBC -%s%s\n", + flags & SERIO_TIMEOUT ? " timeout" : "", + flags & SERIO_PARITY ? " bad parity" : ""); ps2_cmd_aborted(&psmouse->ps2dev); goto out; } @@ -315,8 +323,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { - printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); + psmouse_info(psmouse, "%s at %s lost synchronization, throwing %d bytes away.\n", + psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); psmouse_queue_work(psmouse, &psmouse->resync_work, 0); @@ -943,7 +951,8 @@ static int psmouse_probe(struct psmouse *psmouse) */ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS)) - printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys); + psmouse_warn(psmouse, "Failed to reset mouse on %s\n", + ps2dev->serio->phys); return 0; } @@ -1005,8 +1014,8 @@ static void psmouse_initialize(struct psmouse *psmouse) static void psmouse_activate(struct psmouse *psmouse) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) - printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "Failed to enable mouse on %s\n", + psmouse->ps2dev.serio->phys); psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); } @@ -1020,14 +1029,14 @@ static void psmouse_activate(struct psmouse *psmouse) static void psmouse_deactivate(struct psmouse *psmouse) { if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", + psmouse->ps2dev.serio->phys); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); } /* - * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it. + * psmouse_poll() - default poll handler. Everyone except for ALPS uses it. */ static int psmouse_poll(struct psmouse *psmouse) @@ -1115,14 +1124,15 @@ static void psmouse_resync(struct work_struct *work) } if (!enabled) { - printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "failed to re-enable mouse on %s\n", + psmouse->ps2dev.serio->phys); failed = true; } if (failed) { psmouse_set_state(psmouse, PSMOUSE_IGNORE); - printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n"); + psmouse_info(psmouse, + "resync failed, issuing reconnect request\n"); serio_reconnect(serio); } else psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); @@ -1155,8 +1165,8 @@ static void psmouse_cleanup(struct serio *serio) * Disable stream mode so cleanup routine can proceed undisturbed. */ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - printk(KERN_WARNING "psmouse.c: Failed to disable mouse on %s\n", - psmouse->ps2dev.serio->phys); + psmouse_warn(psmouse, "Failed to disable mouse on %s\n", + psmouse->ps2dev.serio->phys); if (psmouse->cleanup) psmouse->cleanup(psmouse); @@ -1400,7 +1410,8 @@ static int psmouse_reconnect(struct serio *serio) int rc = -1; if (!drv || !psmouse) { - printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); + psmouse_dbg(psmouse, + "reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -1427,8 +1438,9 @@ static int psmouse_reconnect(struct serio *serio) goto out; } - /* ok, the device type (and capabilities) match the old one, - * we can continue using it, complete intialization + /* + * OK, the device type (and capabilities) match the old one, + * we can continue using it, complete initialization */ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); @@ -1586,9 +1598,8 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co while (!list_empty(&serio->children)) { if (++retry > 3) { - printk(KERN_WARNING - "psmouse: failed to destroy children ports, " - "protocol change aborted.\n"); + psmouse_warn(psmouse, + "failed to destroy children ports, protocol change aborted.\n"); input_free_device(new_dev); return -EIO; } @@ -1715,7 +1726,7 @@ static int __init psmouse_init(void) kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); if (!kpsmoused_wq) { - printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); + pr_err("failed to create kpsmoused workqueue\n"); return -ENOMEM; } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 593e910bfc7..9b84b0c4e37 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -150,4 +150,29 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true) +#ifndef psmouse_fmt +#define psmouse_fmt(fmt) KBUILD_BASENAME ": " fmt +#endif + +#define psmouse_dbg(psmouse, format, ...) \ + dev_dbg(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_info(psmouse, format, ...) \ + dev_info(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_warn(psmouse, format, ...) \ + dev_warn(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_err(psmouse, format, ...) \ + dev_err(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_notice(psmouse, format, ...) \ + dev_notice(&(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) +#define psmouse_printk(level, psmouse, format, ...) \ + dev_printk(level, \ + &(psmouse)->ps2dev.serio->dev, \ + psmouse_fmt(format), ##__VA_ARGS__) + + #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 2fc887a5106..c5b12d2e955 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -607,11 +607,12 @@ static void fsp_packet_debug(unsigned char packet[]) ps2_packet_cnt++; jiffies_msec = jiffies_to_msecs(jiffies); - printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", - jiffies_msec, packet[0], packet[1], packet[2], packet[3]); + psmouse_dbg(psmouse, + "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", + jiffies_msec, packet[0], packet[1], packet[2], packet[3]); if (jiffies_msec - ps2_last_second > 1000) { - printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt); + psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt); ps2_packet_cnt = 0; ps2_last_second = jiffies_msec; } @@ -820,9 +821,9 @@ int fsp_init(struct psmouse *psmouse) return -ENODEV; } - printk(KERN_INFO - "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", - ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); + psmouse_info(psmouse, + "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", + ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); if (!priv) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 30c85a5b718..c080b828e5d 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -167,8 +167,8 @@ static int synaptics_capability(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { - printk(KERN_ERR "Synaptics claims to have extended capabilities," - " but I'm not able to read them.\n"); + psmouse_warn(psmouse, + "device claims to have extended capabilities, but I'm not able to read them.\n"); } else { priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; @@ -183,8 +183,8 @@ static int synaptics_capability(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) { - printk(KERN_ERR "Synaptics claims to have extended capability 0x0c," - " but I'm not able to read it.\n"); + psmouse_warn(psmouse, + "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); } else { priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2]; } @@ -232,8 +232,8 @@ static int synaptics_resolution(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { - printk(KERN_ERR "Synaptics claims to have max coordinates" - " query, but I'm not able to read it.\n"); + psmouse_warn(psmouse, + "device claims to have max coordinates query, but I'm not able to read it.\n"); } else { priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); @@ -243,8 +243,8 @@ static int synaptics_resolution(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 && SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) { - printk(KERN_ERR "Synaptics claims to have min coordinates" - " query, but I'm not able to read it.\n"); + psmouse_warn(psmouse, + "device claims to have min coordinates query, but I'm not able to read it.\n"); } else { priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); @@ -388,7 +388,8 @@ static void synaptics_pt_activate(struct psmouse *psmouse) priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT; if (synaptics_mode_cmd(psmouse, priv->mode)) - printk(KERN_INFO "synaptics: failed to switch guest protocol\n"); + psmouse_warn(psmouse, + "failed to switch guest protocol\n"); } } @@ -398,7 +399,8 @@ static void synaptics_pt_create(struct psmouse *psmouse) serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) { - printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); + psmouse_err(psmouse, + "not enough memory for pass-through port\n"); return; } @@ -412,7 +414,8 @@ static void synaptics_pt_create(struct psmouse *psmouse) psmouse->pt_activate = synaptics_pt_activate; - printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys); + psmouse_info(psmouse, "serio: %s port at %s\n", + serio->name, psmouse->phys); serio_register_port(serio); } @@ -1049,13 +1052,15 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_sync(dev); } -static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) +static int synaptics_validate_byte(struct psmouse *psmouse, + int idx, unsigned char pkt_type) { static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + const char *packet = psmouse->packet; if (idx < 0 || idx > 4) return 0; @@ -1073,7 +1078,7 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; default: - printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); + psmouse_err(psmouse, "unknown packet type %d\n", pkt_type); return 0; } } @@ -1083,8 +1088,8 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) int i; for (i = 0; i < 5; i++) - if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) { - printk(KERN_INFO "synaptics: using relaxed packet validation\n"); + if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) { + psmouse_info(psmouse, "using relaxed packet validation\n"); return SYN_NEWABS_RELAXED; } @@ -1109,7 +1114,7 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) return PSMOUSE_FULL_PACKET; } - return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ? + return synaptics_validate_byte(psmouse, psmouse->pktcnt - 1, priv->pkt_type) ? PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; } @@ -1222,21 +1227,21 @@ static int synaptics_reconnect(struct psmouse *psmouse) return -1; if (retry > 1) - printk(KERN_DEBUG "Synaptics reconnected after %d tries\n", - retry); + psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); if (synaptics_query_hardware(psmouse)) { - printk(KERN_ERR "Unable to query Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to query device.\n"); return -1; } if (synaptics_set_absolute_mode(psmouse)) { - printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to initialize device.\n"); return -1; } if (synaptics_set_advanced_gesture_mode(psmouse)) { - printk(KERN_ERR "Advanced gesture mode reconnect failed.\n"); + psmouse_err(psmouse, + "Advanced gesture mode reconnect failed.\n"); return -1; } @@ -1244,12 +1249,12 @@ static int synaptics_reconnect(struct psmouse *psmouse) old_priv.model_id != priv->model_id || old_priv.capabilities != priv->capabilities || old_priv.ext_cap != priv->ext_cap) { - printk(KERN_ERR "Synaptics hardware appears to be different: " - "id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", - old_priv.identity, priv->identity, - old_priv.model_id, priv->model_id, - old_priv.capabilities, priv->capabilities, - old_priv.ext_cap, priv->ext_cap); + psmouse_err(psmouse, + "hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", + old_priv.identity, priv->identity, + old_priv.model_id, priv->model_id, + old_priv.capabilities, priv->capabilities, + old_priv.ext_cap, priv->ext_cap); return -1; } @@ -1330,7 +1335,8 @@ int synaptics_init(struct psmouse *psmouse) * just fine. */ if (broken_olpc_ec) { - printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n"); + psmouse_info(psmouse, + "OLPC XO detected, not enabling Synaptics protocol.\n"); return -ENODEV; } @@ -1341,26 +1347,28 @@ int synaptics_init(struct psmouse *psmouse) psmouse_reset(psmouse); if (synaptics_query_hardware(psmouse)) { - printk(KERN_ERR "Unable to query Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to query device.\n"); goto init_fail; } if (synaptics_set_absolute_mode(psmouse)) { - printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); + psmouse_err(psmouse, "Unable to initialize device.\n"); goto init_fail; } if (synaptics_set_advanced_gesture_mode(psmouse)) { - printk(KERN_ERR "Advanced gesture mode init failed.\n"); + psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); goto init_fail; } priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; - printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", - SYN_ID_MODEL(priv->identity), - SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), - priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c); + psmouse_info(psmouse, + "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", + SYN_ID_MODEL(priv->identity), + SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), + priv->model_id, + priv->capabilities, priv->ext_cap, priv->ext_cap_0c); set_input_params(psmouse->dev, priv); @@ -1392,8 +1400,9 @@ int synaptics_init(struct psmouse *psmouse) * the same rate as a standard PS/2 mouse). */ if (psmouse->rate >= 80 && impaired_toshiba_kbc) { - printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", - dmi_get_system_info(DMI_PRODUCT_NAME)); + psmouse_info(psmouse, + "Toshiba %s detected, limiting rate to 40pps.\n", + dmi_get_system_info(DMI_PRODUCT_NAME)); psmouse->rate = 40; } -- cgit v1.2.3-70-g09d2 From ba538cd2a83f3556448759283d2330a603005afe Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:30:03 -0700 Subject: Input: serio_raw - use kref instead of rolling out its own refcounting Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index b7ba4597f7f..ef3a69c304d 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -9,6 +9,7 @@ * the Free Software Foundation. */ +#include #include #include #include @@ -33,7 +34,7 @@ struct serio_raw { unsigned int tail, head; char name[16]; - unsigned int refcnt; + struct kref kref; struct serio *serio; struct miscdevice dev; wait_queue_head_t wait; @@ -104,7 +105,7 @@ static int serio_raw_open(struct inode *inode, struct file *file) list->serio_raw = serio_raw; file->private_data = list; - serio_raw->refcnt++; + kref_get(&serio_raw->kref); list_add_tail(&list->node, &serio_raw->list); out: @@ -112,17 +113,14 @@ out: return retval; } -static int serio_raw_cleanup(struct serio_raw *serio_raw) +static void serio_raw_cleanup(struct kref *kref) { - if (--serio_raw->refcnt == 0) { - misc_deregister(&serio_raw->dev); - list_del_init(&serio_raw->node); - kfree(serio_raw); + struct serio_raw *serio_raw = + container_of(kref, struct serio_raw, kref); - return 1; - } - - return 0; + misc_deregister(&serio_raw->dev); + list_del_init(&serio_raw->node); + kfree(serio_raw); } static int serio_raw_release(struct inode *inode, struct file *file) @@ -132,7 +130,7 @@ static int serio_raw_release(struct inode *inode, struct file *file) mutex_lock(&serio_raw_mutex); - serio_raw_cleanup(serio_raw); + kref_put(&serio_raw->kref, serio_raw_cleanup); mutex_unlock(&serio_raw_mutex); return 0; @@ -283,7 +281,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) mutex_lock(&serio_raw_mutex); snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); - serio_raw->refcnt = 1; + kref_init(&serio_raw->kref); serio_raw->serio = serio; INIT_LIST_HEAD(&serio_raw->list); init_waitqueue_head(&serio_raw->wait); @@ -357,8 +355,8 @@ static void serio_raw_disconnect(struct serio *serio) serio_set_drvdata(serio, NULL); serio_raw->serio = NULL; - if (!serio_raw_cleanup(serio_raw)) - wake_up_interruptible(&serio_raw->wait); + wake_up_interruptible(&serio_raw->wait); + kref_put(&serio_raw->kref, serio_raw_cleanup); mutex_unlock(&serio_raw_mutex); } -- cgit v1.2.3-70-g09d2 From 7c5bbb2eb7ad047b53c205b1f500bae7b0a88c06 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:30:14 -0700 Subject: Input: serio_raw - rename serio_raw_list to serio_raw_client 'serio_raw_list' and 'list' names do not accurately represent their objects and are extremely confusing when reading the code. Let's use better suited names. Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 75 +++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 36 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index ef3a69c304d..6b57ee37efe 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -38,11 +38,11 @@ struct serio_raw { struct serio *serio; struct miscdevice dev; wait_queue_head_t wait; - struct list_head list; + struct list_head client_list; struct list_head node; }; -struct serio_raw_list { +struct serio_raw_client { struct fasync_struct *fasync; struct serio_raw *serio_raw; struct list_head node; @@ -58,9 +58,9 @@ static unsigned int serio_raw_no; static int serio_raw_fasync(int fd, struct file *file, int on) { - struct serio_raw_list *list = file->private_data; + struct serio_raw_client *client = file->private_data; - return fasync_helper(fd, file, on, &list->fasync); + return fasync_helper(fd, file, on, &client->fasync); } static struct serio_raw *serio_raw_locate(int minor) @@ -78,8 +78,8 @@ static struct serio_raw *serio_raw_locate(int minor) static int serio_raw_open(struct inode *inode, struct file *file) { struct serio_raw *serio_raw; - struct serio_raw_list *list; - int retval = 0; + struct serio_raw_client *client; + int retval; retval = mutex_lock_interruptible(&serio_raw_mutex); if (retval) @@ -96,17 +96,17 @@ static int serio_raw_open(struct inode *inode, struct file *file) goto out; } - list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL); - if (!list) { + client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL); + if (!client) { retval = -ENOMEM; goto out; } - list->serio_raw = serio_raw; - file->private_data = list; + client->serio_raw = serio_raw; + file->private_data = client; kref_get(&serio_raw->kref); - list_add_tail(&list->node, &serio_raw->list); + list_add_tail(&client->node, &serio_raw->client_list); out: mutex_unlock(&serio_raw_mutex); @@ -125,8 +125,8 @@ static void serio_raw_cleanup(struct kref *kref) static int serio_raw_release(struct inode *inode, struct file *file) { - struct serio_raw_list *list = file->private_data; - struct serio_raw *serio_raw = list->serio_raw; + struct serio_raw_client *client = file->private_data; + struct serio_raw *serio_raw = client->serio_raw; mutex_lock(&serio_raw_mutex); @@ -156,8 +156,8 @@ static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - struct serio_raw_list *list = file->private_data; - struct serio_raw *serio_raw = list->serio_raw; + struct serio_raw_client *client = file->private_data; + struct serio_raw *serio_raw = client->serio_raw; char uninitialized_var(c); ssize_t retval = 0; @@ -167,8 +167,9 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t cou if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(list->serio_raw->wait, - serio_raw->head != serio_raw->tail || !serio_raw->serio); + retval = wait_event_interruptible(serio_raw->wait, + serio_raw->head != serio_raw->tail || + !serio_raw->serio); if (retval) return retval; @@ -186,7 +187,8 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t cou static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - struct serio_raw_list *list = file->private_data; + struct serio_raw_client *client = file->private_data; + struct serio_raw *serio_raw = client->serio_raw; ssize_t written = 0; int retval; unsigned char c; @@ -195,7 +197,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz if (retval) return retval; - if (!list->serio_raw->serio) { + if (!serio_raw->serio) { retval = -ENODEV; goto out; } @@ -208,7 +210,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz retval = -EFAULT; goto out; } - if (serio_write(list->serio_raw->serio, c)) { + if (serio_write(serio_raw->serio, c)) { retval = -EIO; goto out; } @@ -222,25 +224,26 @@ out: static unsigned int serio_raw_poll(struct file *file, poll_table *wait) { - struct serio_raw_list *list = file->private_data; + struct serio_raw_client *client = file->private_data; + struct serio_raw *serio_raw = client->serio_raw; - poll_wait(file, &list->serio_raw->wait, wait); + poll_wait(file, &serio_raw->wait, wait); - if (list->serio_raw->head != list->serio_raw->tail) + if (serio_raw->head != serio_raw->tail) return POLLIN | POLLRDNORM; return 0; } static const struct file_operations serio_raw_fops = { - .owner = THIS_MODULE, - .open = serio_raw_open, - .release = serio_raw_release, - .read = serio_raw_read, - .write = serio_raw_write, - .poll = serio_raw_poll, - .fasync = serio_raw_fasync, - .llseek = noop_llseek, + .owner = THIS_MODULE, + .open = serio_raw_open, + .release = serio_raw_release, + .read = serio_raw_read, + .write = serio_raw_write, + .poll = serio_raw_poll, + .fasync = serio_raw_fasync, + .llseek = noop_llseek, }; @@ -252,16 +255,16 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, unsigned int dfl) { struct serio_raw *serio_raw = serio_get_drvdata(serio); - struct serio_raw_list *list; + struct serio_raw_client *client; unsigned int head = serio_raw->head; - /* we are holding serio->lock here so we are prootected */ + /* we are holding serio->lock here so we are protected */ serio_raw->queue[head] = data; head = (head + 1) % SERIO_RAW_QUEUE_LEN; if (likely(head != serio_raw->tail)) { serio_raw->head = head; - list_for_each_entry(list, &serio_raw->list, node) - kill_fasync(&list->fasync, SIGIO, POLL_IN); + list_for_each_entry(client, &serio_raw->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_IN); wake_up_interruptible(&serio_raw->wait); } @@ -283,7 +286,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); kref_init(&serio_raw->kref); serio_raw->serio = serio; - INIT_LIST_HEAD(&serio_raw->list); + INIT_LIST_HEAD(&serio_raw->client_list); init_waitqueue_head(&serio_raw->wait); serio_set_drvdata(serio, serio_raw); -- cgit v1.2.3-70-g09d2 From 843e784afe164ac8c75a97259d54cf489be74bb9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:30:26 -0700 Subject: Input: serio_raw - perform proper locking when adding clients to list Make sure we hold serio lock when adding clients to client list so that we do not race with serio_raw_release() removing clients from the same list. Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 6b57ee37efe..77ce3a6a159 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -106,7 +106,10 @@ static int serio_raw_open(struct inode *inode, struct file *file) file->private_data = client; kref_get(&serio_raw->kref); + + serio_pause_rx(serio_raw->serio); list_add_tail(&client->node, &serio_raw->client_list); + serio_continue_rx(serio_raw->serio); out: mutex_unlock(&serio_raw_mutex); @@ -138,10 +141,9 @@ static int serio_raw_release(struct inode *inode, struct file *file) static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) { - unsigned long flags; int empty; - spin_lock_irqsave(&serio_raw->serio->lock, flags); + serio_pause_rx(serio_raw->serio); empty = serio_raw->head == serio_raw->tail; if (!empty) { @@ -149,7 +151,7 @@ static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; } - spin_unlock_irqrestore(&serio_raw->serio->lock, flags); + serio_continue_rx(serio_raw->serio); return !empty; } -- cgit v1.2.3-70-g09d2 From 8c31eb01e1ab91df69c60554b9aec2d522d414e0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:30:36 -0700 Subject: Input: serio_raw - use bool for boolean data Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 77ce3a6a159..a5afc7cbcdf 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -139,9 +139,9 @@ static int serio_raw_release(struct inode *inode, struct file *file) return 0; } -static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) +static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) { - int empty; + bool empty; serio_pause_rx(serio_raw->serio); @@ -394,7 +394,7 @@ static struct serio_driver serio_raw_drv = { .connect = serio_raw_connect, .reconnect = serio_raw_reconnect, .disconnect = serio_raw_disconnect, - .manual_bind = 1, + .manual_bind = true, }; static int __init serio_raw_init(void) -- cgit v1.2.3-70-g09d2 From 8d92847700870e33cb92b43bde0a81f5a4298028 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:30:46 -0700 Subject: Input: serio_raw - use dev_*() for messages This will ensure our reporting is consistent with the rest of the system. Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index a5afc7cbcdf..396a17fcc34 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -279,7 +279,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) int err; if (!(serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL))) { - printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); + dev_dbg(&serio->dev, "can't allocate memory for a device\n"); return -ENOMEM; } @@ -311,13 +311,14 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) } if (err) { - printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n", + dev_err(&serio->dev, + "failed to register raw access device for %s\n", serio->phys); goto out_close; } - printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n", - serio->phys, serio_raw->name, serio_raw->dev.minor); + dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n", + serio->phys, serio_raw->name, serio_raw->dev.minor); goto out; out_close: @@ -337,7 +338,8 @@ static int serio_raw_reconnect(struct serio *serio) struct serio_driver *drv = serio->drv; if (!drv || !serio_raw) { - printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n"); + dev_dbg(&serio->dev, + "reconnect request, but serio is disconnected, ignoring...\n"); return -1; } -- cgit v1.2.3-70-g09d2 From 15a564d8dbfc9429540c2d9b38a64d1909de8b24 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:30:56 -0700 Subject: Input: serio_raw - fix coding style issues This makes checkpatch.pl happy with the driver Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 396a17fcc34..64fcefb50fb 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -156,7 +156,8 @@ static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) return !empty; } -static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t serio_raw_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) { struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; @@ -187,7 +188,8 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t cou return retval; } -static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t serio_raw_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; @@ -250,7 +252,7 @@ static const struct file_operations serio_raw_fops = { /********************************************************************* - * Interface with serio port * + * Interface with serio port * *********************************************************************/ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, @@ -278,14 +280,16 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) struct serio_raw *serio_raw; int err; - if (!(serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL))) { + serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL); + if (!serio_raw) { dev_dbg(&serio->dev, "can't allocate memory for a device\n"); return -ENOMEM; } mutex_lock(&serio_raw_mutex); - snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); + snprintf(serio_raw->name, sizeof(serio_raw->name), + "serio_raw%d", serio_raw_no++); kref_init(&serio_raw->kref); serio_raw->serio = serio; INIT_LIST_HEAD(&serio_raw->client_list); -- cgit v1.2.3-70-g09d2 From 85f5b35da86bcd63dd27f0976176169727f96da4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:31:04 -0700 Subject: Input: serio_raw - explicitly mark disconnected ports as dead Instead of relying on setting serio_raw->serio to NULL upon disconnecting ports mark them explicitly as "dead". Also take and carry reference to underlying serio port to make sure it does not go away until we are done with it. Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 64fcefb50fb..30ff9638819 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -40,6 +40,7 @@ struct serio_raw { wait_queue_head_t wait; struct list_head client_list; struct list_head node; + bool dead; }; struct serio_raw_client { @@ -91,7 +92,7 @@ static int serio_raw_open(struct inode *inode, struct file *file) goto out; } - if (!serio_raw->serio) { + if (serio_raw->dead) { retval = -ENODEV; goto out; } @@ -123,6 +124,8 @@ static void serio_raw_cleanup(struct kref *kref) misc_deregister(&serio_raw->dev); list_del_init(&serio_raw->node); + + put_device(&serio_raw->serio->dev); kfree(serio_raw); } @@ -164,19 +167,18 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, char uninitialized_var(c); ssize_t retval = 0; - if (!serio_raw->serio) + if (serio_raw->dead) return -ENODEV; if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(serio_raw->wait, - serio_raw->head != serio_raw->tail || - !serio_raw->serio); + serio_raw->head != serio_raw->tail || serio_raw->dead); if (retval) return retval; - if (!serio_raw->serio) + if (serio_raw->dead) return -ENODEV; while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { @@ -201,7 +203,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, if (retval) return retval; - if (!serio_raw->serio) { + if (serio_raw->dead) { retval = -ENODEV; goto out; } @@ -291,10 +293,12 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); kref_init(&serio_raw->kref); - serio_raw->serio = serio; INIT_LIST_HEAD(&serio_raw->client_list); init_waitqueue_head(&serio_raw->wait); + serio_raw->serio = serio; + get_device(&serio->dev); + serio_set_drvdata(serio, serio_raw); err = serio_open(serio, drv); @@ -330,6 +334,7 @@ out_close: list_del_init(&serio_raw->node); out_free: serio_set_drvdata(serio, NULL); + put_device(&serio->dev); kfree(serio_raw); out: mutex_unlock(&serio_raw_mutex); @@ -365,7 +370,7 @@ static void serio_raw_disconnect(struct serio *serio) serio_close(serio); serio_set_drvdata(serio, NULL); - serio_raw->serio = NULL; + serio_raw->dead = true; wake_up_interruptible(&serio_raw->wait); kref_put(&serio_raw->kref, serio_raw_cleanup); -- cgit v1.2.3-70-g09d2 From 8c1c10d5706bbb3b41cb4a5578339d67d3eeffc2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:31:30 -0700 Subject: Input: serio_raw - kick clients when disconnecting port Send SIGIO/POLL_HUP and otherwise wake up waiters when corresponding serio port is being disconnected. Also check if port is dead in serio_raw_poll and signal POLLHUP|POLLERR. This should speed up process of releasing dead devices by userspace applications. Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 30ff9638819..830e2fe70a6 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -232,9 +232,11 @@ static unsigned int serio_raw_poll(struct file *file, poll_table *wait) { struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; + unsigned int mask; poll_wait(file, &serio_raw->wait, wait); + mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM; if (serio_raw->head != serio_raw->tail) return POLLIN | POLLRDNORM; @@ -359,22 +361,37 @@ static int serio_raw_reconnect(struct serio *serio) return 0; } +/* + * Wake up users waiting for IO so they can disconnect from + * dead device. + */ +static void serio_raw_hangup(struct serio_raw *serio_raw) +{ + struct serio_raw_client *client; + + serio_pause_rx(serio_raw->serio); + list_for_each_entry(client, &serio_raw->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + serio_continue_rx(serio_raw->serio); + + wake_up_interruptible(&serio_raw->wait); +} + + static void serio_raw_disconnect(struct serio *serio) { - struct serio_raw *serio_raw; + struct serio_raw *serio_raw = serio_get_drvdata(serio); mutex_lock(&serio_raw_mutex); - serio_raw = serio_get_drvdata(serio); - serio_close(serio); - serio_set_drvdata(serio, NULL); - serio_raw->dead = true; - wake_up_interruptible(&serio_raw->wait); + serio_raw_hangup(serio_raw); kref_put(&serio_raw->kref, serio_raw_cleanup); mutex_unlock(&serio_raw_mutex); + + serio_set_drvdata(serio, NULL); } static struct serio_device_id serio_raw_serio_ids[] = { -- cgit v1.2.3-70-g09d2 From 550eca7cafa1c6e2c077afb2211a364a982d8645 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:31:39 -0700 Subject: Input: serio_raw - fix memory leak when closing char device Apparently we never freed memory allocated when users open our char devices nor removed old users from the list of connected clients. Also unregister misc device immediately upon disconnecting the port instead of waiting until last user drops off (refcounting in misc device code will make sure needed pieces stay around while they are needed) and make sure we are not holing holding serio_raw_mutex when registering/unregistering misc device. This should fix potential deadlock between serio_raw and misc device code uncovered by lockdep and reported by Thomas Tuttle. Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 54 ++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 830e2fe70a6..4d4cd142bbb 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -51,7 +51,6 @@ struct serio_raw_client { static DEFINE_MUTEX(serio_raw_mutex); static LIST_HEAD(serio_raw_list); -static unsigned int serio_raw_no; /********************************************************************* * Interface with userspace (file operations) * @@ -117,14 +116,11 @@ out: return retval; } -static void serio_raw_cleanup(struct kref *kref) +static void serio_raw_free(struct kref *kref) { struct serio_raw *serio_raw = container_of(kref, struct serio_raw, kref); - misc_deregister(&serio_raw->dev); - list_del_init(&serio_raw->node); - put_device(&serio_raw->serio->dev); kfree(serio_raw); } @@ -134,11 +130,14 @@ static int serio_raw_release(struct inode *inode, struct file *file) struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; - mutex_lock(&serio_raw_mutex); + serio_pause_rx(serio_raw->serio); + list_del(&client->node); + serio_continue_rx(serio_raw->serio); - kref_put(&serio_raw->kref, serio_raw_cleanup); + kfree(client); + + kref_put(&serio_raw->kref, serio_raw_free); - mutex_unlock(&serio_raw_mutex); return 0; } @@ -281,6 +280,7 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) { + static atomic_t serio_raw_no = ATOMIC_INIT(0); struct serio_raw *serio_raw; int err; @@ -290,10 +290,8 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) return -ENOMEM; } - mutex_lock(&serio_raw_mutex); - snprintf(serio_raw->name, sizeof(serio_raw->name), - "serio_raw%d", serio_raw_no++); + "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no) - 1); kref_init(&serio_raw->kref); INIT_LIST_HEAD(&serio_raw->client_list); init_waitqueue_head(&serio_raw->wait); @@ -305,9 +303,14 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) err = serio_open(serio, drv); if (err) - goto out_free; + goto err_free; + + err = mutex_lock_killable(&serio_raw_mutex); + if (err) + goto err_close; list_add_tail(&serio_raw->node, &serio_raw_list); + mutex_unlock(&serio_raw_mutex); serio_raw->dev.minor = PSMOUSE_MINOR; serio_raw->dev.name = serio_raw->name; @@ -324,22 +327,20 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) dev_err(&serio->dev, "failed to register raw access device for %s\n", serio->phys); - goto out_close; + goto err_unlink; } dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n", serio->phys, serio_raw->name, serio_raw->dev.minor); - goto out; + return 0; -out_close: - serio_close(serio); +err_unlink: list_del_init(&serio_raw->node); -out_free: +err_close: + serio_close(serio); +err_free: serio_set_drvdata(serio, NULL); - put_device(&serio->dev); - kfree(serio_raw); -out: - mutex_unlock(&serio_raw_mutex); + kref_put(&serio_raw->kref, serio_raw_free); return err; } @@ -382,14 +383,17 @@ static void serio_raw_disconnect(struct serio *serio) { struct serio_raw *serio_raw = serio_get_drvdata(serio); - mutex_lock(&serio_raw_mutex); + misc_deregister(&serio_raw->dev); - serio_close(serio); + mutex_lock(&serio_raw_mutex); serio_raw->dead = true; + list_del_init(&serio_raw->node); + mutex_unlock(&serio_raw_mutex); + serio_raw_hangup(serio_raw); - kref_put(&serio_raw->kref, serio_raw_cleanup); - mutex_unlock(&serio_raw_mutex); + serio_close(serio); + kref_put(&serio_raw->kref, serio_raw_free); serio_set_drvdata(serio, NULL); } -- cgit v1.2.3-70-g09d2 From 341deefe8f4584b09564193cb46d8cf386f491a5 Mon Sep 17 00:00:00 2001 From: Philip Rakity Date: Tue, 11 Oct 2011 20:54:55 -0700 Subject: Input: tsc2007 - make sure that X plate resistance is specified Abort driver initialization if X plate resistance was not specified in platform data as it will cause pressure to be always calculated as 0, and making userspace ignore touch coordinates. Signed-off-by: Philip Rakity Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 6 ++++++ include/linux/i2c/tsc2007.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 0acca68cc52..1f674cb6c55 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -310,6 +310,12 @@ static int __devinit tsc2007_probe(struct i2c_client *client, ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; + if (pdata->x_plate_ohms == 0) { + dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); + err = -EINVAL; + goto err_free_mem; + } + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h index 591427a63b0..506a9f7af51 100644 --- a/include/linux/i2c/tsc2007.h +++ b/include/linux/i2c/tsc2007.h @@ -5,7 +5,7 @@ struct tsc2007_platform_data { u16 model; /* 2007. */ - u16 x_plate_ohms; + u16 x_plate_ohms; /* must be non-zero value */ u16 max_rt; /* max. resistance above which samples are ignored */ unsigned long poll_delay; /* delay (in ms) after pen-down event before polling starts */ -- cgit v1.2.3-70-g09d2 From 05be8b81aafd4f95106a91ff3fd8581fa984fad9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2011 21:05:53 -0700 Subject: Input: force feedback - potential integer wrap in input_ff_create() The problem here is that max_effects can wrap on 32 bits systems. We'd allocate a smaller amount of data than sizeof(struct ff_device). The call to kcalloc() on the next line would fail but it would write the NULL return outside of the memory we just allocated causing data corruption. The call path is that uinput_setup_device() get ->ff_effects_max from the user and sets the value in the ->private_data struct. From there it is: -> uinput_ioctl_handler() -> uinput_create_device() -> input_ff_create(dev, udev->ff_effects_max); I've also changed ff_effects_max so it's an unsigned int instead of a signed int as a cleanup. Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov --- drivers/input/ff-core.c | 11 ++++++++--- include/linux/input.h | 2 +- include/linux/uinput.h | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 3367f760d75..480eb9d9876 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -309,9 +309,10 @@ EXPORT_SYMBOL_GPL(input_ff_event); * Once ff device is created you need to setup its upload, erase, * playback and other handlers before registering input device */ -int input_ff_create(struct input_dev *dev, int max_effects) +int input_ff_create(struct input_dev *dev, unsigned int max_effects) { struct ff_device *ff; + size_t ff_dev_size; int i; if (!max_effects) { @@ -319,8 +320,12 @@ int input_ff_create(struct input_dev *dev, int max_effects) return -EINVAL; } - ff = kzalloc(sizeof(struct ff_device) + - max_effects * sizeof(struct file *), GFP_KERNEL); + ff_dev_size = sizeof(struct ff_device) + + max_effects * sizeof(struct file *); + if (ff_dev_size < max_effects) /* overflow */ + return -EINVAL; + + ff = kzalloc(ff_dev_size, GFP_KERNEL); if (!ff) return -ENOMEM; diff --git a/include/linux/input.h b/include/linux/input.h index 57add325e7a..6d5eddb18c8 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1610,7 +1610,7 @@ struct ff_device { struct file *effect_owners[]; }; -int input_ff_create(struct input_dev *dev, int max_effects); +int input_ff_create(struct input_dev *dev, unsigned int max_effects); void input_ff_destroy(struct input_dev *dev); int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); diff --git a/include/linux/uinput.h b/include/linux/uinput.h index d28c726ede4..2aa2881b0df 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h @@ -68,7 +68,7 @@ struct uinput_device { unsigned char head; unsigned char tail; struct input_event buff[UINPUT_BUFFER_SIZE]; - int ff_effects_max; + unsigned int ff_effects_max; struct uinput_request *requests[UINPUT_NUM_REQUESTS]; wait_queue_head_t requests_waitq; -- cgit v1.2.3-70-g09d2 From 81e8f2bc82cd591a749c0cc5694f57676db749ae Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 12 Oct 2011 21:11:16 -0700 Subject: Input: imx_keypad - add pm suspend and resume support The imx_keypad driver was indicating that it was wakeup capable in imx_keypad_probe(), but it didn't implement suspend or resume methods. According to the i.MX series MCU Reference Manual, the kpp (keypad port) is a major wake up source which can detect any key press even in low power mode and even when there is no clock. Signed-off-by: Hui Wang Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/imx_keypad.c | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 4b093faf578..ccebd2d0915 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -567,10 +567,54 @@ static int __devexit imx_keypad_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int imx_kbd_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_keypad *kbd = platform_get_drvdata(pdev); + struct input_dev *input_dev = kbd->input_dev; + + /* imx kbd can wake up system even clock is disabled */ + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + clk_disable(kbd->clk); + + mutex_unlock(&input_dev->mutex); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(kbd->irq); + + return 0; +} + +static int imx_kbd_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_keypad *kbd = platform_get_drvdata(pdev); + struct input_dev *input_dev = kbd->input_dev; + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(kbd->irq); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + clk_enable(kbd->clk); + + mutex_unlock(&input_dev->mutex); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume); + static struct platform_driver imx_keypad_driver = { .driver = { .name = "imx-keypad", .owner = THIS_MODULE, + .pm = &imx_kbd_pm_ops, }, .probe = imx_keypad_probe, .remove = __devexit_p(imx_keypad_remove), -- cgit v1.2.3-70-g09d2 From 3f48e7354358519e5b93f7f755ec270b3f8eafa0 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 18 Oct 2011 21:12:39 -0700 Subject: Input: adp5589-keys - add support for the ADP5585 derivatives The ADP5585 family keypad decoder and IO expander is similar to the ADP5589, however it features less IO pins, and lacks hardware assisted key-lock functionality. Unfortunately the register addresses are different, as well as the event codes and bit organization within the port related registers. Move ADP5589 Register defines from the header file into the main source file. Add new defines while making sure we don't break existing platform_data. Add register address translation, and turn device specific defines into variables. Introduce some helper functions and disable functions that doesn't exist on the added devices. Signed-off-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 4 +- drivers/input/keyboard/adp5589-keys.c | 609 +++++++++++++++++++++++++++------- include/linux/input/adp5589.h | 157 ++++----- 3 files changed, 550 insertions(+), 220 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b4dee9d5a05..615c21f2a55 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -33,10 +33,10 @@ config KEYBOARD_ADP5588 module will be called adp5588-keys. config KEYBOARD_ADP5589 - tristate "ADP5589 I2C QWERTY Keypad and IO Expander" + tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander" depends on I2C help - Say Y here if you want to use a ADP5589 attached to your + Say Y here if you want to use a ADP5585/ADP5589 attached to your system I2C bus. To compile this driver as a module, choose M here: the diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index c7708263051..02b5d53031b 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1,5 +1,5 @@ /* - * Description: keypad driver for ADP5589 + * Description: keypad driver for ADP5589, ADP5585 * I2C QWERTY Keypad and IO Expander * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -22,35 +22,165 @@ #include +/* ADP5589/ADP5585 Common Registers */ +#define ADP5589_5_ID 0x00 +#define ADP5589_5_INT_STATUS 0x01 +#define ADP5589_5_STATUS 0x02 +#define ADP5589_5_FIFO_1 0x03 +#define ADP5589_5_FIFO_2 0x04 +#define ADP5589_5_FIFO_3 0x05 +#define ADP5589_5_FIFO_4 0x06 +#define ADP5589_5_FIFO_5 0x07 +#define ADP5589_5_FIFO_6 0x08 +#define ADP5589_5_FIFO_7 0x09 +#define ADP5589_5_FIFO_8 0x0A +#define ADP5589_5_FIFO_9 0x0B +#define ADP5589_5_FIFO_10 0x0C +#define ADP5589_5_FIFO_11 0x0D +#define ADP5589_5_FIFO_12 0x0E +#define ADP5589_5_FIFO_13 0x0F +#define ADP5589_5_FIFO_14 0x10 +#define ADP5589_5_FIFO_15 0x11 +#define ADP5589_5_FIFO_16 0x12 +#define ADP5589_5_GPI_INT_STAT_A 0x13 +#define ADP5589_5_GPI_INT_STAT_B 0x14 + +/* ADP5589 Registers */ +#define ADP5589_GPI_INT_STAT_C 0x15 +#define ADP5589_GPI_STATUS_A 0x16 +#define ADP5589_GPI_STATUS_B 0x17 +#define ADP5589_GPI_STATUS_C 0x18 +#define ADP5589_RPULL_CONFIG_A 0x19 +#define ADP5589_RPULL_CONFIG_B 0x1A +#define ADP5589_RPULL_CONFIG_C 0x1B +#define ADP5589_RPULL_CONFIG_D 0x1C +#define ADP5589_RPULL_CONFIG_E 0x1D +#define ADP5589_GPI_INT_LEVEL_A 0x1E +#define ADP5589_GPI_INT_LEVEL_B 0x1F +#define ADP5589_GPI_INT_LEVEL_C 0x20 +#define ADP5589_GPI_EVENT_EN_A 0x21 +#define ADP5589_GPI_EVENT_EN_B 0x22 +#define ADP5589_GPI_EVENT_EN_C 0x23 +#define ADP5589_GPI_INTERRUPT_EN_A 0x24 +#define ADP5589_GPI_INTERRUPT_EN_B 0x25 +#define ADP5589_GPI_INTERRUPT_EN_C 0x26 +#define ADP5589_DEBOUNCE_DIS_A 0x27 +#define ADP5589_DEBOUNCE_DIS_B 0x28 +#define ADP5589_DEBOUNCE_DIS_C 0x29 +#define ADP5589_GPO_DATA_OUT_A 0x2A +#define ADP5589_GPO_DATA_OUT_B 0x2B +#define ADP5589_GPO_DATA_OUT_C 0x2C +#define ADP5589_GPO_OUT_MODE_A 0x2D +#define ADP5589_GPO_OUT_MODE_B 0x2E +#define ADP5589_GPO_OUT_MODE_C 0x2F +#define ADP5589_GPIO_DIRECTION_A 0x30 +#define ADP5589_GPIO_DIRECTION_B 0x31 +#define ADP5589_GPIO_DIRECTION_C 0x32 +#define ADP5589_UNLOCK1 0x33 +#define ADP5589_UNLOCK2 0x34 +#define ADP5589_EXT_LOCK_EVENT 0x35 +#define ADP5589_UNLOCK_TIMERS 0x36 +#define ADP5589_LOCK_CFG 0x37 +#define ADP5589_RESET1_EVENT_A 0x38 +#define ADP5589_RESET1_EVENT_B 0x39 +#define ADP5589_RESET1_EVENT_C 0x3A +#define ADP5589_RESET2_EVENT_A 0x3B +#define ADP5589_RESET2_EVENT_B 0x3C +#define ADP5589_RESET_CFG 0x3D +#define ADP5589_PWM_OFFT_LOW 0x3E +#define ADP5589_PWM_OFFT_HIGH 0x3F +#define ADP5589_PWM_ONT_LOW 0x40 +#define ADP5589_PWM_ONT_HIGH 0x41 +#define ADP5589_PWM_CFG 0x42 +#define ADP5589_CLOCK_DIV_CFG 0x43 +#define ADP5589_LOGIC_1_CFG 0x44 +#define ADP5589_LOGIC_2_CFG 0x45 +#define ADP5589_LOGIC_FF_CFG 0x46 +#define ADP5589_LOGIC_INT_EVENT_EN 0x47 +#define ADP5589_POLL_PTIME_CFG 0x48 +#define ADP5589_PIN_CONFIG_A 0x49 +#define ADP5589_PIN_CONFIG_B 0x4A +#define ADP5589_PIN_CONFIG_C 0x4B +#define ADP5589_PIN_CONFIG_D 0x4C +#define ADP5589_GENERAL_CFG 0x4D +#define ADP5589_INT_EN 0x4E + +/* ADP5585 Registers */ +#define ADP5585_GPI_STATUS_A 0x15 +#define ADP5585_GPI_STATUS_B 0x16 +#define ADP5585_RPULL_CONFIG_A 0x17 +#define ADP5585_RPULL_CONFIG_B 0x18 +#define ADP5585_RPULL_CONFIG_C 0x19 +#define ADP5585_RPULL_CONFIG_D 0x1A +#define ADP5585_GPI_INT_LEVEL_A 0x1B +#define ADP5585_GPI_INT_LEVEL_B 0x1C +#define ADP5585_GPI_EVENT_EN_A 0x1D +#define ADP5585_GPI_EVENT_EN_B 0x1E +#define ADP5585_GPI_INTERRUPT_EN_A 0x1F +#define ADP5585_GPI_INTERRUPT_EN_B 0x20 +#define ADP5585_DEBOUNCE_DIS_A 0x21 +#define ADP5585_DEBOUNCE_DIS_B 0x22 +#define ADP5585_GPO_DATA_OUT_A 0x23 +#define ADP5585_GPO_DATA_OUT_B 0x24 +#define ADP5585_GPO_OUT_MODE_A 0x25 +#define ADP5585_GPO_OUT_MODE_B 0x26 +#define ADP5585_GPIO_DIRECTION_A 0x27 +#define ADP5585_GPIO_DIRECTION_B 0x28 +#define ADP5585_RESET1_EVENT_A 0x29 +#define ADP5585_RESET1_EVENT_B 0x2A +#define ADP5585_RESET1_EVENT_C 0x2B +#define ADP5585_RESET2_EVENT_A 0x2C +#define ADP5585_RESET2_EVENT_B 0x2D +#define ADP5585_RESET_CFG 0x2E +#define ADP5585_PWM_OFFT_LOW 0x2F +#define ADP5585_PWM_OFFT_HIGH 0x30 +#define ADP5585_PWM_ONT_LOW 0x31 +#define ADP5585_PWM_ONT_HIGH 0x32 +#define ADP5585_PWM_CFG 0x33 +#define ADP5585_LOGIC_CFG 0x34 +#define ADP5585_LOGIC_FF_CFG 0x35 +#define ADP5585_LOGIC_INT_EVENT_EN 0x36 +#define ADP5585_POLL_PTIME_CFG 0x37 +#define ADP5585_PIN_CONFIG_A 0x38 +#define ADP5585_PIN_CONFIG_B 0x39 +#define ADP5585_PIN_CONFIG_D 0x3A +#define ADP5585_GENERAL_CFG 0x3B +#define ADP5585_INT_EN 0x3C + +/* ID Register */ +#define ADP5589_5_DEVICE_ID_MASK 0xF +#define ADP5589_5_MAN_ID_MASK 0xF +#define ADP5589_5_MAN_ID_SHIFT 4 +#define ADP5589_5_MAN_ID 0x02 + /* GENERAL_CFG Register */ #define OSC_EN (1 << 7) #define CORE_CLK(x) (((x) & 0x3) << 5) -#define LCK_TRK_LOGIC (1 << 4) -#define LCK_TRK_GPI (1 << 3) +#define LCK_TRK_LOGIC (1 << 4) /* ADP5589 only */ +#define LCK_TRK_GPI (1 << 3) /* ADP5589 only */ #define INT_CFG (1 << 1) #define RST_CFG (1 << 0) /* INT_EN Register */ -#define LOGIC2_IEN (1 << 5) +#define LOGIC2_IEN (1 << 5) /* ADP5589 only */ #define LOGIC1_IEN (1 << 4) -#define LOCK_IEN (1 << 3) +#define LOCK_IEN (1 << 3) /* ADP5589 only */ #define OVRFLOW_IEN (1 << 2) #define GPI_IEN (1 << 1) #define EVENT_IEN (1 << 0) /* Interrupt Status Register */ -#define LOGIC2_INT (1 << 5) +#define LOGIC2_INT (1 << 5) /* ADP5589 only */ #define LOGIC1_INT (1 << 4) -#define LOCK_INT (1 << 3) +#define LOCK_INT (1 << 3) /* ADP5589 only */ #define OVRFLOW_INT (1 << 2) #define GPI_INT (1 << 1) #define EVENT_INT (1 << 0) /* STATUS Register */ - -#define LOGIC2_STAT (1 << 7) +#define LOGIC2_STAT (1 << 7) /* ADP5589 only */ #define LOGIC1_STAT (1 << 6) -#define LOCK_STAT (1 << 5) +#define LOCK_STAT (1 << 5) /* ADP5589 only */ #define KEC 0xF /* PIN_CONFIG_D Register */ @@ -61,27 +191,54 @@ #define LOCK_EN (1 << 0) #define PTIME_MASK 0x3 -#define LTIME_MASK 0x3 +#define LTIME_MASK 0x3 /* ADP5589 only */ /* Key Event Register xy */ #define KEY_EV_PRESSED (1 << 7) #define KEY_EV_MASK (0x7F) #define KEYP_MAX_EVENT 16 +#define ADP5589_MAXGPIO 19 +#define ADP5585_MAXGPIO 11 /* 10 on the ADP5585-01, 11 on ADP5585-02 */ -#define MAXGPIO 19 -#define ADP_BANK(offs) ((offs) >> 3) -#define ADP_BIT(offs) (1u << ((offs) & 0x7)) +enum { + ADP5589, + ADP5585_01, + ADP5585_02 +}; + +struct adp_constants { + u8 maxgpio; + u8 keymapsize; + u8 gpi_pin_row_base; + u8 gpi_pin_row_end; + u8 gpi_pin_col_base; + u8 gpi_pin_base; + u8 gpi_pin_end; + u8 gpimapsize_max; + u8 max_row_num; + u8 max_col_num; + u8 row_mask; + u8 col_mask; + u8 col_shift; + u8 c4_extend_cfg; + u8 (*bank) (u8 offset); + u8 (*bit) (u8 offset); + u8 (*reg) (u8 reg); +}; struct adp5589_kpad { struct i2c_client *client; struct input_dev *input; + const struct adp_constants *var; unsigned short keycode[ADP5589_KEYMAPSIZE]; const struct adp5589_gpi_map *gpimap; unsigned short gpimapsize; unsigned extend_cfg; + bool is_adp5585; + bool adp5585_support_row5; #ifdef CONFIG_GPIOLIB - unsigned char gpiomap[MAXGPIO]; + unsigned char gpiomap[ADP5589_MAXGPIO]; bool export_gpio; struct gpio_chip gc; struct mutex gpio_lock; /* Protect cached dir, dat_out */ @@ -90,6 +247,129 @@ struct adp5589_kpad { #endif }; +/* + * ADP5589 / ADP5585 derivative / variant handling + */ + + +/* ADP5589 */ + +static unsigned char adp5589_bank(unsigned char offset) +{ + return offset >> 3; +} + +static unsigned char adp5589_bit(unsigned char offset) +{ + return 1u << (offset & 0x7); +} + +static unsigned char adp5589_reg(unsigned char reg) +{ + return reg; +} + +static const struct adp_constants const_adp5589 = { + .maxgpio = ADP5589_MAXGPIO, + .keymapsize = ADP5589_KEYMAPSIZE, + .gpi_pin_row_base = ADP5589_GPI_PIN_ROW_BASE, + .gpi_pin_row_end = ADP5589_GPI_PIN_ROW_END, + .gpi_pin_col_base = ADP5589_GPI_PIN_COL_BASE, + .gpi_pin_base = ADP5589_GPI_PIN_BASE, + .gpi_pin_end = ADP5589_GPI_PIN_END, + .gpimapsize_max = ADP5589_GPIMAPSIZE_MAX, + .c4_extend_cfg = 12, + .max_row_num = ADP5589_MAX_ROW_NUM, + .max_col_num = ADP5589_MAX_COL_NUM, + .row_mask = ADP5589_ROW_MASK, + .col_mask = ADP5589_COL_MASK, + .col_shift = ADP5589_COL_SHIFT, + .bank = adp5589_bank, + .bit = adp5589_bit, + .reg = adp5589_reg, +}; + +/* ADP5585 */ + +static unsigned char adp5585_bank(unsigned char offset) +{ + return offset > ADP5585_MAX_ROW_NUM; +} + +static unsigned char adp5585_bit(unsigned char offset) +{ + return (offset > ADP5585_MAX_ROW_NUM) ? + 1u << (offset - ADP5585_COL_SHIFT) : 1u << offset; +} + +static const unsigned char adp5585_reg_lut[] = { + [ADP5589_GPI_STATUS_A] = ADP5585_GPI_STATUS_A, + [ADP5589_GPI_STATUS_B] = ADP5585_GPI_STATUS_B, + [ADP5589_RPULL_CONFIG_A] = ADP5585_RPULL_CONFIG_A, + [ADP5589_RPULL_CONFIG_B] = ADP5585_RPULL_CONFIG_B, + [ADP5589_RPULL_CONFIG_C] = ADP5585_RPULL_CONFIG_C, + [ADP5589_RPULL_CONFIG_D] = ADP5585_RPULL_CONFIG_D, + [ADP5589_GPI_INT_LEVEL_A] = ADP5585_GPI_INT_LEVEL_A, + [ADP5589_GPI_INT_LEVEL_B] = ADP5585_GPI_INT_LEVEL_B, + [ADP5589_GPI_EVENT_EN_A] = ADP5585_GPI_EVENT_EN_A, + [ADP5589_GPI_EVENT_EN_B] = ADP5585_GPI_EVENT_EN_B, + [ADP5589_GPI_INTERRUPT_EN_A] = ADP5585_GPI_INTERRUPT_EN_A, + [ADP5589_GPI_INTERRUPT_EN_B] = ADP5585_GPI_INTERRUPT_EN_B, + [ADP5589_DEBOUNCE_DIS_A] = ADP5585_DEBOUNCE_DIS_A, + [ADP5589_DEBOUNCE_DIS_B] = ADP5585_DEBOUNCE_DIS_B, + [ADP5589_GPO_DATA_OUT_A] = ADP5585_GPO_DATA_OUT_A, + [ADP5589_GPO_DATA_OUT_B] = ADP5585_GPO_DATA_OUT_B, + [ADP5589_GPO_OUT_MODE_A] = ADP5585_GPO_OUT_MODE_A, + [ADP5589_GPO_OUT_MODE_B] = ADP5585_GPO_OUT_MODE_B, + [ADP5589_GPIO_DIRECTION_A] = ADP5585_GPIO_DIRECTION_A, + [ADP5589_GPIO_DIRECTION_B] = ADP5585_GPIO_DIRECTION_B, + [ADP5589_RESET1_EVENT_A] = ADP5585_RESET1_EVENT_A, + [ADP5589_RESET1_EVENT_B] = ADP5585_RESET1_EVENT_B, + [ADP5589_RESET1_EVENT_C] = ADP5585_RESET1_EVENT_C, + [ADP5589_RESET2_EVENT_A] = ADP5585_RESET2_EVENT_A, + [ADP5589_RESET2_EVENT_B] = ADP5585_RESET2_EVENT_B, + [ADP5589_RESET_CFG] = ADP5585_RESET_CFG, + [ADP5589_PWM_OFFT_LOW] = ADP5585_PWM_OFFT_LOW, + [ADP5589_PWM_OFFT_HIGH] = ADP5585_PWM_OFFT_HIGH, + [ADP5589_PWM_ONT_LOW] = ADP5585_PWM_ONT_LOW, + [ADP5589_PWM_ONT_HIGH] = ADP5585_PWM_ONT_HIGH, + [ADP5589_PWM_CFG] = ADP5585_PWM_CFG, + [ADP5589_LOGIC_1_CFG] = ADP5585_LOGIC_CFG, + [ADP5589_LOGIC_FF_CFG] = ADP5585_LOGIC_FF_CFG, + [ADP5589_LOGIC_INT_EVENT_EN] = ADP5585_LOGIC_INT_EVENT_EN, + [ADP5589_POLL_PTIME_CFG] = ADP5585_POLL_PTIME_CFG, + [ADP5589_PIN_CONFIG_A] = ADP5585_PIN_CONFIG_A, + [ADP5589_PIN_CONFIG_B] = ADP5585_PIN_CONFIG_B, + [ADP5589_PIN_CONFIG_D] = ADP5585_PIN_CONFIG_D, + [ADP5589_GENERAL_CFG] = ADP5585_GENERAL_CFG, + [ADP5589_INT_EN] = ADP5585_INT_EN, +}; + +static unsigned char adp5585_reg(unsigned char reg) +{ + return adp5585_reg_lut[reg]; +} + +static const struct adp_constants const_adp5585 = { + .maxgpio = ADP5585_MAXGPIO, + .keymapsize = ADP5585_KEYMAPSIZE, + .gpi_pin_row_base = ADP5585_GPI_PIN_ROW_BASE, + .gpi_pin_row_end = ADP5585_GPI_PIN_ROW_END, + .gpi_pin_col_base = ADP5585_GPI_PIN_COL_BASE, + .gpi_pin_base = ADP5585_GPI_PIN_BASE, + .gpi_pin_end = ADP5585_GPI_PIN_END, + .gpimapsize_max = ADP5585_GPIMAPSIZE_MAX, + .c4_extend_cfg = 10, + .max_row_num = ADP5585_MAX_ROW_NUM, + .max_col_num = ADP5585_MAX_COL_NUM, + .row_mask = ADP5585_ROW_MASK, + .col_mask = ADP5585_COL_MASK, + .col_shift = ADP5585_COL_SHIFT, + .bank = adp5585_bank, + .bit = adp5585_bit, + .reg = adp5585_reg, +}; + static int adp5589_read(struct i2c_client *client, u8 reg) { int ret = i2c_smbus_read_byte_data(client, reg); @@ -109,19 +389,20 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val) static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) & - bit); + return !!(adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_A) + bank) & + bit); } static void adp5589_gpio_set_value(struct gpio_chip *chip, unsigned off, int val) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); mutex_lock(&kpad->gpio_lock); @@ -130,8 +411,8 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, else kpad->dat_out[bank] &= ~bit; - adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank, - kpad->dat_out[bank]); + adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + + bank, kpad->dat_out[bank]); mutex_unlock(&kpad->gpio_lock); } @@ -139,14 +420,15 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); int ret; mutex_lock(&kpad->gpio_lock); kpad->dir[bank] &= ~bit; - ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank, + ret = adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, kpad->dir[bank]); mutex_unlock(&kpad->gpio_lock); @@ -158,8 +440,8 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, unsigned off, int val) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); int ret; mutex_lock(&kpad->gpio_lock); @@ -171,9 +453,10 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, else kpad->dat_out[bank] &= ~bit; - ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank, - kpad->dat_out[bank]); - ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank, + ret = adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + + bank, kpad->dat_out[bank]); + ret |= adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, kpad->dir[bank]); mutex_unlock(&kpad->gpio_lock); @@ -184,26 +467,29 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad, const struct adp5589_kpad_platform_data *pdata) { - bool pin_used[MAXGPIO]; + bool pin_used[ADP5589_MAXGPIO]; int n_unused = 0; int i; memset(pin_used, false, sizeof(pin_used)); - for (i = 0; i < MAXGPIO; i++) + for (i = 0; i < kpad->var->maxgpio; i++) if (pdata->keypad_en_mask & (1 << i)) pin_used[i] = true; for (i = 0; i < kpad->gpimapsize; i++) - pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true; + pin_used[kpad->gpimap[i].pin - kpad->var->gpi_pin_base] = true; if (kpad->extend_cfg & R4_EXTEND_CFG) pin_used[4] = true; if (kpad->extend_cfg & C4_EXTEND_CFG) - pin_used[12] = true; + pin_used[kpad->var->c4_extend_cfg] = true; + + if (!kpad->adp5585_support_row5) + pin_used[5] = true; - for (i = 0; i < MAXGPIO; i++) + for (i = 0; i < kpad->var->maxgpio; i++) if (!pin_used[i]) kpad->gpiomap[n_unused++] = i; @@ -246,11 +532,11 @@ static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad) return error; } - for (i = 0; i <= ADP_BANK(MAXGPIO); i++) { - kpad->dat_out[i] = adp5589_read(kpad->client, - ADP5589_GPO_DATA_OUT_A + i); - kpad->dir[i] = adp5589_read(kpad->client, - ADP5589_GPIO_DIRECTION_A + i); + for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) { + kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg( + ADP5589_GPO_DATA_OUT_A) + i); + kpad->dir[i] = adp5589_read(kpad->client, kpad->var->reg( + ADP5589_GPIO_DIRECTION_A) + i); } if (gpio_data->setup) { @@ -317,11 +603,11 @@ static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt) int i; for (i = 0; i < ev_cnt; i++) { - int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i); + int key = adp5589_read(kpad->client, ADP5589_5_FIFO_1 + i); int key_val = key & KEY_EV_MASK; - if (key_val >= ADP5589_GPI_PIN_BASE && - key_val <= ADP5589_GPI_PIN_END) { + if (key_val >= kpad->var->gpi_pin_base && + key_val <= kpad->var->gpi_pin_end) { adp5589_report_switches(kpad, key, key_val); } else { input_report_key(kpad->input, @@ -337,29 +623,30 @@ static irqreturn_t adp5589_irq(int irq, void *handle) struct i2c_client *client = kpad->client; int status, ev_cnt; - status = adp5589_read(client, ADP5589_INT_STATUS); + status = adp5589_read(client, ADP5589_5_INT_STATUS); if (status & OVRFLOW_INT) /* Unlikely and should never happen */ dev_err(&client->dev, "Event Overflow Error\n"); if (status & EVENT_INT) { - ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC; + ev_cnt = adp5589_read(client, ADP5589_5_STATUS) & KEC; if (ev_cnt) { adp5589_report_events(kpad, ev_cnt); input_sync(kpad->input); } } - adp5589_write(client, ADP5589_INT_STATUS, status); /* Status is W1C */ + adp5589_write(client, ADP5589_5_INT_STATUS, status); /* Status is W1C */ return IRQ_HANDLED; } -static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key) +static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, + unsigned short key) { int i; - for (i = 0; i < ADP5589_KEYMAPSIZE; i++) + for (i = 0; i < kpad->var->keymapsize; i++) if (key == kpad->keycode[i]) return (i + 1) | KEY_EV_PRESSED; @@ -372,19 +659,23 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) { struct i2c_client *client = kpad->client; const struct adp5589_kpad_platform_data *pdata = - client->dev.platform_data; - int i, ret; + client->dev.platform_data; + u8 (*reg) (u8) = kpad->var->reg; unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; unsigned char pull_mask = 0; + int i, ret; + + ret = adp5589_write(client, reg(ADP5589_PIN_CONFIG_A), + pdata->keypad_en_mask & kpad->var->row_mask); + ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_B), + (pdata->keypad_en_mask >> kpad->var->col_shift) & + kpad->var->col_mask); - ret = adp5589_write(client, ADP5589_PIN_CONFIG_A, - pdata->keypad_en_mask & 0xFF); - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B, - (pdata->keypad_en_mask >> 8) & 0xFF); - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C, - (pdata->keypad_en_mask >> 16) & 0xFF); + if (!kpad->is_adp5585) + ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C, + (pdata->keypad_en_mask >> 16) & 0xFF); - if (pdata->en_keylock) { + if (!kpad->is_adp5585 && pdata->en_keylock) { ret |= adp5589_write(client, ADP5589_UNLOCK1, pdata->unlock_key1); ret |= adp5589_write(client, ADP5589_UNLOCK2, @@ -395,96 +686,130 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) } for (i = 0; i < KEYP_MAX_EVENT; i++) - ret |= adp5589_read(client, ADP5589_FIFO_1 + i); + ret |= adp5589_read(client, ADP5589_5_FIFO_1 + i); for (i = 0; i < pdata->gpimapsize; i++) { unsigned short pin = pdata->gpimap[i].pin; - if (pin <= ADP5589_GPI_PIN_ROW_END) { - evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE)); + if (pin <= kpad->var->gpi_pin_row_end) { + evt_mode1 |= (1 << (pin - kpad->var->gpi_pin_row_base)); } else { evt_mode2 |= - ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF); - evt_mode3 |= - ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8); + ((1 << (pin - kpad->var->gpi_pin_col_base)) & 0xFF); + if (!kpad->is_adp5585) + evt_mode3 |= ((1 << (pin - + kpad->var->gpi_pin_col_base)) >> 8); } } if (pdata->gpimapsize) { - ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1); - ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2); - ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3); + ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_A), + evt_mode1); + ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_B), + evt_mode2); + if (!kpad->is_adp5585) + ret |= adp5589_write(client, + reg(ADP5589_GPI_EVENT_EN_C), + evt_mode3); } if (pdata->pull_dis_mask & pdata->pullup_en_100k & - pdata->pullup_en_300k & pdata->pulldown_en_300k) + pdata->pullup_en_300k & pdata->pulldown_en_300k) dev_warn(&client->dev, "Conflicting pull resistor config\n"); - for (i = 0; i < MAXGPIO; i++) { - unsigned val = 0; + for (i = 0; i <= kpad->var->max_row_num; i++) { + unsigned val = 0, bit = (1 << i); + if (pdata->pullup_en_300k & bit) + val = 0; + else if (pdata->pulldown_en_300k & bit) + val = 1; + else if (pdata->pullup_en_100k & bit) + val = 2; + else if (pdata->pull_dis_mask & bit) + val = 3; + + pull_mask |= val << (2 * (i & 0x3)); + + if (i == 3 || i == kpad->var->max_row_num) { + ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A) + + (i >> 2), pull_mask); + pull_mask = 0; + } + } - if (pdata->pullup_en_300k & (1 << i)) + for (i = 0; i <= kpad->var->max_col_num; i++) { + unsigned val = 0, bit = 1 << (i + kpad->var->col_shift); + if (pdata->pullup_en_300k & bit) val = 0; - else if (pdata->pulldown_en_300k & (1 << i)) + else if (pdata->pulldown_en_300k & bit) val = 1; - else if (pdata->pullup_en_100k & (1 << i)) + else if (pdata->pullup_en_100k & bit) val = 2; - else if (pdata->pull_dis_mask & (1 << i)) + else if (pdata->pull_dis_mask & bit) val = 3; pull_mask |= val << (2 * (i & 0x3)); - if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) { + if (i == 3 || i == kpad->var->max_col_num) { ret |= adp5589_write(client, - ADP5589_RPULL_CONFIG_A + (i >> 2), - pull_mask); + reg(ADP5585_RPULL_CONFIG_C) + + (i >> 2), pull_mask); pull_mask = 0; } } if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) { - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_A), adp5589_get_evcode(kpad, pdata->reset1_key_1)); - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_B), adp5589_get_evcode(kpad, pdata->reset1_key_2)); - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_C), adp5589_get_evcode(kpad, pdata->reset1_key_3)); kpad->extend_cfg |= R4_EXTEND_CFG; } if (pdata->reset2_key_1 && pdata->reset2_key_2) { - ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A, + ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_A), adp5589_get_evcode(kpad, pdata->reset2_key_1)); - ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B, + ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_B), adp5589_get_evcode(kpad, pdata->reset2_key_2)); kpad->extend_cfg |= C4_EXTEND_CFG; } if (kpad->extend_cfg) { - ret |= adp5589_write(client, ADP5589_RESET_CFG, + ret |= adp5589_write(client, reg(ADP5589_RESET_CFG), pdata->reset_cfg); - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D, + ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_D), kpad->extend_cfg); } - for (i = 0; i <= ADP_BANK(MAXGPIO); i++) - ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i, - pdata->debounce_dis_mask >> (i * 8)); + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_A), + pdata->debounce_dis_mask & kpad->var->row_mask); - ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG, + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_B), + (pdata->debounce_dis_mask >> kpad->var->col_shift) + & kpad->var->col_mask); + + if (!kpad->is_adp5585) + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_C), + (pdata->debounce_dis_mask >> 16) & 0xFF); + + ret |= adp5589_write(client, reg(ADP5589_POLL_PTIME_CFG), pdata->scan_cycle_time & PTIME_MASK); - ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT | - LOGIC1_INT | OVRFLOW_INT | LOCK_INT | + ret |= adp5589_write(client, ADP5589_5_INT_STATUS, + (kpad->is_adp5585 ? 0 : LOGIC2_INT) | + LOGIC1_INT | OVRFLOW_INT | + (kpad->is_adp5585 ? 0 : LOCK_INT) | GPI_INT | EVENT_INT); /* Status is W1C */ - ret |= adp5589_write(client, ADP5589_GENERAL_CFG, + ret |= adp5589_write(client, reg(ADP5589_GENERAL_CFG), INT_CFG | OSC_EN | CORE_CLK(3)); - ret |= adp5589_write(client, ADP5589_INT_EN, + ret |= adp5589_write(client, reg(ADP5589_INT_EN), OVRFLOW_IEN | GPI_IEN | EVENT_IEN); if (ret < 0) { @@ -497,30 +822,33 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad) { - int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A); - int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B); - int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C); int gpi_stat_tmp, pin_loc; int i; + int gpi_stat1 = adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_A)); + int gpi_stat2 = adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_B)); + int gpi_stat3 = !kpad->is_adp5585 ? + adp5589_read(kpad->client, ADP5589_GPI_STATUS_C) : 0; for (i = 0; i < kpad->gpimapsize; i++) { unsigned short pin = kpad->gpimap[i].pin; - if (pin <= ADP5589_GPI_PIN_ROW_END) { + if (pin <= kpad->var->gpi_pin_row_end) { gpi_stat_tmp = gpi_stat1; - pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE; - } else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) { + pin_loc = pin - kpad->var->gpi_pin_row_base; + } else if ((pin - kpad->var->gpi_pin_col_base) < 8) { gpi_stat_tmp = gpi_stat2; - pin_loc = pin - ADP5589_GPI_PIN_COL_BASE; + pin_loc = pin - kpad->var->gpi_pin_col_base; } else { gpi_stat_tmp = gpi_stat3; - pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8; + pin_loc = pin - kpad->var->gpi_pin_col_base - 8; } if (gpi_stat_tmp < 0) { dev_err(&kpad->client->dev, - "Can't read GPIO_DAT_STAT switch" - " %d default to OFF\n", pin); + "Can't read GPIO_DAT_STAT switch %d, default to OFF\n", + pin); gpi_stat_tmp = 0; } @@ -536,7 +864,8 @@ static int __devinit adp5589_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adp5589_kpad *kpad; - const struct adp5589_kpad_platform_data *pdata; + const struct adp5589_kpad_platform_data *pdata = + client->dev.platform_data; struct input_dev *input; unsigned int revid; int ret, i; @@ -548,56 +877,79 @@ static int __devinit adp5589_probe(struct i2c_client *client, return -EIO; } - pdata = client->dev.platform_data; if (!pdata) { dev_err(&client->dev, "no platform data?\n"); return -EINVAL; } - if (!((pdata->keypad_en_mask & 0xFF) && - (pdata->keypad_en_mask >> 8)) || !pdata->keymap) { + kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); + if (!kpad) + return -ENOMEM; + + switch (id->driver_data) { + case ADP5585_02: + kpad->adp5585_support_row5 = true; + case ADP5585_01: + kpad->is_adp5585 = true; + kpad->var = &const_adp5585; + break; + case ADP5589: + kpad->var = &const_adp5589; + break; + } + + if (!((pdata->keypad_en_mask & kpad->var->row_mask) && + (pdata->keypad_en_mask >> kpad->var->col_shift)) || + !pdata->keymap) { dev_err(&client->dev, "no rows, cols or keymap from pdata\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if (pdata->keymapsize != ADP5589_KEYMAPSIZE) { + if (pdata->keymapsize != kpad->var->keymapsize) { dev_err(&client->dev, "invalid keymapsize\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } if (!pdata->gpimap && pdata->gpimapsize) { dev_err(&client->dev, "invalid gpimap from pdata\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) { + if (pdata->gpimapsize > kpad->var->gpimapsize_max) { dev_err(&client->dev, "invalid gpimapsize\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } for (i = 0; i < pdata->gpimapsize; i++) { unsigned short pin = pdata->gpimap[i].pin; - if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) { + if (pin < kpad->var->gpi_pin_base || + pin > kpad->var->gpi_pin_end) { dev_err(&client->dev, "invalid gpi pin data\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) & + if ((1 << (pin - kpad->var->gpi_pin_row_base)) & pdata->keypad_en_mask) { dev_err(&client->dev, "invalid gpi row/col data\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } } if (!client->irq) { dev_err(&client->dev, "no IRQ?\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); input = input_allocate_device(); - if (!kpad || !input) { + if (!input) { error = -ENOMEM; goto err_free_mem; } @@ -605,13 +957,13 @@ static int __devinit adp5589_probe(struct i2c_client *client, kpad->client = client; kpad->input = input; - ret = adp5589_read(client, ADP5589_ID); + ret = adp5589_read(client, ADP5589_5_ID); if (ret < 0) { error = ret; - goto err_free_mem; + goto err_free_input; } - revid = (u8) ret & ADP5589_DEVICE_ID_MASK; + revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK; input->name = client->name; input->phys = "adp5589-keys/input0"; @@ -652,7 +1004,7 @@ static int __devinit adp5589_probe(struct i2c_client *client, error = input_register_device(input); if (error) { dev_err(&client->dev, "unable to register input device\n"); - goto err_free_mem; + goto err_free_input; } error = request_threaded_irq(client->irq, NULL, adp5589_irq, @@ -685,8 +1037,9 @@ err_free_irq: err_unreg_dev: input_unregister_device(input); input = NULL; -err_free_mem: +err_free_input: input_free_device(input); +err_free_mem: kfree(kpad); return error; @@ -696,7 +1049,7 @@ static int __devexit adp5589_remove(struct i2c_client *client) { struct adp5589_kpad *kpad = i2c_get_clientdata(client); - adp5589_write(client, ADP5589_GENERAL_CFG, 0); + adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); free_irq(client->irq, kpad); input_unregister_device(kpad->input); adp5589_gpio_remove(kpad); @@ -736,7 +1089,9 @@ static int adp5589_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume); static const struct i2c_device_id adp5589_id[] = { - {"adp5589-keys", 0}, + {"adp5589-keys", ADP5589}, + {"adp5585-keys", ADP5585_01}, + {"adp5585-02-keys", ADP5585_02}, /* Adds ROW5 to ADP5585 */ {} }; @@ -767,4 +1122,4 @@ module_exit(adp5589_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("ADP5589 Keypad driver"); +MODULE_DESCRIPTION("ADP5589/ADP5585 Keypad driver"); diff --git a/include/linux/input/adp5589.h b/include/linux/input/adp5589.h index ef792ecfaab..1a05eee15e6 100644 --- a/include/linux/input/adp5589.h +++ b/include/linux/input/adp5589.h @@ -1,5 +1,5 @@ /* - * Analog Devices ADP5589 I/O Expander and QWERTY Keypad Controller + * Analog Devices ADP5589/ADP5585 I/O Expander and QWERTY Keypad Controller * * Copyright 2010-2011 Analog Devices Inc. * @@ -9,89 +9,9 @@ #ifndef _ADP5589_H #define _ADP5589_H -#define ADP5589_ID 0x00 -#define ADP5589_INT_STATUS 0x01 -#define ADP5589_STATUS 0x02 -#define ADP5589_FIFO_1 0x03 -#define ADP5589_FIFO_2 0x04 -#define ADP5589_FIFO_3 0x05 -#define ADP5589_FIFO_4 0x06 -#define ADP5589_FIFO_5 0x07 -#define ADP5589_FIFO_6 0x08 -#define ADP5589_FIFO_7 0x09 -#define ADP5589_FIFO_8 0x0A -#define ADP5589_FIFO_9 0x0B -#define ADP5589_FIFO_10 0x0C -#define ADP5589_FIFO_11 0x0D -#define ADP5589_FIFO_12 0x0E -#define ADP5589_FIFO_13 0x0F -#define ADP5589_FIFO_14 0x10 -#define ADP5589_FIFO_15 0x11 -#define ADP5589_FIFO_16 0x12 -#define ADP5589_GPI_INT_STAT_A 0x13 -#define ADP5589_GPI_INT_STAT_B 0x14 -#define ADP5589_GPI_INT_STAT_C 0x15 -#define ADP5589_GPI_STATUS_A 0x16 -#define ADP5589_GPI_STATUS_B 0x17 -#define ADP5589_GPI_STATUS_C 0x18 -#define ADP5589_RPULL_CONFIG_A 0x19 -#define ADP5589_RPULL_CONFIG_B 0x1A -#define ADP5589_RPULL_CONFIG_C 0x1B -#define ADP5589_RPULL_CONFIG_D 0x1C -#define ADP5589_RPULL_CONFIG_E 0x1D -#define ADP5589_GPI_INT_LEVEL_A 0x1E -#define ADP5589_GPI_INT_LEVEL_B 0x1F -#define ADP5589_GPI_INT_LEVEL_C 0x20 -#define ADP5589_GPI_EVENT_EN_A 0x21 -#define ADP5589_GPI_EVENT_EN_B 0x22 -#define ADP5589_GPI_EVENT_EN_C 0x23 -#define ADP5589_GPI_INTERRUPT_EN_A 0x24 -#define ADP5589_GPI_INTERRUPT_EN_B 0x25 -#define ADP5589_GPI_INTERRUPT_EN_C 0x26 -#define ADP5589_DEBOUNCE_DIS_A 0x27 -#define ADP5589_DEBOUNCE_DIS_B 0x28 -#define ADP5589_DEBOUNCE_DIS_C 0x29 -#define ADP5589_GPO_DATA_OUT_A 0x2A -#define ADP5589_GPO_DATA_OUT_B 0x2B -#define ADP5589_GPO_DATA_OUT_C 0x2C -#define ADP5589_GPO_OUT_MODE_A 0x2D -#define ADP5589_GPO_OUT_MODE_B 0x2E -#define ADP5589_GPO_OUT_MODE_C 0x2F -#define ADP5589_GPIO_DIRECTION_A 0x30 -#define ADP5589_GPIO_DIRECTION_B 0x31 -#define ADP5589_GPIO_DIRECTION_C 0x32 -#define ADP5589_UNLOCK1 0x33 -#define ADP5589_UNLOCK2 0x34 -#define ADP5589_EXT_LOCK_EVENT 0x35 -#define ADP5589_UNLOCK_TIMERS 0x36 -#define ADP5589_LOCK_CFG 0x37 -#define ADP5589_RESET1_EVENT_A 0x38 -#define ADP5589_RESET1_EVENT_B 0x39 -#define ADP5589_RESET1_EVENT_C 0x3A -#define ADP5589_RESET2_EVENT_A 0x3B -#define ADP5589_RESET2_EVENT_B 0x3C -#define ADP5589_RESET_CFG 0x3D -#define ADP5589_PWM_OFFT_LOW 0x3E -#define ADP5589_PWM_OFFT_HIGH 0x3F -#define ADP5589_PWM_ONT_LOW 0x40 -#define ADP5589_PWM_ONT_HIGH 0x41 -#define ADP5589_PWM_CFG 0x42 -#define ADP5589_CLOCK_DIV_CFG 0x43 -#define ADP5589_LOGIC_1_CFG 0x44 -#define ADP5589_LOGIC_2_CFG 0x45 -#define ADP5589_LOGIC_FF_CFG 0x46 -#define ADP5589_LOGIC_INT_EVENT_EN 0x47 -#define ADP5589_POLL_PTIME_CFG 0x48 -#define ADP5589_PIN_CONFIG_A 0x49 -#define ADP5589_PIN_CONFIG_B 0x4A -#define ADP5589_PIN_CONFIG_C 0x4B -#define ADP5589_PIN_CONFIG_D 0x4C -#define ADP5589_GENERAL_CFG 0x4D -#define ADP5589_INT_EN 0x4E - -#define ADP5589_DEVICE_ID_MASK 0xF - -/* Put one of these structures in i2c_board_info platform_data */ +/* + * ADP5589 specific GPI and Keymap defines + */ #define ADP5589_KEYMAPSIZE 88 @@ -127,6 +47,35 @@ #define ADP5589_GPIMAPSIZE_MAX (ADP5589_GPI_PIN_END - ADP5589_GPI_PIN_BASE + 1) +/* + * ADP5585 specific GPI and Keymap defines + */ + +#define ADP5585_KEYMAPSIZE 30 + +#define ADP5585_GPI_PIN_ROW0 37 +#define ADP5585_GPI_PIN_ROW1 38 +#define ADP5585_GPI_PIN_ROW2 39 +#define ADP5585_GPI_PIN_ROW3 40 +#define ADP5585_GPI_PIN_ROW4 41 +#define ADP5585_GPI_PIN_ROW5 42 +#define ADP5585_GPI_PIN_COL0 43 +#define ADP5585_GPI_PIN_COL1 44 +#define ADP5585_GPI_PIN_COL2 45 +#define ADP5585_GPI_PIN_COL3 46 +#define ADP5585_GPI_PIN_COL4 47 +#define GPI_LOGIC 48 + +#define ADP5585_GPI_PIN_ROW_BASE ADP5585_GPI_PIN_ROW0 +#define ADP5585_GPI_PIN_ROW_END ADP5585_GPI_PIN_ROW5 +#define ADP5585_GPI_PIN_COL_BASE ADP5585_GPI_PIN_COL0 +#define ADP5585_GPI_PIN_COL_END ADP5585_GPI_PIN_COL4 + +#define ADP5585_GPI_PIN_BASE ADP5585_GPI_PIN_ROW_BASE +#define ADP5585_GPI_PIN_END ADP5585_GPI_PIN_COL_END + +#define ADP5585_GPIMAPSIZE_MAX (ADP5585_GPI_PIN_END - ADP5585_GPI_PIN_BASE + 1) + struct adp5589_gpi_map { unsigned short pin; unsigned short sw_evt; @@ -159,7 +108,7 @@ struct adp5589_gpi_map { #define RESET2_POL_HIGH (1 << 7) #define RESET2_POL_LOW (0 << 7) -/* Mask Bits: +/* ADP5589 Mask Bits: * C C C C C C C C C C C | R R R R R R R R * 1 9 8 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 * 0 @@ -168,18 +117,44 @@ struct adp5589_gpi_map { * 8 7 6 5 4 3 2 1 0 9 8 | 7 6 5 4 3 2 1 0 */ -#define ADP_ROW(x) (1 << (x)) -#define ADP_COL(x) (1 << (x + 8)) +#define ADP_ROW(x) (1 << (x)) +#define ADP_COL(x) (1 << (x + 8)) +#define ADP5589_ROW_MASK 0xFF +#define ADP5589_COL_MASK 0xFF +#define ADP5589_COL_SHIFT 8 +#define ADP5589_MAX_ROW_NUM 7 +#define ADP5589_MAX_COL_NUM 10 + +/* ADP5585 Mask Bits: + * C C C C C | R R R R R R + * 4 3 2 1 0 | 5 4 3 2 1 0 + * + * ---- BIT -- ----------- + * 1 0 0 0 0 | 0 0 0 0 0 0 + * 0 9 8 7 6 | 5 4 3 2 1 0 + */ + +#define ADP5585_ROW_MASK 0x3F +#define ADP5585_COL_MASK 0x1F +#define ADP5585_ROW_SHIFT 0 +#define ADP5585_COL_SHIFT 6 +#define ADP5585_MAX_ROW_NUM 5 +#define ADP5585_MAX_COL_NUM 4 + +#define ADP5585_ROW(x) (1 << ((x) & ADP5585_ROW_MASK)) +#define ADP5585_COL(x) (1 << (((x) & ADP5585_COL_MASK) + ADP5585_COL_SHIFT)) + +/* Put one of these structures in i2c_board_info platform_data */ struct adp5589_kpad_platform_data { unsigned keypad_en_mask; /* Keypad (Rows/Columns) enable mask */ const unsigned short *keymap; /* Pointer to keymap */ unsigned short keymapsize; /* Keymap size */ bool repeat; /* Enable key repeat */ - bool en_keylock; /* Enable key lock feature */ - unsigned char unlock_key1; /* Unlock Key 1 */ - unsigned char unlock_key2; /* Unlock Key 2 */ - unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable */ + bool en_keylock; /* Enable key lock feature (ADP5589 only)*/ + unsigned char unlock_key1; /* Unlock Key 1 (ADP5589 only) */ + unsigned char unlock_key2; /* Unlock Key 2 (ADP5589 only) */ + unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable (ADP5589 only) */ unsigned char scan_cycle_time; /* Time between consecutive scan cycles */ unsigned char reset_cfg; /* Reset config */ unsigned short reset1_key_1; /* Reset Key 1 */ -- cgit v1.2.3-70-g09d2