summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/ec.c10
-rw-r--r--drivers/acpi/processor_driver.c1
-rw-r--r--drivers/acpi/video_detect.c2
-rw-r--r--drivers/atm/eni.c1
-rw-r--r--drivers/atm/firestream.c1
-rw-r--r--drivers/atm/horizon.c1
-rw-r--r--drivers/atm/idt77105.c1
-rw-r--r--drivers/atm/iphase.c1
-rw-r--r--drivers/atm/suni.c1
-rw-r--r--drivers/atm/zatm.c1
-rw-r--r--drivers/base/dma-buf.c165
-rw-r--r--drivers/block/floppy.c1
-rw-r--r--drivers/block/hd.c1
-rw-r--r--drivers/block/nbd.c296
-rw-r--r--drivers/block/rbd.c730
-rw-r--r--drivers/block/rbd_types.h4
-rw-r--r--drivers/block/sunvdc.c5
-rw-r--r--drivers/block/xd.c1
-rw-r--r--drivers/bluetooth/bt3c_cs.c1
-rw-r--r--drivers/bluetooth/btuart_cs.c1
-rw-r--r--drivers/bluetooth/dtl1_cs.c1
-rw-r--r--drivers/char/apm-emulation.c1
-rw-r--r--drivers/char/ds1302.c1
-rw-r--r--drivers/char/efirtc.c1
-rw-r--r--drivers/char/genrtc.c1
-rw-r--r--drivers/char/hpet.c1
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c1
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c4
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c243
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c73
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c25
-rw-r--r--drivers/char/lp.c6
-rw-r--r--drivers/char/mbcs.c1
-rw-r--r--drivers/char/mspec.c1
-rw-r--r--drivers/char/mwave/3780i.c1
-rw-r--r--drivers/char/nvram.c1
-rw-r--r--drivers/char/nwflash.c1
-rw-r--r--drivers/char/pcmcia/synclink_cs.c1
-rw-r--r--drivers/char/rtc.c1
-rw-r--r--drivers/char/sonypi.c1
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c1
-rw-r--r--drivers/clk/Kconfig37
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/clk-divider.c200
-rw-r--r--drivers/clk/clk-fixed-rate.c82
-rw-r--r--drivers/clk/clk-gate.c150
-rw-r--r--drivers/clk/clk-mux.c116
-rw-r--r--drivers/clk/clk.c1461
-rw-r--r--drivers/clocksource/Kconfig1
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c13
-rw-r--r--drivers/cpufreq/omap-cpufreq.c1
-rw-r--r--drivers/cpufreq/powernow-k7.c1
-rw-r--r--drivers/dma/Kconfig3
-rw-r--r--drivers/dma/amba-pl08x.c46
-rw-r--r--drivers/dma/at_hdmac.c111
-rw-r--r--drivers/dma/at_hdmac_regs.h34
-rw-r--r--drivers/dma/coh901318.c41
-rw-r--r--drivers/dma/dmaengine.c8
-rw-r--r--drivers/dma/dmaengine.h89
-rw-r--r--drivers/dma/dw_dmac.c228
-rw-r--r--drivers/dma/dw_dmac_regs.h16
-rw-r--r--drivers/dma/ep93xx_dma.c31
-rw-r--r--drivers/dma/fsldma.c28
-rw-r--r--drivers/dma/fsldma.h1
-rw-r--r--drivers/dma/imx-dma.c950
-rw-r--r--drivers/dma/imx-sdma.c187
-rw-r--r--drivers/dma/intel_mid_dma.c46
-rw-r--r--drivers/dma/intel_mid_dma_regs.h2
-rw-r--r--drivers/dma/ioat/dma.c21
-rw-r--r--drivers/dma/ioat/dma.h23
-rw-r--r--drivers/dma/ioat/dma_v2.c13
-rw-r--r--drivers/dma/ioat/dma_v3.c12
-rw-r--r--drivers/dma/iop-adma.c52
-rw-r--r--drivers/dma/ipu/ipu_idmac.c25
-rw-r--r--drivers/dma/mpc512x_dma.c25
-rw-r--r--drivers/dma/mv_xor.c34
-rw-r--r--drivers/dma/mv_xor.h3
-rw-r--r--drivers/dma/mxs-dma.c28
-rw-r--r--drivers/dma/pch_dma.c37
-rw-r--r--drivers/dma/pl330.c2149
-rw-r--r--drivers/dma/ppc4xx/adma.c49
-rw-r--r--drivers/dma/ppc4xx/adma.h2
-rw-r--r--drivers/dma/shdma.c33
-rw-r--r--drivers/dma/shdma.h1
-rw-r--r--drivers/dma/sirf-dma.c27
-rw-r--r--drivers/dma/ste_dma40.c41
-rw-r--r--drivers/dma/timb_dma.c37
-rw-r--r--drivers/dma/txx9dmac.c43
-rw-r--r--drivers/dma/txx9dmac.h1
-rw-r--r--drivers/edac/Kconfig2
-rw-r--r--drivers/edac/edac_mc.c6
-rw-r--r--drivers/edac/i5100_edac.c13
-rw-r--r--drivers/edac/i5400_edac.c54
-rw-r--r--drivers/edac/ppc4xx_edac.c4
-rw-r--r--drivers/edac/sb_edac.c52
-rw-r--r--drivers/firewire/core-cdev.c1
-rw-r--r--drivers/firewire/core-device.c1
-rw-r--r--drivers/firewire/core-topology.c1
-rw-r--r--drivers/firewire/ohci.c1
-rw-r--r--drivers/firewire/sbp2.c1
-rw-r--r--drivers/gpio/Kconfig14
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-davinci.c26
-rw-r--r--drivers/gpio/gpio-ep93xx.c8
-rw-r--r--drivers/gpio/gpio-lpc32xx.c19
-rw-r--r--drivers/gpio/gpio-mc9s08dz60.c161
-rw-r--r--drivers/gpio/gpio-omap.c291
-rw-r--r--drivers/gpio/gpio-pl061.c7
-rw-r--r--drivers/gpio/gpio-pxa.c2
-rw-r--r--drivers/gpio/gpio-samsung.c487
-rw-r--r--drivers/gpio/gpio-sodaville.c302
-rw-r--r--drivers/gpio/gpio-stmpe.c43
-rw-r--r--drivers/gpio/gpio-tegra.c4
-rw-r--r--drivers/gpio/gpio-tps65910.c20
-rw-r--r--drivers/gpio/gpio-twl4030.c111
-rw-r--r--drivers/gpio/gpiolib.c98
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_output.c5
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c7
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c8
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c3
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c4
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c98
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h8
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c391
-rw-r--r--drivers/gpu/drm/radeon/r600d.h8
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c12
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/cayman1
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/evergreen1
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r6001
-rw-r--r--drivers/hwmon/fschmd.c4
-rw-r--r--drivers/hwmon/mc13783-adc.c2
-rw-r--r--drivers/hwmon/w83793.c4
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c5
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c3
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c3
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.h3
-rw-r--r--drivers/i2c/busses/Kconfig1
-rw-r--r--drivers/i2c/busses/i2c-acorn.c1
-rw-r--r--drivers/i2c/busses/i2c-gpio.c98
-rw-r--r--drivers/i2c/busses/i2c-i801.c27
-rw-r--r--drivers/i2c/busses/i2c-isch.c10
-rw-r--r--drivers/i2c/i2c-boardinfo.c3
-rw-r--r--drivers/i2c/i2c-core.c3
-rw-r--r--drivers/i2c/i2c-core.h3
-rw-r--r--drivers/i2c/i2c-dev.c3
-rw-r--r--drivers/i2c/i2c-smbus.c3
-rw-r--r--drivers/i2c/muxes/pca9541.c13
-rw-r--r--drivers/i2c/muxes/pca954x.c13
-rw-r--r--drivers/ide/ide-cs.c1
-rw-r--r--drivers/ide/qd65xx.c1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c1
-rw-r--r--drivers/input/input-compat.c4
-rw-r--r--drivers/input/input-compat.h2
-rw-r--r--drivers/input/joydev.c1
-rw-r--r--drivers/input/joystick/amijoy.c4
-rw-r--r--drivers/input/keyboard/gpio_keys.c259
-rw-r--r--drivers/input/keyboard/tegra-kbc.c1
-rw-r--r--drivers/input/misc/88pm860x_onkey.c26
-rw-r--r--drivers/input/mouse/amimouse.c1
-rw-r--r--drivers/input/mouse/atarimouse.c1
-rw-r--r--drivers/input/mouse/sentelic.c294
-rw-r--r--drivers/input/mouse/sentelic.h35
-rw-r--r--drivers/input/serio/ams_delta_serio.c2
-rw-r--r--drivers/input/serio/hp_sdc.c1
-rw-r--r--drivers/input/serio/maceps2.c1
-rw-r--r--drivers/input/serio/rpckbd.c1
-rw-r--r--drivers/input/serio/sa1111ps2.c1
-rw-r--r--drivers/input/tablet/Kconfig1
-rw-r--r--drivers/input/tablet/wacom.h9
-rw-r--r--drivers/input/tablet/wacom_sys.c231
-rw-r--r--drivers/input/tablet/wacom_wac.c49
-rw-r--r--drivers/input/tablet/wacom_wac.h6
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c11
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c1
-rw-r--r--drivers/isdn/hisax/avma1_cs.c1
-rw-r--r--drivers/isdn/hisax/elsa_cs.c1
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c1
-rw-r--r--drivers/isdn/hisax/teles_cs.c1
-rw-r--r--drivers/isdn/i4l/isdn_bsdcomp.c1
-rw-r--r--drivers/isdn/pcbit/layer2.c1
-rw-r--r--drivers/leds/leds-88pm860x.c23
-rw-r--r--drivers/macintosh/macio-adb.c1
-rw-r--r--drivers/macintosh/therm_adt746x.c1
-rw-r--r--drivers/macintosh/therm_pm72.c1
-rw-r--r--drivers/macintosh/therm_windtunnel.c1
-rw-r--r--drivers/macintosh/via-cuda.c1
-rw-r--r--drivers/macintosh/via-macii.c1
-rw-r--r--drivers/macintosh/via-pmu.c1
-rw-r--r--drivers/macintosh/via-pmu68k.c1
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c1
-rw-r--r--drivers/macintosh/windfarm_pm121.c1
-rw-r--r--drivers/macintosh/windfarm_pm81.c1
-rw-r--r--drivers/macintosh/windfarm_pm91.c1
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c1
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c1
-rw-r--r--drivers/md/Kconfig28
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/dm-bufio.c108
-rw-r--r--drivers/md/dm-bufio.h8
-rw-r--r--drivers/md/dm-crypt.c46
-rw-r--r--drivers/md/dm-delay.c9
-rw-r--r--drivers/md/dm-exception-store.c2
-rw-r--r--drivers/md/dm-flakey.c3
-rw-r--r--drivers/md/dm-ioctl.c5
-rw-r--r--drivers/md/dm-linear.c3
-rw-r--r--drivers/md/dm-log.c3
-rw-r--r--drivers/md/dm-mpath.c52
-rw-r--r--drivers/md/dm-queue-length.c3
-rw-r--r--drivers/md/dm-raid.c53
-rw-r--r--drivers/md/dm-raid1.c12
-rw-r--r--drivers/md/dm-round-robin.c3
-rw-r--r--drivers/md/dm-service-time.c5
-rw-r--r--drivers/md/dm-stripe.c3
-rw-r--r--drivers/md/dm-table.c9
-rw-r--r--drivers/md/dm-thin-metadata.c5
-rw-r--r--drivers/md/dm-thin-metadata.h13
-rw-r--r--drivers/md/dm-thin.c680
-rw-r--r--drivers/md/dm-verity.c913
-rw-r--r--drivers/md/dm.c1
-rw-r--r--drivers/md/persistent-data/dm-btree-internal.h7
-rw-r--r--drivers/md/persistent-data/dm-btree-remove.c202
-rw-r--r--drivers/md/persistent-data/dm-btree.c27
-rw-r--r--drivers/md/persistent-data/dm-space-map-common.c3
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c1
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110.c1
-rw-r--r--drivers/media/media-devnode.c1
-rw-r--r--drivers/media/video/davinci/vpbe_osd.c1
-rw-r--r--drivers/media/video/davinci/vpbe_venc.c1
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h1
-rw-r--r--drivers/media/video/mx3_camera.c2
-rw-r--r--drivers/media/video/timblogiw.c2
-rw-r--r--drivers/media/video/v4l2-common.c1
-rw-r--r--drivers/media/video/v4l2-dev.c1
-rw-r--r--drivers/message/i2o/i2o_scsi.c1
-rw-r--r--drivers/mfd/88pm860x-core.c110
-rw-r--r--drivers/mfd/88pm860x-i2c.c25
-rw-r--r--drivers/mfd/Kconfig54
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/ab8500-core.c375
-rw-r--r--drivers/mfd/ab8500-i2c.c30
-rw-r--r--drivers/mfd/anatop-mfd.c137
-rw-r--r--drivers/mfd/asic3.c6
-rw-r--r--drivers/mfd/da9052-core.c3
-rw-r--r--drivers/mfd/da9052-i2c.c11
-rw-r--r--drivers/mfd/da9052-spi.c9
-rw-r--r--drivers/mfd/db8500-prcmu.c1220
-rw-r--r--drivers/mfd/dbx500-prcmu-regs.h130
-rw-r--r--drivers/mfd/mc13xxx-core.c11
-rw-r--r--drivers/mfd/mcp-core.c2
-rw-r--r--drivers/mfd/mcp-sa11x0.c1
-rw-r--r--drivers/mfd/mfd-core.c2
-rw-r--r--drivers/mfd/omap-usb-host.c7
-rw-r--r--drivers/mfd/pcf50633-core.c8
-rw-r--r--drivers/mfd/pcf50633-gpio.c27
-rw-r--r--drivers/mfd/pcf50633-irq.c7
-rw-r--r--drivers/mfd/rc5t583-irq.c408
-rw-r--r--drivers/mfd/rc5t583.c386
-rw-r--r--drivers/mfd/s5m-core.c58
-rw-r--r--drivers/mfd/s5m-irq.c14
-rw-r--r--drivers/mfd/sm501.c10
-rw-r--r--drivers/mfd/stmpe.c134
-rw-r--r--drivers/mfd/tps65090.c387
-rw-r--r--drivers/mfd/tps65217.c242
-rw-r--r--drivers/mfd/tps65910-irq.c11
-rw-r--r--drivers/mfd/tps65910.c123
-rw-r--r--drivers/mfd/twl-core.c153
-rw-r--r--drivers/mfd/twl-core.h4
-rw-r--r--drivers/mfd/twl4030-irq.c107
-rw-r--r--drivers/mfd/twl6030-irq.c86
-rw-r--r--drivers/mfd/wm831x-spi.c2
-rw-r--r--drivers/mfd/wm8400-core.c3
-rw-r--r--drivers/mfd/wm8994-core.c2
-rw-r--r--drivers/mfd/wm8994-regmap.c20
-rw-r--r--drivers/misc/sgi-gru/gru_instructions.h1
-rw-r--r--drivers/misc/sgi-xp/xp.h1
-rw-r--r--drivers/mmc/card/block.c22
-rw-r--r--drivers/mmc/core/cd-gpio.c13
-rw-r--r--drivers/mmc/core/core.c252
-rw-r--r--drivers/mmc/core/host.c1
-rw-r--r--drivers/mmc/core/host.h1
-rw-r--r--drivers/mmc/core/mmc.c55
-rw-r--r--drivers/mmc/core/mmc_ops.c12
-rw-r--r--drivers/mmc/host/Kconfig25
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/atmel-mci.c23
-rw-r--r--drivers/mmc/host/davinci_mmc.c66
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c158
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c134
-rw-r--r--drivers/mmc/host/dw_mmc.c280
-rw-r--r--drivers/mmc/host/dw_mmc.h7
-rw-r--r--drivers/mmc/host/mmci.c4
-rw-r--r--drivers/mmc/host/mxcmmc.c5
-rw-r--r--drivers/mmc/host/mxs-mmc.c2
-rw-r--r--drivers/mmc/host/omap_hsmmc.c293
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c37
-rw-r--r--drivers/mmc/host/sdhci-pci.c47
-rw-r--r--drivers/mmc/host/sdhci-spear.c9
-rw-r--r--drivers/mmc/host/sdhci-tegra.c100
-rw-r--r--drivers/mmc/host/sdhci.c38
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mmc/host/sh_mmcif.c6
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c29
-rw-r--r--drivers/mmc/host/tmio_mmc.h9
-rw-r--r--drivers/mmc/host/tmio_mmc_dma.c4
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c108
-rw-r--r--drivers/mtd/devices/pmc551.c1
-rw-r--r--drivers/mtd/devices/slram.c1
-rw-r--r--drivers/mtd/maps/pcmciamtd.c1
-rw-r--r--drivers/mtd/nand/atmel_nand.c136
-rw-r--r--drivers/mtd/nand/bcm_umi_nand.c1
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c25
-rw-r--r--drivers/net/appletalk/cops.c1
-rw-r--r--drivers/net/appletalk/ltpc.c1
-rw-r--r--drivers/net/arcnet/com20020_cs.c1
-rw-r--r--drivers/net/bonding/bond_main.c1
-rw-r--r--drivers/net/can/slcan.c1
-rw-r--r--drivers/net/cris/eth_v10.c1
-rw-r--r--drivers/net/ethernet/3com/3c574_cs.c1
-rw-r--r--drivers/net/ethernet/3com/3c589_cs.c1
-rw-r--r--drivers/net/ethernet/8390/3c503.c1
-rw-r--r--drivers/net/ethernet/8390/ac3200.c1
-rw-r--r--drivers/net/ethernet/8390/apne.c1
-rw-r--r--drivers/net/ethernet/8390/ax88796.c1
-rw-r--r--drivers/net/ethernet/8390/axnet_cs.c1
-rw-r--r--drivers/net/ethernet/8390/e2100.c1
-rw-r--r--drivers/net/ethernet/8390/es3210.c1
-rw-r--r--drivers/net/ethernet/8390/etherh.c2
-rw-r--r--drivers/net/ethernet/8390/hp-plus.c1
-rw-r--r--drivers/net/ethernet/8390/hp.c1
-rw-r--r--drivers/net/ethernet/8390/lib8390.c1
-rw-r--r--drivers/net/ethernet/8390/lne390.c1
-rw-r--r--drivers/net/ethernet/8390/mac8390.c1
-rw-r--r--drivers/net/ethernet/8390/ne-h8300.c1
-rw-r--r--drivers/net/ethernet/8390/ne.c1
-rw-r--r--drivers/net/ethernet/8390/ne2.c1
-rw-r--r--drivers/net/ethernet/8390/ne2k-pci.c1
-rw-r--r--drivers/net/ethernet/8390/ne3210.c1
-rw-r--r--drivers/net/ethernet/8390/pcnet_cs.c1
-rw-r--r--drivers/net/ethernet/8390/smc-mca.c1
-rw-r--r--drivers/net/ethernet/8390/smc-ultra.c1
-rw-r--r--drivers/net/ethernet/8390/smc-ultra32.c1
-rw-r--r--drivers/net/ethernet/8390/stnic.c1
-rw-r--r--drivers/net/ethernet/8390/wd.c1
-rw-r--r--drivers/net/ethernet/8390/zorro8390.c1
-rw-r--r--drivers/net/ethernet/alteon/acenic.c1
-rw-r--r--drivers/net/ethernet/amd/7990.c1
-rw-r--r--drivers/net/ethernet/amd/am79c961a.c1
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c1
-rw-r--r--drivers/net/ethernet/amd/declance.c1
-rw-r--r--drivers/net/ethernet/amd/hplance.c1
-rw-r--r--drivers/net/ethernet/amd/mvme147.c1
-rw-r--r--drivers/net/ethernet/amd/nmclan_cs.c1
-rw-r--r--drivers/net/ethernet/amd/sunlance.c1
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c1
-rw-r--r--drivers/net/ethernet/cirrus/cs89x0.c1
-rw-r--r--drivers/net/ethernet/cirrus/mac89x0.c1
-rw-r--r--drivers/net/ethernet/dlink/de600.c1
-rw-r--r--drivers/net/ethernet/dlink/de620.c1
-rw-r--r--drivers/net/ethernet/fujitsu/at1700.c1
-rw-r--r--drivers/net/ethernet/fujitsu/eth16i.c1
-rw-r--r--drivers/net/ethernet/fujitsu/fmvj18x_cs.c1
-rw-r--r--drivers/net/ethernet/i825xx/3c507.c1
-rw-r--r--drivers/net/ethernet/i825xx/3c527.c1
-rw-r--r--drivers/net/ethernet/i825xx/eepro.c1
-rw-r--r--drivers/net/ethernet/i825xx/eexpress.c1
-rw-r--r--drivers/net/ethernet/i825xx/ether1.c1
-rw-r--r--drivers/net/ethernet/i825xx/znet.c1
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c7
-rw-r--r--drivers/net/ethernet/korina.c1
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c1
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c1
-rw-r--r--drivers/net/ethernet/micrel/ks8842.c4
-rw-r--r--drivers/net/ethernet/natsemi/jazzsonic.c1
-rw-r--r--drivers/net/ethernet/natsemi/macsonic.c1
-rw-r--r--drivers/net/ethernet/natsemi/ns83820.c1
-rw-r--r--drivers/net/ethernet/neterion/s2io.c1
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c1
-rw-r--r--drivers/net/ethernet/realtek/atp.c1
-rw-r--r--drivers/net/ethernet/realtek/r8169.c1
-rw-r--r--drivers/net/ethernet/seeq/ether3.c1
-rw-r--r--drivers/net/ethernet/seeq/seeq8005.c1
-rw-r--r--drivers/net/ethernet/smsc/smc91c92_cs.c1
-rw-r--r--drivers/net/ethernet/sun/cassini.c1
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c1
-rw-r--r--drivers/net/ethernet/sun/sungem.c1
-rw-r--r--drivers/net/ethernet/sun/sunhme.c1
-rw-r--r--drivers/net/ethernet/sun/sunqe.c1
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c5
-rw-r--r--drivers/net/ethernet/tundra/tsi108_eth.c1
-rw-r--r--drivers/net/ethernet/xircom/xirc2ps_cs.c1
-rw-r--r--drivers/net/hamradio/6pack.c1
-rw-r--r--drivers/net/hamradio/baycom_par.c1
-rw-r--r--drivers/net/hamradio/bpqether.c1
-rw-r--r--drivers/net/hamradio/mkiss.c1
-rw-r--r--drivers/net/hamradio/scc.c1
-rw-r--r--drivers/net/hamradio/yam.c1
-rw-r--r--drivers/net/hippi/rrunner.c1
-rw-r--r--drivers/net/irda/donauboe.c1
-rw-r--r--drivers/net/loopback.c1
-rw-r--r--drivers/net/plip/plip.c1
-rw-r--r--drivers/net/slip/slhc.c1
-rw-r--r--drivers/net/slip/slip.c1
-rw-r--r--drivers/net/tokenring/3c359.c1
-rw-r--r--drivers/net/tokenring/abyss.c1
-rw-r--r--drivers/net/tokenring/ibmtr_cs.c1
-rw-r--r--drivers/net/tokenring/lanstreamer.c1
-rw-r--r--drivers/net/tokenring/madgemc.c1
-rw-r--r--drivers/net/tokenring/olympic.c1
-rw-r--r--drivers/net/tokenring/proteon.c1
-rw-r--r--drivers/net/tokenring/skisa.c1
-rw-r--r--drivers/net/tokenring/smctr.c1
-rw-r--r--drivers/net/tokenring/tms380tr.c1
-rw-r--r--drivers/net/tokenring/tmspci.c1
-rw-r--r--drivers/net/tun.c1
-rw-r--r--drivers/net/wan/dlci.c1
-rw-r--r--drivers/net/wan/dscc4.c1
-rw-r--r--drivers/net/wan/hd64570.c1
-rw-r--r--drivers/net/wan/hd64572.c1
-rw-r--r--drivers/net/wan/lapbether.c1
-rw-r--r--drivers/net/wan/sdla.c1
-rw-r--r--drivers/net/wan/x25_asy.c1
-rw-r--r--drivers/net/wireless/airo.c1
-rw-r--r--drivers/net/wireless/airo_cs.c1
-rw-r--r--drivers/net/wireless/atmel.c1
-rw-r--r--drivers/net/wireless/atmel_cs.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c1
-rw-r--r--drivers/net/wireless/ray_cs.c1
-rw-r--r--drivers/net/wireless/wl3501_cs.c1
-rw-r--r--drivers/nubus/nubus.c1
-rw-r--r--drivers/of/Kconfig4
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/gpio.c11
-rw-r--r--drivers/of/of_mtd.c85
-rw-r--r--drivers/parisc/dino.c1
-rw-r--r--drivers/parisc/iosapic.c1
-rw-r--r--drivers/parisc/lba_pci.c1
-rw-r--r--drivers/pcmcia/at91_cf.c52
-rw-r--r--drivers/pcmcia/bcm63xx_pcmcia.c2
-rw-r--r--drivers/pcmcia/bfin_cf_pcmcia.c13
-rw-r--r--drivers/pcmcia/cs.c1
-rw-r--r--drivers/pcmcia/db1xxx_ss.c17
-rw-r--r--drivers/pcmcia/electra_cf.c12
-rw-r--r--drivers/pcmcia/i82092.c12
-rw-r--r--drivers/pcmcia/i82365.c1
-rw-r--r--drivers/pcmcia/m32r_cfc.c1
-rw-r--r--drivers/pcmcia/m32r_pcc.c1
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c14
-rw-r--r--drivers/pcmcia/pd6729.c10
-rw-r--r--drivers/pcmcia/pxa2xx_base.c1
-rw-r--r--drivers/pcmcia/pxa2xx_viper.c13
-rw-r--r--drivers/pcmcia/sa11xx_base.c1
-rw-r--r--drivers/pcmcia/soc_common.c1
-rw-r--r--drivers/pcmcia/socket_sysfs.c1
-rw-r--r--drivers/pcmcia/tcic.c1
-rw-r--r--drivers/pcmcia/vrc4173_cardu.c7
-rw-r--r--drivers/pcmcia/xxs1500_ss.c14
-rw-r--r--drivers/pcmcia/yenta_socket.c2
-rw-r--r--drivers/platform/x86/Kconfig71
-rw-r--r--drivers/platform/x86/Makefile6
-rw-r--r--drivers/platform/x86/acer-wmi.c152
-rw-r--r--drivers/platform/x86/acerhdf.c19
-rw-r--r--drivers/platform/x86/amilo-rfkill.c5
-rw-r--r--drivers/platform/x86/apple-gmux.c244
-rw-r--r--drivers/platform/x86/asus-laptop.c273
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c12
-rw-r--r--drivers/platform/x86/asus-wmi.c68
-rw-r--r--drivers/platform/x86/asus-wmi.h14
-rw-r--r--drivers/platform/x86/asus_acpi.c1513
-rw-r--r--drivers/platform/x86/compal-laptop.c14
-rw-r--r--drivers/platform/x86/dell-laptop.c34
-rw-r--r--drivers/platform/x86/eeepc-laptop.c13
-rw-r--r--drivers/platform/x86/eeepc-wmi.c108
-rw-r--r--drivers/platform/x86/hdaps.c4
-rw-r--r--drivers/platform/x86/intel_mid_powerbtn.c12
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c14
-rw-r--r--drivers/platform/x86/intel_oaktrail.c2
-rw-r--r--drivers/platform/x86/samsung-laptop.c1749
-rw-r--r--drivers/platform/x86/sony-laptop.c15
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c2
-rw-r--r--drivers/platform/x86/toshiba_acpi.c254
-rw-r--r--drivers/platform/x86/xo1-rfkill.c13
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c1
-rw-r--r--drivers/pnp/pnpbios/core.c1
-rw-r--r--drivers/rtc/interface.c5
-rw-r--r--drivers/rtc/rtc-88pm860x.c27
-rw-r--r--drivers/rtc/rtc-mpc5121.c2
-rw-r--r--drivers/rtc/rtc-mv.c9
-rw-r--r--drivers/rtc/rtc-sa1100.c1
-rw-r--r--drivers/s390/char/sclp_cmd.c1
-rw-r--r--drivers/s390/cio/crw.c1
-rw-r--r--drivers/s390/crypto/ap_bus.c2
-rw-r--r--drivers/sbus/char/flash.c1
-rw-r--r--drivers/sbus/char/openprom.c1
-rw-r--r--drivers/sbus/char/uctrl.c1
-rw-r--r--drivers/scsi/53c700.c1
-rw-r--r--drivers/scsi/BusLogic.c1
-rw-r--r--drivers/scsi/advansys.c1
-rw-r--r--drivers/scsi/aha152x.c1
-rw-r--r--drivers/scsi/aha1542.c1
-rw-r--r--drivers/scsi/aha1740.c1
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c1
-rw-r--r--drivers/scsi/arm/acornscsi.c1
-rw-r--r--drivers/scsi/arm/cumana_1.c1
-rw-r--r--drivers/scsi/arm/oak.c1
-rw-r--r--drivers/scsi/atp870u.c1
-rw-r--r--drivers/scsi/dtc.c1
-rw-r--r--drivers/scsi/fd_mcs.c1
-rw-r--r--drivers/scsi/fdomain.c1
-rw-r--r--drivers/scsi/g_NCR5380.c1
-rw-r--r--drivers/scsi/gdth.c1
-rw-r--r--drivers/scsi/ibmmca.c1
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c7
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c7
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c5
-rw-r--r--drivers/scsi/in2000.c1
-rw-r--r--drivers/scsi/mac53c94.c1
-rw-r--r--drivers/scsi/mac_scsi.c1
-rw-r--r--drivers/scsi/mesh.c1
-rw-r--r--drivers/scsi/ncr53c8xx.c1
-rw-r--r--drivers/scsi/nsp32.c1
-rw-r--r--drivers/scsi/osst.c1
-rw-r--r--drivers/scsi/pas16.c1
-rw-r--r--drivers/scsi/qla1280.c1
-rw-r--r--drivers/scsi/qlogicpti.c1
-rw-r--r--drivers/scsi/st.c1
-rw-r--r--drivers/scsi/sun3_scsi.c1
-rw-r--r--drivers/scsi/sun3_scsi_vme.c1
-rw-r--r--drivers/scsi/sym53c416.c1
-rw-r--r--drivers/scsi/t128.c1
-rw-r--r--drivers/scsi/u14-34f.c1
-rw-r--r--drivers/scsi/ultrastor.c1
-rw-r--r--drivers/scsi/wd7000.c1
-rw-r--r--drivers/sh/intc/balancing.c2
-rw-r--r--drivers/sh/intc/core.c2
-rw-r--r--drivers/sh/intc/handle.c2
-rw-r--r--drivers/sh/intc/virq.c2
-rw-r--r--drivers/spi/spi-dw-mid.c7
-rw-r--r--drivers/spi/spi-ep93xx.c4
-rw-r--r--drivers/spi/spi-omap-uwire.c1
-rw-r--r--drivers/spi/spi-orion.c5
-rw-r--r--drivers/spi/spi-pl022.c6
-rw-r--r--drivers/spi/spi-topcliff-pch.c4
-rw-r--r--drivers/staging/android/binder.c13
-rw-r--r--drivers/staging/comedi/drivers.c1
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c1
-rw-r--r--drivers/staging/comedi/drivers/mite.c1
-rw-r--r--drivers/staging/crystalhd/bc_dts_defs.h2
-rw-r--r--drivers/staging/crystalhd/crystalhd.h1
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.h1
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.h1
-rw-r--r--drivers/staging/et131x/et131x.c1
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c1
-rw-r--r--drivers/staging/media/go7007/go7007-driver.c1
-rw-r--r--drivers/staging/media/go7007/go7007-i2c.c1
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c1
-rw-r--r--drivers/staging/media/go7007/snd-go7007.c1
-rw-r--r--drivers/staging/media/lirc/lirc_serial.c1
-rw-r--r--drivers/staging/media/lirc/lirc_sir.c1
-rw-r--r--drivers/staging/mei/wd.c1
-rw-r--r--drivers/staging/panel/panel.c1
-rw-r--r--drivers/staging/sbe-2t3e3/io.c1
-rw-r--r--drivers/staging/ste_rmi4/Makefile2
-rw-r--r--drivers/staging/telephony/phonedev.c1
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/host_os.h1
-rw-r--r--drivers/staging/wlags49_h2/wl_cs.c1
-rw-r--r--drivers/staging/wlags49_h2/wl_main.c3
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c3
-rw-r--r--drivers/staging/wlags49_h2/wl_pci.c1
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c3
-rw-r--r--drivers/tty/amiserial.c1
-rw-r--r--drivers/tty/hvc/hvc_vio.c7
-rw-r--r--drivers/tty/hvc/hvcs.c5
-rw-r--r--drivers/tty/isicom.c1
-rw-r--r--drivers/tty/moxa.c1
-rw-r--r--drivers/tty/mxser.c1
-rw-r--r--drivers/tty/n_hdlc.c1
-rw-r--r--drivers/tty/n_tty.c1
-rw-r--r--drivers/tty/pty.c1
-rw-r--r--drivers/tty/serial/21285.c1
-rw-r--r--drivers/tty/serial/68328serial.c1
-rw-r--r--drivers/tty/serial/8250/serial_cs.c1
-rw-r--r--drivers/tty/serial/amba-pl011.c9
-rw-r--r--drivers/tty/serial/crisv10.c2
-rw-r--r--drivers/tty/serial/dz.c1
-rw-r--r--drivers/tty/serial/icom.c1
-rw-r--r--drivers/tty/serial/msm_serial_hs.c1
-rw-r--r--drivers/tty/serial/pch_uart.c4
-rw-r--r--drivers/tty/serial/sh-sci.c4
-rw-r--r--drivers/tty/serial/sunhv.c1
-rw-r--r--drivers/tty/serial/sunsab.c1
-rw-r--r--drivers/tty/serial/sunsu.c1
-rw-r--r--drivers/tty/serial/sunzilog.c1
-rw-r--r--drivers/tty/serial/zs.c1
-rw-r--r--drivers/tty/synclink.c1
-rw-r--r--drivers/tty/synclink_gt.c1
-rw-r--r--drivers/tty/synclinkmp.c1
-rw-r--r--drivers/tty/tty_io.c1
-rw-r--r--drivers/tty/tty_ioctl.c1
-rw-r--r--drivers/tty/vt/vt.c1
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/amd5536udc.c1
-rw-r--r--drivers/usb/gadget/at91_udc.c41
-rw-r--r--drivers/usb/gadget/dummy_hcd.c1
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c1
-rw-r--r--drivers/usb/gadget/goku_udc.c1
-rw-r--r--drivers/usb/gadget/langwell_udc.c1
-rw-r--r--drivers/usb/gadget/mv_udc_core.c1
-rw-r--r--drivers/usb/gadget/net2272.c1
-rw-r--r--drivers/usb/gadget/net2280.c1
-rw-r--r--drivers/usb/gadget/omap_udc.c1
-rw-r--r--drivers/usb/gadget/printer.c1
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c1
-rw-r--r--drivers/usb/gadget/rndis.c1
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c1
-rw-r--r--drivers/usb/host/ehci-atmel.c24
-rw-r--r--drivers/usb/host/ehci-hcd.c1
-rw-r--r--drivers/usb/host/isp116x-hcd.c1
-rw-r--r--drivers/usb/host/isp1362-hcd.c1
-rw-r--r--drivers/usb/host/ohci-at91.c101
-rw-r--r--drivers/usb/host/ohci-hcd.c1
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c1
-rw-r--r--drivers/usb/host/sl811-hcd.c1
-rw-r--r--drivers/usb/host/u132-hcd.c1
-rw-r--r--drivers/usb/host/uhci-hcd.c1
-rw-r--r--drivers/usb/musb/ux500_dma.c4
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c5
-rw-r--r--drivers/video/amifb.c1
-rw-r--r--drivers/video/backlight/88pm860x_bl.c49
-rw-r--r--drivers/video/backlight/apple_bl.c23
-rw-r--r--drivers/video/backlight/tosa_lcd.c2
-rw-r--r--drivers/video/bt431.h1
-rw-r--r--drivers/video/bt455.h1
-rw-r--r--drivers/video/console/fbcon.c1
-rw-r--r--drivers/video/console/newport_con.c1
-rw-r--r--drivers/video/cyber2000fb.c1
-rw-r--r--drivers/video/dnfb.c1
-rw-r--r--drivers/video/mx3fb.c4
-rw-r--r--drivers/video/neofb.c1
-rw-r--r--drivers/video/omap2/vrfb.c1
-rw-r--r--drivers/video/pmag-ba-fb.c1
-rw-r--r--drivers/video/pmagb-b-fb.c1
-rw-r--r--drivers/video/q40fb.c1
-rw-r--r--drivers/video/savage/savagefb_driver.c1
-rw-r--r--drivers/virtio/config.c1
-rw-r--r--drivers/watchdog/Kconfig8
-rw-r--r--drivers/watchdog/acquirewdt.c28
-rw-r--r--drivers/watchdog/advantechwdt.c35
-rw-r--r--drivers/watchdog/alim1535_wdt.c25
-rw-r--r--drivers/watchdog/alim7101_wdt.c56
-rw-r--r--drivers/watchdog/ar7_wdt.c38
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c4
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c14
-rw-r--r--drivers/watchdog/at91sam9_wdt.c12
-rw-r--r--drivers/watchdog/ath79_wdt.c9
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c18
-rw-r--r--drivers/watchdog/bcm63xx_wdt.c11
-rw-r--r--drivers/watchdog/bfin_wdt.c31
-rw-r--r--drivers/watchdog/booke_wdt.c15
-rw-r--r--drivers/watchdog/coh901327_wdt.c206
-rw-r--r--drivers/watchdog/cpu5wdt.c19
-rw-r--r--drivers/watchdog/cpwd.c20
-rw-r--r--drivers/watchdog/dw_wdt.c7
-rw-r--r--drivers/watchdog/ep93xx_wdt.c220
-rw-r--r--drivers/watchdog/eurotechwdt.c33
-rw-r--r--drivers/watchdog/f71808e_wdt.c40
-rw-r--r--drivers/watchdog/gef_wdt.c15
-rw-r--r--drivers/watchdog/geodewdt.c9
-rw-r--r--drivers/watchdog/hpwdt.c31
-rw-r--r--drivers/watchdog/i6300esb.c39
-rw-r--r--drivers/watchdog/iTCO_vendor_support.c7
-rw-r--r--drivers/watchdog/iTCO_wdt.c59
-rw-r--r--drivers/watchdog/ib700wdt.c27
-rw-r--r--drivers/watchdog/ibmasr.c18
-rw-r--r--drivers/watchdog/imx2_wdt.c14
-rw-r--r--drivers/watchdog/indydog.c24
-rw-r--r--drivers/watchdog/intel_scu_watchdog.c71
-rw-r--r--drivers/watchdog/intel_scu_watchdog.h1
-rw-r--r--drivers/watchdog/iop_wdt.c15
-rw-r--r--drivers/watchdog/it8712f_wdt.c39
-rw-r--r--drivers/watchdog/it87_wdt.c47
-rw-r--r--drivers/watchdog/ixp2000_wdt.c11
-rw-r--r--drivers/watchdog/ixp4xx_wdt.c15
-rw-r--r--drivers/watchdog/jz4740_wdt.c265
-rw-r--r--drivers/watchdog/ks8695_wdt.c10
-rw-r--r--drivers/watchdog/lantiq_wdt.c8
-rw-r--r--drivers/watchdog/m54xx_wdt.c14
-rw-r--r--drivers/watchdog/machzwd.c38
-rw-r--r--drivers/watchdog/max63xx_wdt.c194
-rw-r--r--drivers/watchdog/mixcomwd.c29
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c17
-rw-r--r--drivers/watchdog/mpcore_wdt.c111
-rw-r--r--drivers/watchdog/mv64x60_wdt.c15
-rw-r--r--drivers/watchdog/nuc900_wdt.c4
-rw-r--r--drivers/watchdog/nv_tco.c46
-rw-r--r--drivers/watchdog/octeon-wdt-main.c16
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c41
-rw-r--r--drivers/watchdog/omap_wdt.c4
-rw-r--r--drivers/watchdog/orion_wdt.c39
-rw-r--r--drivers/watchdog/pc87413_wdt.c58
-rw-r--r--drivers/watchdog/pcwd.c127
-rw-r--r--drivers/watchdog/pcwd_pci.c113
-rw-r--r--drivers/watchdog/pcwd_usb.c78
-rw-r--r--drivers/watchdog/pika_wdt.c23
-rw-r--r--drivers/watchdog/pnx4008_wdt.c263
-rw-r--r--drivers/watchdog/pnx833x_wdt.c30
-rw-r--r--drivers/watchdog/rc32434_wdt.c33
-rw-r--r--drivers/watchdog/riowd.c10
-rw-r--r--drivers/watchdog/s3c2410_wdt.c31
-rw-r--r--drivers/watchdog/sa1100_wdt.c11
-rw-r--r--drivers/watchdog/sb_wdog.c28
-rw-r--r--drivers/watchdog/sbc60xxwdt.c42
-rw-r--r--drivers/watchdog/sbc7240_wdt.c45
-rw-r--r--drivers/watchdog/sbc8360.c25
-rw-r--r--drivers/watchdog/sbc_epx_c3.c23
-rw-r--r--drivers/watchdog/sbc_fitpc2_wdt.c14
-rw-r--r--drivers/watchdog/sc1200wdt.c34
-rw-r--r--drivers/watchdog/sc520_wdt.c40
-rw-r--r--drivers/watchdog/sch311x_wdt.c17
-rw-r--r--drivers/watchdog/scx200_wdt.c25
-rw-r--r--drivers/watchdog/shwdt.c19
-rw-r--r--drivers/watchdog/smsc37b787_wdt.c43
-rw-r--r--drivers/watchdog/softdog.c211
-rw-r--r--drivers/watchdog/sp5100_tco.c35
-rw-r--r--drivers/watchdog/sp805_wdt.c111
-rw-r--r--drivers/watchdog/stmp3xxx_wdt.c8
-rw-r--r--drivers/watchdog/ts72xx_wdt.c4
-rw-r--r--drivers/watchdog/twl4030_wdt.c4
-rw-r--r--drivers/watchdog/txx9wdt.c184
-rw-r--r--drivers/watchdog/via_wdt.c13
-rw-r--r--drivers/watchdog/w83627hf_wdt.c39
-rw-r--r--drivers/watchdog/w83697hf_wdt.c44
-rw-r--r--drivers/watchdog/w83697ug_wdt.c39
-rw-r--r--drivers/watchdog/w83877f_wdt.c41
-rw-r--r--drivers/watchdog/w83977f_wdt.c39
-rw-r--r--drivers/watchdog/wafer5823wdt.c34
-rw-r--r--drivers/watchdog/watchdog_core.c4
-rw-r--r--drivers/watchdog/watchdog_dev.c16
-rw-r--r--drivers/watchdog/wdrtas.c71
-rw-r--r--drivers/watchdog/wdt.c56
-rw-r--r--drivers/watchdog/wdt285.c13
-rw-r--r--drivers/watchdog/wdt977.c41
-rw-r--r--drivers/watchdog/wdt_pci.c71
-rw-r--r--drivers/watchdog/wm831x_wdt.c6
-rw-r--r--drivers/watchdog/wm8350_wdt.c223
-rw-r--r--drivers/watchdog/xen_wdt.c42
752 files changed, 20257 insertions, 10017 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b19a18dd994f..e37615f310d7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -445,6 +445,16 @@ int ec_transaction(u8 command,
EXPORT_SYMBOL(ec_transaction);
+/* Get the handle to the EC device */
+acpi_handle ec_get_handle(void)
+{
+ if (!first_ec)
+ return NULL;
+ return first_ec->handle;
+}
+
+EXPORT_SYMBOL(ec_get_handle);
+
void acpi_ec_block_transactions(void)
{
struct acpi_ec *ec = first_ec;
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 2801b418d7bb..d4d9cb7e016a 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -46,7 +46,6 @@
#include <linux/slab.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/cpu.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index f3f0fe7e255a..45d8097ef4cf 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -23,7 +23,7 @@
* Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
* are available, video.ko should be used to handle the device.
*
- * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
+ * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
* sony_acpi,... can take care about backlight brightness.
*
* If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 6ff612d099c3..2059ee460b0c 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -19,7 +19,6 @@
#include <linux/atm_eni.h>
#include <linux/bitops.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <linux/atomic.h>
#include <asm/uaccess.h>
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 5072f8ac16fd..86fed1b91695 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -49,7 +49,6 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/string.h>
#include <asm/io.h>
#include <linux/atomic.h>
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index b81210330aca..75fd691cd43e 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -43,7 +43,6 @@
#include <linux/wait.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <linux/atomic.h>
#include <asm/uaccess.h>
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 487a54739854..45d506363aba 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -16,7 +16,6 @@
#include <linux/atm_idt77105.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <asm/param.h>
#include <asm/uaccess.h>
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 9e373ba20308..d4386019af5d 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -56,7 +56,6 @@
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <linux/atomic.h>
#include <asm/uaccess.h>
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index 90f1ccca9e52..02159345566c 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -22,7 +22,6 @@
#include <linux/capability.h>
#include <linux/atm_suni.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <asm/param.h>
#include <asm/uaccess.h>
#include <linux/atomic.h>
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index d889f56e8d8c..abe4e20b0766 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -24,7 +24,6 @@
#include <linux/wait.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/string.h>
#include <asm/io.h>
#include <linux/atomic.h>
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index e38ad243b4bb..07cbbc6fddb4 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -71,7 +71,7 @@ static inline int is_dma_buf_file(struct file *file)
* ops, or error in allocating struct dma_buf, will return negative error.
*
*/
-struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
+struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
size_t size, int flags)
{
struct dma_buf *dmabuf;
@@ -80,7 +80,9 @@ struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
if (WARN_ON(!priv || !ops
|| !ops->map_dma_buf
|| !ops->unmap_dma_buf
- || !ops->release)) {
+ || !ops->release
+ || !ops->kmap_atomic
+ || !ops->kmap)) {
return ERR_PTR(-EINVAL);
}
@@ -107,17 +109,18 @@ EXPORT_SYMBOL_GPL(dma_buf_export);
/**
* dma_buf_fd - returns a file descriptor for the given dma_buf
* @dmabuf: [in] pointer to dma_buf for which fd is required.
+ * @flags: [in] flags to give to fd
*
* On success, returns an associated 'fd'. Else, returns error.
*/
-int dma_buf_fd(struct dma_buf *dmabuf)
+int dma_buf_fd(struct dma_buf *dmabuf, int flags)
{
int error, fd;
if (!dmabuf || !dmabuf->file)
return -EINVAL;
- error = get_unused_fd();
+ error = get_unused_fd_flags(flags);
if (error < 0)
return error;
fd = error;
@@ -185,17 +188,18 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct dma_buf_attachment *attach;
int ret;
- if (WARN_ON(!dmabuf || !dev || !dmabuf->ops))
+ if (WARN_ON(!dmabuf || !dev))
return ERR_PTR(-EINVAL);
attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL);
if (attach == NULL)
- goto err_alloc;
-
- mutex_lock(&dmabuf->lock);
+ return ERR_PTR(-ENOMEM);
attach->dev = dev;
attach->dmabuf = dmabuf;
+
+ mutex_lock(&dmabuf->lock);
+
if (dmabuf->ops->attach) {
ret = dmabuf->ops->attach(dmabuf, dev, attach);
if (ret)
@@ -206,8 +210,6 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
mutex_unlock(&dmabuf->lock);
return attach;
-err_alloc:
- return ERR_PTR(-ENOMEM);
err_attach:
kfree(attach);
mutex_unlock(&dmabuf->lock);
@@ -224,7 +226,7 @@ EXPORT_SYMBOL_GPL(dma_buf_attach);
*/
void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
{
- if (WARN_ON(!dmabuf || !attach || !dmabuf->ops))
+ if (WARN_ON(!dmabuf || !attach))
return;
mutex_lock(&dmabuf->lock);
@@ -255,13 +257,10 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
might_sleep();
- if (WARN_ON(!attach || !attach->dmabuf || !attach->dmabuf->ops))
+ if (WARN_ON(!attach || !attach->dmabuf))
return ERR_PTR(-EINVAL);
- mutex_lock(&attach->dmabuf->lock);
- if (attach->dmabuf->ops->map_dma_buf)
- sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
- mutex_unlock(&attach->dmabuf->lock);
+ sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
return sg_table;
}
@@ -273,19 +272,137 @@ EXPORT_SYMBOL_GPL(dma_buf_map_attachment);
* dma_buf_ops.
* @attach: [in] attachment to unmap buffer from
* @sg_table: [in] scatterlist info of the buffer to unmap
+ * @direction: [in] direction of DMA transfer
*
*/
void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
- struct sg_table *sg_table)
+ struct sg_table *sg_table,
+ enum dma_data_direction direction)
{
- if (WARN_ON(!attach || !attach->dmabuf || !sg_table
- || !attach->dmabuf->ops))
+ if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
return;
- mutex_lock(&attach->dmabuf->lock);
- if (attach->dmabuf->ops->unmap_dma_buf)
- attach->dmabuf->ops->unmap_dma_buf(attach, sg_table);
- mutex_unlock(&attach->dmabuf->lock);
-
+ attach->dmabuf->ops->unmap_dma_buf(attach, sg_table,
+ direction);
}
EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
+
+
+/**
+ * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the
+ * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
+ * preparations. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf: [in] buffer to prepare cpu access for.
+ * @start: [in] start of range for cpu access.
+ * @len: [in] length of range for cpu access.
+ * @direction: [in] length of range for cpu access.
+ *
+ * Can return negative error values, returns 0 on success.
+ */
+int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+ enum dma_data_direction direction)
+{
+ int ret = 0;
+
+ if (WARN_ON(!dmabuf))
+ return -EINVAL;
+
+ if (dmabuf->ops->begin_cpu_access)
+ ret = dmabuf->ops->begin_cpu_access(dmabuf, start, len, direction);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
+
+/**
+ * dma_buf_end_cpu_access - Must be called after accessing a dma_buf from the
+ * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
+ * actions. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf: [in] buffer to complete cpu access for.
+ * @start: [in] start of range for cpu access.
+ * @len: [in] length of range for cpu access.
+ * @direction: [in] length of range for cpu access.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+ enum dma_data_direction direction)
+{
+ WARN_ON(!dmabuf);
+
+ if (dmabuf->ops->end_cpu_access)
+ dmabuf->ops->end_cpu_access(dmabuf, start, len, direction);
+}
+EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
+
+/**
+ * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address
+ * space. The same restrictions as for kmap_atomic and friends apply.
+ * @dma_buf: [in] buffer to map page from.
+ * @page_num: [in] page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
+{
+ WARN_ON(!dmabuf);
+
+ return dmabuf->ops->kmap_atomic(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic);
+
+/**
+ * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic.
+ * @dma_buf: [in] buffer to unmap page from.
+ * @page_num: [in] page in PAGE_SIZE units to unmap.
+ * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap_atomic.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num,
+ void *vaddr)
+{
+ WARN_ON(!dmabuf);
+
+ if (dmabuf->ops->kunmap_atomic)
+ dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic);
+
+/**
+ * dma_buf_kmap - Map a page of the buffer object into kernel address space. The
+ * same restrictions as for kmap and friends apply.
+ * @dma_buf: [in] buffer to map page from.
+ * @page_num: [in] page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
+{
+ WARN_ON(!dmabuf);
+
+ return dmabuf->ops->kmap(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap);
+
+/**
+ * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
+ * @dma_buf: [in] buffer to unmap page from.
+ * @page_num: [in] page in PAGE_SIZE units to unmap.
+ * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num,
+ void *vaddr)
+{
+ WARN_ON(!dmabuf);
+
+ if (dmabuf->ops->kunmap)
+ dmabuf->ops->kunmap(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 744f078f4dd8..76a08236430a 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -202,7 +202,6 @@ static int slow_floppy;
#include <asm/dma.h>
#include <asm/irq.h>
-#include <asm/system.h>
static int FLOPPY_IRQ = 6;
static int FLOPPY_DMA = 2;
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index b52c9ca146fc..bf397bf108b7 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -44,7 +44,6 @@
#define HD_IRQ 14
#define REALLY_SLOW_IO
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c3f0ee16594d..061427a75d37 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -34,12 +34,11 @@
#include <linux/kthread.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/types.h>
#include <linux/nbd.h>
-#define LO_MAGIC 0x68797548
+#define NBD_MAGIC 0x68797548
#ifdef NDEBUG
#define dprintk(flags, fmt...)
@@ -116,7 +115,7 @@ static void nbd_end_request(struct request *req)
spin_unlock_irqrestore(q->queue_lock, flags);
}
-static void sock_shutdown(struct nbd_device *lo, int lock)
+static void sock_shutdown(struct nbd_device *nbd, int lock)
{
/* Forcibly shutdown the socket causing all listeners
* to error
@@ -125,14 +124,14 @@ static void sock_shutdown(struct nbd_device *lo, int lock)
* there should be a more generic interface rather than
* calling socket ops directly here */
if (lock)
- mutex_lock(&lo->tx_lock);
- if (lo->sock) {
- dev_warn(disk_to_dev(lo->disk), "shutting down socket\n");
- kernel_sock_shutdown(lo->sock, SHUT_RDWR);
- lo->sock = NULL;
+ mutex_lock(&nbd->tx_lock);
+ if (nbd->sock) {
+ dev_warn(disk_to_dev(nbd->disk), "shutting down socket\n");
+ kernel_sock_shutdown(nbd->sock, SHUT_RDWR);
+ nbd->sock = NULL;
}
if (lock)
- mutex_unlock(&lo->tx_lock);
+ mutex_unlock(&nbd->tx_lock);
}
static void nbd_xmit_timeout(unsigned long arg)
@@ -147,17 +146,17 @@ static void nbd_xmit_timeout(unsigned long arg)
/*
* Send or receive packet.
*/
-static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
+static int sock_xmit(struct nbd_device *nbd, int send, void *buf, int size,
int msg_flags)
{
- struct socket *sock = lo->sock;
+ struct socket *sock = nbd->sock;
int result;
struct msghdr msg;
struct kvec iov;
sigset_t blocked, oldset;
if (unlikely(!sock)) {
- dev_err(disk_to_dev(lo->disk),
+ dev_err(disk_to_dev(nbd->disk),
"Attempted %s on closed socket in sock_xmit\n",
(send ? "send" : "recv"));
return -EINVAL;
@@ -181,15 +180,15 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
if (send) {
struct timer_list ti;
- if (lo->xmit_timeout) {
+ if (nbd->xmit_timeout) {
init_timer(&ti);
ti.function = nbd_xmit_timeout;
ti.data = (unsigned long)current;
- ti.expires = jiffies + lo->xmit_timeout;
+ ti.expires = jiffies + nbd->xmit_timeout;
add_timer(&ti);
}
result = kernel_sendmsg(sock, &msg, &iov, 1, size);
- if (lo->xmit_timeout)
+ if (nbd->xmit_timeout)
del_timer_sync(&ti);
} else
result = kernel_recvmsg(sock, &msg, &iov, 1, size,
@@ -201,7 +200,7 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
task_pid_nr(current), current->comm,
dequeue_signal_lock(current, &current->blocked, &info));
result = -EINTR;
- sock_shutdown(lo, !send);
+ sock_shutdown(nbd, !send);
break;
}
@@ -219,18 +218,19 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
return result;
}
-static inline int sock_send_bvec(struct nbd_device *lo, struct bio_vec *bvec,
+static inline int sock_send_bvec(struct nbd_device *nbd, struct bio_vec *bvec,
int flags)
{
int result;
void *kaddr = kmap(bvec->bv_page);
- result = sock_xmit(lo, 1, kaddr + bvec->bv_offset, bvec->bv_len, flags);
+ result = sock_xmit(nbd, 1, kaddr + bvec->bv_offset,
+ bvec->bv_len, flags);
kunmap(bvec->bv_page);
return result;
}
/* always call with the tx_lock held */
-static int nbd_send_req(struct nbd_device *lo, struct request *req)
+static int nbd_send_req(struct nbd_device *nbd, struct request *req)
{
int result, flags;
struct nbd_request request;
@@ -243,14 +243,14 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
memcpy(request.handle, &req, sizeof(req));
dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n",
- lo->disk->disk_name, req,
+ nbd->disk->disk_name, req,
nbdcmd_to_ascii(nbd_cmd(req)),
(unsigned long long)blk_rq_pos(req) << 9,
blk_rq_bytes(req));
- result = sock_xmit(lo, 1, &request, sizeof(request),
+ result = sock_xmit(nbd, 1, &request, sizeof(request),
(nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
if (result <= 0) {
- dev_err(disk_to_dev(lo->disk),
+ dev_err(disk_to_dev(nbd->disk),
"Send control failed (result %d)\n", result);
goto error_out;
}
@@ -267,10 +267,10 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
if (!rq_iter_last(req, iter))
flags = MSG_MORE;
dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
- lo->disk->disk_name, req, bvec->bv_len);
- result = sock_send_bvec(lo, bvec, flags);
+ nbd->disk->disk_name, req, bvec->bv_len);
+ result = sock_send_bvec(nbd, bvec, flags);
if (result <= 0) {
- dev_err(disk_to_dev(lo->disk),
+ dev_err(disk_to_dev(nbd->disk),
"Send data failed (result %d)\n",
result);
goto error_out;
@@ -283,25 +283,25 @@ error_out:
return -EIO;
}
-static struct request *nbd_find_request(struct nbd_device *lo,
+static struct request *nbd_find_request(struct nbd_device *nbd,
struct request *xreq)
{
struct request *req, *tmp;
int err;
- err = wait_event_interruptible(lo->active_wq, lo->active_req != xreq);
+ err = wait_event_interruptible(nbd->active_wq, nbd->active_req != xreq);
if (unlikely(err))
goto out;
- spin_lock(&lo->queue_lock);
- list_for_each_entry_safe(req, tmp, &lo->queue_head, queuelist) {
+ spin_lock(&nbd->queue_lock);
+ list_for_each_entry_safe(req, tmp, &nbd->queue_head, queuelist) {
if (req != xreq)
continue;
list_del_init(&req->queuelist);
- spin_unlock(&lo->queue_lock);
+ spin_unlock(&nbd->queue_lock);
return req;
}
- spin_unlock(&lo->queue_lock);
+ spin_unlock(&nbd->queue_lock);
err = -ENOENT;
@@ -309,78 +309,78 @@ out:
return ERR_PTR(err);
}
-static inline int sock_recv_bvec(struct nbd_device *lo, struct bio_vec *bvec)
+static inline int sock_recv_bvec(struct nbd_device *nbd, struct bio_vec *bvec)
{
int result;
void *kaddr = kmap(bvec->bv_page);
- result = sock_xmit(lo, 0, kaddr + bvec->bv_offset, bvec->bv_len,
+ result = sock_xmit(nbd, 0, kaddr + bvec->bv_offset, bvec->bv_len,
MSG_WAITALL);
kunmap(bvec->bv_page);
return result;
}
/* NULL returned = something went wrong, inform userspace */
-static struct request *nbd_read_stat(struct nbd_device *lo)
+static struct request *nbd_read_stat(struct nbd_device *nbd)
{
int result;
struct nbd_reply reply;
struct request *req;
reply.magic = 0;
- result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL);
+ result = sock_xmit(nbd, 0, &reply, sizeof(reply), MSG_WAITALL);
if (result <= 0) {
- dev_err(disk_to_dev(lo->disk),
+ dev_err(disk_to_dev(nbd->disk),
"Receive control failed (result %d)\n", result);
goto harderror;
}
if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
- dev_err(disk_to_dev(lo->disk), "Wrong magic (0x%lx)\n",
+ dev_err(disk_to_dev(nbd->disk), "Wrong magic (0x%lx)\n",
(unsigned long)ntohl(reply.magic));
result = -EPROTO;
goto harderror;
}
- req = nbd_find_request(lo, *(struct request **)reply.handle);
+ req = nbd_find_request(nbd, *(struct request **)reply.handle);
if (IS_ERR(req)) {
result = PTR_ERR(req);
if (result != -ENOENT)
goto harderror;
- dev_err(disk_to_dev(lo->disk), "Unexpected reply (%p)\n",
+ dev_err(disk_to_dev(nbd->disk), "Unexpected reply (%p)\n",
reply.handle);
result = -EBADR;
goto harderror;
}
if (ntohl(reply.error)) {
- dev_err(disk_to_dev(lo->disk), "Other side returned error (%d)\n",
+ dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n",
ntohl(reply.error));
req->errors++;
return req;
}
dprintk(DBG_RX, "%s: request %p: got reply\n",
- lo->disk->disk_name, req);
+ nbd->disk->disk_name, req);
if (nbd_cmd(req) == NBD_CMD_READ) {
struct req_iterator iter;
struct bio_vec *bvec;
rq_for_each_segment(bvec, req, iter) {
- result = sock_recv_bvec(lo, bvec);
+ result = sock_recv_bvec(nbd, bvec);
if (result <= 0) {
- dev_err(disk_to_dev(lo->disk), "Receive data failed (result %d)\n",
+ dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
result);
req->errors++;
return req;
}
dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
- lo->disk->disk_name, req, bvec->bv_len);
+ nbd->disk->disk_name, req, bvec->bv_len);
}
}
return req;
harderror:
- lo->harderror = result;
+ nbd->harderror = result;
return NULL;
}
@@ -398,48 +398,48 @@ static struct device_attribute pid_attr = {
.show = pid_show,
};
-static int nbd_do_it(struct nbd_device *lo)
+static int nbd_do_it(struct nbd_device *nbd)
{
struct request *req;
int ret;
- BUG_ON(lo->magic != LO_MAGIC);
+ BUG_ON(nbd->magic != NBD_MAGIC);
- lo->pid = task_pid_nr(current);
- ret = device_create_file(disk_to_dev(lo->disk), &pid_attr);
+ nbd->pid = task_pid_nr(current);
+ ret = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
if (ret) {
- dev_err(disk_to_dev(lo->disk), "device_create_file failed!\n");
- lo->pid = 0;
+ dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
+ nbd->pid = 0;
return ret;
}
- while ((req = nbd_read_stat(lo)) != NULL)
+ while ((req = nbd_read_stat(nbd)) != NULL)
nbd_end_request(req);
- device_remove_file(disk_to_dev(lo->disk), &pid_attr);
- lo->pid = 0;
+ device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
+ nbd->pid = 0;
return 0;
}
-static void nbd_clear_que(struct nbd_device *lo)
+static void nbd_clear_que(struct nbd_device *nbd)
{
struct request *req;
- BUG_ON(lo->magic != LO_MAGIC);
+ BUG_ON(nbd->magic != NBD_MAGIC);
/*
- * Because we have set lo->sock to NULL under the tx_lock, all
+ * Because we have set nbd->sock to NULL under the tx_lock, all
* modifications to the list must have completed by now. For
* the same reason, the active_req must be NULL.
*
* As a consequence, we don't need to take the spin lock while
* purging the list here.
*/
- BUG_ON(lo->sock);
- BUG_ON(lo->active_req);
+ BUG_ON(nbd->sock);
+ BUG_ON(nbd->active_req);
- while (!list_empty(&lo->queue_head)) {
- req = list_entry(lo->queue_head.next, struct request,
+ while (!list_empty(&nbd->queue_head)) {
+ req = list_entry(nbd->queue_head.next, struct request,
queuelist);
list_del_init(&req->queuelist);
req->errors++;
@@ -448,7 +448,7 @@ static void nbd_clear_que(struct nbd_device *lo)
}
-static void nbd_handle_req(struct nbd_device *lo, struct request *req)
+static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
{
if (req->cmd_type != REQ_TYPE_FS)
goto error_out;
@@ -456,8 +456,8 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req)
nbd_cmd(req) = NBD_CMD_READ;
if (rq_data_dir(req) == WRITE) {
nbd_cmd(req) = NBD_CMD_WRITE;
- if (lo->flags & NBD_READ_ONLY) {
- dev_err(disk_to_dev(lo->disk),
+ if (nbd->flags & NBD_READ_ONLY) {
+ dev_err(disk_to_dev(nbd->disk),
"Write on read-only\n");
goto error_out;
}
@@ -465,29 +465,29 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req)
req->errors = 0;
- mutex_lock(&lo->tx_lock);
- if (unlikely(!lo->sock)) {
- mutex_unlock(&lo->tx_lock);
- dev_err(disk_to_dev(lo->disk),
+ mutex_lock(&nbd->tx_lock);
+ if (unlikely(!nbd->sock)) {
+ mutex_unlock(&nbd->tx_lock);
+ dev_err(disk_to_dev(nbd->disk),
"Attempted send on closed socket\n");
goto error_out;
}
- lo->active_req = req;
+ nbd->active_req = req;
- if (nbd_send_req(lo, req) != 0) {
- dev_err(disk_to_dev(lo->disk), "Request send failed\n");
+ if (nbd_send_req(nbd, req) != 0) {
+ dev_err(disk_to_dev(nbd->disk), "Request send failed\n");
req->errors++;
nbd_end_request(req);
} else {
- spin_lock(&lo->queue_lock);
- list_add(&req->queuelist, &lo->queue_head);
- spin_unlock(&lo->queue_lock);
+ spin_lock(&nbd->queue_lock);
+ list_add(&req->queuelist, &nbd->queue_head);
+ spin_unlock(&nbd->queue_lock);
}
- lo->active_req = NULL;
- mutex_unlock(&lo->tx_lock);
- wake_up_all(&lo->active_wq);
+ nbd->active_req = NULL;
+ mutex_unlock(&nbd->tx_lock);
+ wake_up_all(&nbd->active_wq);
return;
@@ -498,28 +498,28 @@ error_out:
static int nbd_thread(void *data)
{
- struct nbd_device *lo = data;
+ struct nbd_device *nbd = data;
struct request *req;
set_user_nice(current, -20);
- while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) {
+ while (!kthread_should_stop() || !list_empty(&nbd->waiting_queue)) {
/* wait for something to do */
- wait_event_interruptible(lo->waiting_wq,
+ wait_event_interruptible(nbd->waiting_wq,
kthread_should_stop() ||
- !list_empty(&lo->waiting_queue));
+ !list_empty(&nbd->waiting_queue));
/* extract request */
- if (list_empty(&lo->waiting_queue))
+ if (list_empty(&nbd->waiting_queue))
continue;
- spin_lock_irq(&lo->queue_lock);
- req = list_entry(lo->waiting_queue.next, struct request,
+ spin_lock_irq(&nbd->queue_lock);
+ req = list_entry(nbd->waiting_queue.next, struct request,
queuelist);
list_del_init(&req->queuelist);
- spin_unlock_irq(&lo->queue_lock);
+ spin_unlock_irq(&nbd->queue_lock);
/* handle request */
- nbd_handle_req(lo, req);
+ nbd_handle_req(nbd, req);
}
return 0;
}
@@ -527,7 +527,7 @@ static int nbd_thread(void *data)
/*
* We always wait for result of write, for now. It would be nice to make it optional
* in future
- * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK))
+ * if ((rq_data_dir(req) == WRITE) && (nbd->flags & NBD_WRITE_NOCHK))
* { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
*/
@@ -536,19 +536,19 @@ static void do_nbd_request(struct request_queue *q)
struct request *req;
while ((req = blk_fetch_request(q)) != NULL) {
- struct nbd_device *lo;
+ struct nbd_device *nbd;
spin_unlock_irq(q->queue_lock);
dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
req->rq_disk->disk_name, req, req->cmd_type);
- lo = req->rq_disk->private_data;
+ nbd = req->rq_disk->private_data;
- BUG_ON(lo->magic != LO_MAGIC);
+ BUG_ON(nbd->magic != NBD_MAGIC);
- if (unlikely(!lo->sock)) {
- dev_err(disk_to_dev(lo->disk),
+ if (unlikely(!nbd->sock)) {
+ dev_err(disk_to_dev(nbd->disk),
"Attempted send on closed socket\n");
req->errors++;
nbd_end_request(req);
@@ -556,11 +556,11 @@ static void do_nbd_request(struct request_queue *q)
continue;
}
- spin_lock_irq(&lo->queue_lock);
- list_add_tail(&req->queuelist, &lo->waiting_queue);
- spin_unlock_irq(&lo->queue_lock);
+ spin_lock_irq(&nbd->queue_lock);
+ list_add_tail(&req->queuelist, &nbd->waiting_queue);
+ spin_unlock_irq(&nbd->queue_lock);
- wake_up(&lo->waiting_wq);
+ wake_up(&nbd->waiting_wq);
spin_lock_irq(q->queue_lock);
}
@@ -568,32 +568,32 @@ static void do_nbd_request(struct request_queue *q)
/* Must be called with tx_lock held */
-static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
+static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case NBD_DISCONNECT: {
struct request sreq;
- dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n");
+ dev_info(disk_to_dev(nbd->disk), "NBD_DISCONNECT\n");
blk_rq_init(NULL, &sreq);
sreq.cmd_type = REQ_TYPE_SPECIAL;
nbd_cmd(&sreq) = NBD_CMD_DISC;
- if (!lo->sock)
+ if (!nbd->sock)
return -EINVAL;
- nbd_send_req(lo, &sreq);
+ nbd_send_req(nbd, &sreq);
return 0;
}
case NBD_CLEAR_SOCK: {
struct file *file;
- lo->sock = NULL;
- file = lo->file;
- lo->file = NULL;
- nbd_clear_que(lo);
- BUG_ON(!list_empty(&lo->queue_head));
+ nbd->sock = NULL;
+ file = nbd->file;
+ nbd->file = NULL;
+ nbd_clear_que(nbd);
+ BUG_ON(!list_empty(&nbd->queue_head));
if (file)
fput(file);
return 0;
@@ -601,14 +601,14 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
case NBD_SET_SOCK: {
struct file *file;
- if (lo->file)
+ if (nbd->file)
return -EBUSY;
file = fget(arg);
if (file) {
struct inode *inode = file->f_path.dentry->d_inode;
if (S_ISSOCK(inode->i_mode)) {
- lo->file = file;
- lo->sock = SOCKET_I(inode);
+ nbd->file = file;
+ nbd->sock = SOCKET_I(inode);
if (max_part > 0)
bdev->bd_invalidated = 1;
return 0;
@@ -620,29 +620,29 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
}
case NBD_SET_BLKSIZE:
- lo->blksize = arg;
- lo->bytesize &= ~(lo->blksize-1);
- bdev->bd_inode->i_size = lo->bytesize;
- set_blocksize(bdev, lo->blksize);
- set_capacity(lo->disk, lo->bytesize >> 9);
+ nbd->blksize = arg;
+ nbd->bytesize &= ~(nbd->blksize-1);
+ bdev->bd_inode->i_size = nbd->bytesize;
+ set_blocksize(bdev, nbd->blksize);
+ set_capacity(nbd->disk, nbd->bytesize >> 9);
return 0;
case NBD_SET_SIZE:
- lo->bytesize = arg & ~(lo->blksize-1);
- bdev->bd_inode->i_size = lo->bytesize;
- set_blocksize(bdev, lo->blksize);
- set_capacity(lo->disk, lo->bytesize >> 9);
+ nbd->bytesize = arg & ~(nbd->blksize-1);
+ bdev->bd_inode->i_size = nbd->bytesize;
+ set_blocksize(bdev, nbd->blksize);
+ set_capacity(nbd->disk, nbd->bytesize >> 9);
return 0;
case NBD_SET_TIMEOUT:
- lo->xmit_timeout = arg * HZ;
+ nbd->xmit_timeout = arg * HZ;
return 0;
case NBD_SET_SIZE_BLOCKS:
- lo->bytesize = ((u64) arg) * lo->blksize;
- bdev->bd_inode->i_size = lo->bytesize;
- set_blocksize(bdev, lo->blksize);
- set_capacity(lo->disk, lo->bytesize >> 9);
+ nbd->bytesize = ((u64) arg) * nbd->blksize;
+ bdev->bd_inode->i_size = nbd->bytesize;
+ set_blocksize(bdev, nbd->blksize);
+ set_capacity(nbd->disk, nbd->bytesize >> 9);
return 0;
case NBD_DO_IT: {
@@ -650,38 +650,38 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
struct file *file;
int error;
- if (lo->pid)
+ if (nbd->pid)
return -EBUSY;
- if (!lo->file)
+ if (!nbd->file)
return -EINVAL;
- mutex_unlock(&lo->tx_lock);
+ mutex_unlock(&nbd->tx_lock);
- thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
+ thread = kthread_create(nbd_thread, nbd, nbd->disk->disk_name);
if (IS_ERR(thread)) {
- mutex_lock(&lo->tx_lock);
+ mutex_lock(&nbd->tx_lock);
return PTR_ERR(thread);
}
wake_up_process(thread);
- error = nbd_do_it(lo);
+ error = nbd_do_it(nbd);
kthread_stop(thread);
- mutex_lock(&lo->tx_lock);
+ mutex_lock(&nbd->tx_lock);
if (error)
return error;
- sock_shutdown(lo, 0);
- file = lo->file;
- lo->file = NULL;
- nbd_clear_que(lo);
- dev_warn(disk_to_dev(lo->disk), "queue cleared\n");
+ sock_shutdown(nbd, 0);
+ file = nbd->file;
+ nbd->file = NULL;
+ nbd_clear_que(nbd);
+ dev_warn(disk_to_dev(nbd->disk), "queue cleared\n");
if (file)
fput(file);
- lo->bytesize = 0;
+ nbd->bytesize = 0;
bdev->bd_inode->i_size = 0;
- set_capacity(lo->disk, 0);
+ set_capacity(nbd->disk, 0);
if (max_part > 0)
ioctl_by_bdev(bdev, BLKRRPART, 0);
- return lo->harderror;
+ return nbd->harderror;
}
case NBD_CLEAR_QUE:
@@ -689,14 +689,14 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
* This is for compatibility only. The queue is always cleared
* by NBD_DO_IT or NBD_CLEAR_SOCK.
*/
- BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
+ BUG_ON(!nbd->sock && !list_empty(&nbd->queue_head));
return 0;
case NBD_PRINT_DEBUG:
- dev_info(disk_to_dev(lo->disk),
+ dev_info(disk_to_dev(nbd->disk),
"next = %p, prev = %p, head = %p\n",
- lo->queue_head.next, lo->queue_head.prev,
- &lo->queue_head);
+ nbd->queue_head.next, nbd->queue_head.prev,
+ &nbd->queue_head);
return 0;
}
return -ENOTTY;
@@ -705,21 +705,21 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct nbd_device *lo = bdev->bd_disk->private_data;
+ struct nbd_device *nbd = bdev->bd_disk->private_data;
int error;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- BUG_ON(lo->magic != LO_MAGIC);
+ BUG_ON(nbd->magic != NBD_MAGIC);
/* Anyone capable of this syscall can do *real bad* things */
dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
- lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+ nbd->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
- mutex_lock(&lo->tx_lock);
- error = __nbd_ioctl(bdev, lo, cmd, arg);
- mutex_unlock(&lo->tx_lock);
+ mutex_lock(&nbd->tx_lock);
+ error = __nbd_ioctl(bdev, nbd, cmd, arg);
+ mutex_unlock(&nbd->tx_lock);
return error;
}
@@ -805,7 +805,7 @@ static int __init nbd_init(void)
for (i = 0; i < nbds_max; i++) {
struct gendisk *disk = nbd_dev[i].disk;
nbd_dev[i].file = NULL;
- nbd_dev[i].magic = LO_MAGIC;
+ nbd_dev[i].magic = NBD_MAGIC;
nbd_dev[i].flags = 0;
INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
spin_lock_init(&nbd_dev[i].queue_lock);
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index a6278e7e61a0..013c7a549fb6 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -41,19 +41,35 @@
#include "rbd_types.h"
-#define DRV_NAME "rbd"
-#define DRV_NAME_LONG "rbd (rados block device)"
+/*
+ * The basic unit of block I/O is a sector. It is interpreted in a
+ * number of contexts in Linux (blk, bio, genhd), but the default is
+ * universally 512 bytes. These symbols are just slightly more
+ * meaningful than the bare numbers they represent.
+ */
+#define SECTOR_SHIFT 9
+#define SECTOR_SIZE (1ULL << SECTOR_SHIFT)
+
+#define RBD_DRV_NAME "rbd"
+#define RBD_DRV_NAME_LONG "rbd (rados block device)"
#define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */
-#define RBD_MAX_MD_NAME_LEN (96 + sizeof(RBD_SUFFIX))
+#define RBD_MAX_MD_NAME_LEN (RBD_MAX_OBJ_NAME_LEN + sizeof(RBD_SUFFIX))
#define RBD_MAX_POOL_NAME_LEN 64
#define RBD_MAX_SNAP_NAME_LEN 32
#define RBD_MAX_OPT_LEN 1024
#define RBD_SNAP_HEAD_NAME "-"
+/*
+ * An RBD device name will be "rbd#", where the "rbd" comes from
+ * RBD_DRV_NAME above, and # is a unique integer identifier.
+ * MAX_INT_FORMAT_WIDTH is used in ensuring DEV_NAME_LEN is big
+ * enough to hold all possible device names.
+ */
#define DEV_NAME_LEN 32
+#define MAX_INT_FORMAT_WIDTH ((5 * sizeof (int)) / 2 + 1)
#define RBD_NOTIFY_TIMEOUT_DEFAULT 10
@@ -66,7 +82,6 @@ struct rbd_image_header {
__u8 obj_order;
__u8 crypt_type;
__u8 comp_type;
- struct rw_semaphore snap_rwsem;
struct ceph_snap_context *snapc;
size_t snap_names_len;
u64 snap_seq;
@@ -83,7 +98,7 @@ struct rbd_options {
};
/*
- * an instance of the client. multiple devices may share a client.
+ * an instance of the client. multiple devices may share an rbd client.
*/
struct rbd_client {
struct ceph_client *client;
@@ -92,20 +107,9 @@ struct rbd_client {
struct list_head node;
};
-struct rbd_req_coll;
-
/*
- * a single io request
+ * a request completion status
*/
-struct rbd_request {
- struct request *rq; /* blk layer request */
- struct bio *bio; /* cloned bio */
- struct page **pages; /* list of used pages */
- u64 len;
- int coll_index;
- struct rbd_req_coll *coll;
-};
-
struct rbd_req_status {
int done;
int rc;
@@ -122,6 +126,18 @@ struct rbd_req_coll {
struct rbd_req_status status[0];
};
+/*
+ * a single io request
+ */
+struct rbd_request {
+ struct request *rq; /* blk layer request */
+ struct bio *bio; /* cloned bio */
+ struct page **pages; /* list of used pages */
+ u64 len;
+ int coll_index;
+ struct rbd_req_coll *coll;
+};
+
struct rbd_snap {
struct device dev;
const char *name;
@@ -140,7 +156,6 @@ struct rbd_device {
struct gendisk *disk; /* blkdev's gendisk and rq */
struct request_queue *q;
- struct ceph_client *client;
struct rbd_client *rbd_client;
char name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */
@@ -157,6 +172,8 @@ struct rbd_device {
struct ceph_osd_event *watch_event;
struct ceph_osd_request *watch_request;
+ /* protects updating the header */
+ struct rw_semaphore header_rwsem;
char snap_name[RBD_MAX_SNAP_NAME_LEN];
u32 cur_snap; /* index+1 of current snapshot within snap context
0 - for the head */
@@ -171,15 +188,13 @@ struct rbd_device {
struct device dev;
};
-static struct bus_type rbd_bus_type = {
- .name = "rbd",
-};
-
-static spinlock_t node_lock; /* protects client get/put */
-
static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */
+
static LIST_HEAD(rbd_dev_list); /* devices */
-static LIST_HEAD(rbd_client_list); /* clients */
+static DEFINE_SPINLOCK(rbd_dev_list_lock);
+
+static LIST_HEAD(rbd_client_list); /* clients */
+static DEFINE_SPINLOCK(rbd_client_list_lock);
static int __rbd_init_snaps_header(struct rbd_device *rbd_dev);
static void rbd_dev_release(struct device *dev);
@@ -190,12 +205,32 @@ static ssize_t rbd_snap_add(struct device *dev,
static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
struct rbd_snap *snap);
+static ssize_t rbd_add(struct bus_type *bus, const char *buf,
+ size_t count);
+static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
+ size_t count);
-static struct rbd_device *dev_to_rbd(struct device *dev)
+static struct bus_attribute rbd_bus_attrs[] = {
+ __ATTR(add, S_IWUSR, NULL, rbd_add),
+ __ATTR(remove, S_IWUSR, NULL, rbd_remove),
+ __ATTR_NULL
+};
+
+static struct bus_type rbd_bus_type = {
+ .name = "rbd",
+ .bus_attrs = rbd_bus_attrs,
+};
+
+static void rbd_root_dev_release(struct device *dev)
{
- return container_of(dev, struct rbd_device, dev);
}
+static struct device rbd_root_dev = {
+ .init_name = "rbd",
+ .release = rbd_root_dev_release,
+};
+
+
static struct device *rbd_get_dev(struct rbd_device *rbd_dev)
{
return get_device(&rbd_dev->dev);
@@ -210,8 +245,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev);
static int rbd_open(struct block_device *bdev, fmode_t mode)
{
- struct gendisk *disk = bdev->bd_disk;
- struct rbd_device *rbd_dev = disk->private_data;
+ struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
rbd_get_dev(rbd_dev);
@@ -256,9 +290,11 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt,
kref_init(&rbdc->kref);
INIT_LIST_HEAD(&rbdc->node);
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
rbdc->client = ceph_create_client(opt, rbdc, 0, 0);
if (IS_ERR(rbdc->client))
- goto out_rbdc;
+ goto out_mutex;
opt = NULL; /* Now rbdc->client is responsible for opt */
ret = ceph_open_session(rbdc->client);
@@ -267,16 +303,19 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt,
rbdc->rbd_opts = rbd_opts;
- spin_lock(&node_lock);
+ spin_lock(&rbd_client_list_lock);
list_add_tail(&rbdc->node, &rbd_client_list);
- spin_unlock(&node_lock);
+ spin_unlock(&rbd_client_list_lock);
+
+ mutex_unlock(&ctl_mutex);
dout("rbd_client_create created %p\n", rbdc);
return rbdc;
out_err:
ceph_destroy_client(rbdc->client);
-out_rbdc:
+out_mutex:
+ mutex_unlock(&ctl_mutex);
kfree(rbdc);
out_opt:
if (opt)
@@ -324,7 +363,7 @@ static int parse_rbd_opts_token(char *c, void *private)
substring_t argstr[MAX_OPT_ARGS];
int token, intval, ret;
- token = match_token((char *)c, rbdopt_tokens, argstr);
+ token = match_token(c, rbdopt_tokens, argstr);
if (token < 0)
return -EINVAL;
@@ -357,58 +396,54 @@ static int parse_rbd_opts_token(char *c, void *private)
* Get a ceph client with specific addr and configuration, if one does
* not exist create it.
*/
-static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
- char *options)
+static struct rbd_client *rbd_get_client(const char *mon_addr,
+ size_t mon_addr_len,
+ char *options)
{
struct rbd_client *rbdc;
struct ceph_options *opt;
- int ret;
struct rbd_options *rbd_opts;
rbd_opts = kzalloc(sizeof(*rbd_opts), GFP_KERNEL);
if (!rbd_opts)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT;
- ret = ceph_parse_options(&opt, options, mon_addr,
- mon_addr + strlen(mon_addr), parse_rbd_opts_token, rbd_opts);
- if (ret < 0)
- goto done_err;
+ opt = ceph_parse_options(options, mon_addr,
+ mon_addr + mon_addr_len,
+ parse_rbd_opts_token, rbd_opts);
+ if (IS_ERR(opt)) {
+ kfree(rbd_opts);
+ return ERR_CAST(opt);
+ }
- spin_lock(&node_lock);
+ spin_lock(&rbd_client_list_lock);
rbdc = __rbd_client_find(opt);
if (rbdc) {
+ /* using an existing client */
+ kref_get(&rbdc->kref);
+ spin_unlock(&rbd_client_list_lock);
+
ceph_destroy_options(opt);
kfree(rbd_opts);
- /* using an existing client */
- kref_get(&rbdc->kref);
- rbd_dev->rbd_client = rbdc;
- rbd_dev->client = rbdc->client;
- spin_unlock(&node_lock);
- return 0;
+ return rbdc;
}
- spin_unlock(&node_lock);
+ spin_unlock(&rbd_client_list_lock);
rbdc = rbd_client_create(opt, rbd_opts);
- if (IS_ERR(rbdc)) {
- ret = PTR_ERR(rbdc);
- goto done_err;
- }
- rbd_dev->rbd_client = rbdc;
- rbd_dev->client = rbdc->client;
- return 0;
-done_err:
- kfree(rbd_opts);
- return ret;
+ if (IS_ERR(rbdc))
+ kfree(rbd_opts);
+
+ return rbdc;
}
/*
* Destroy ceph client
*
- * Caller must hold node_lock.
+ * Caller must hold rbd_client_list_lock.
*/
static void rbd_client_release(struct kref *kref)
{
@@ -428,11 +463,10 @@ static void rbd_client_release(struct kref *kref)
*/
static void rbd_put_client(struct rbd_device *rbd_dev)
{
- spin_lock(&node_lock);
+ spin_lock(&rbd_client_list_lock);
kref_put(&rbd_dev->rbd_client->kref, rbd_client_release);
- spin_unlock(&node_lock);
+ spin_unlock(&rbd_client_list_lock);
rbd_dev->rbd_client = NULL;
- rbd_dev->client = NULL;
}
/*
@@ -457,21 +491,19 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
gfp_t gfp_flags)
{
int i;
- u32 snap_count = le32_to_cpu(ondisk->snap_count);
- int ret = -ENOMEM;
+ u32 snap_count;
- if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) {
+ if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT)))
return -ENXIO;
- }
- init_rwsem(&header->snap_rwsem);
- header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
+ snap_count = le32_to_cpu(ondisk->snap_count);
header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
- snap_count *
- sizeof(struct rbd_image_snap_ondisk),
+ snap_count * sizeof (*ondisk),
gfp_flags);
if (!header->snapc)
return -ENOMEM;
+
+ header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
if (snap_count) {
header->snap_names = kmalloc(header->snap_names_len,
GFP_KERNEL);
@@ -498,8 +530,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
header->snapc->num_snaps = snap_count;
header->total_snaps = snap_count;
- if (snap_count &&
- allocated_snaps == snap_count) {
+ if (snap_count && allocated_snaps == snap_count) {
for (i = 0; i < snap_count; i++) {
header->snapc->snaps[i] =
le64_to_cpu(ondisk->snaps[i].id);
@@ -518,7 +549,7 @@ err_names:
kfree(header->snap_names);
err_snapc:
kfree(header->snapc);
- return ret;
+ return -ENOMEM;
}
static int snap_index(struct rbd_image_header *header, int snap_num)
@@ -542,35 +573,34 @@ static int snap_by_name(struct rbd_image_header *header, const char *snap_name,
int i;
char *p = header->snap_names;
- for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
- if (strcmp(snap_name, p) == 0)
- break;
- }
- if (i == header->total_snaps)
- return -ENOENT;
- if (seq)
- *seq = header->snapc->snaps[i];
+ for (i = 0; i < header->total_snaps; i++) {
+ if (!strcmp(snap_name, p)) {
- if (size)
- *size = header->snap_sizes[i];
+ /* Found it. Pass back its id and/or size */
- return i;
+ if (seq)
+ *seq = header->snapc->snaps[i];
+ if (size)
+ *size = header->snap_sizes[i];
+ return i;
+ }
+ p += strlen(p) + 1; /* Skip ahead to the next name */
+ }
+ return -ENOENT;
}
-static int rbd_header_set_snap(struct rbd_device *dev,
- const char *snap_name,
- u64 *size)
+static int rbd_header_set_snap(struct rbd_device *dev, u64 *size)
{
struct rbd_image_header *header = &dev->header;
struct ceph_snap_context *snapc = header->snapc;
int ret = -ENOENT;
- down_write(&header->snap_rwsem);
+ BUILD_BUG_ON(sizeof (dev->snap_name) < sizeof (RBD_SNAP_HEAD_NAME));
- if (!snap_name ||
- !*snap_name ||
- strcmp(snap_name, "-") == 0 ||
- strcmp(snap_name, RBD_SNAP_HEAD_NAME) == 0) {
+ down_write(&dev->header_rwsem);
+
+ if (!memcmp(dev->snap_name, RBD_SNAP_HEAD_NAME,
+ sizeof (RBD_SNAP_HEAD_NAME))) {
if (header->total_snaps)
snapc->seq = header->snap_seq;
else
@@ -580,7 +610,7 @@ static int rbd_header_set_snap(struct rbd_device *dev,
if (size)
*size = header->image_size;
} else {
- ret = snap_by_name(header, snap_name, &snapc->seq, size);
+ ret = snap_by_name(header, dev->snap_name, &snapc->seq, size);
if (ret < 0)
goto done;
@@ -590,7 +620,7 @@ static int rbd_header_set_snap(struct rbd_device *dev,
ret = 0;
done:
- up_write(&header->snap_rwsem);
+ up_write(&dev->header_rwsem);
return ret;
}
@@ -717,7 +747,7 @@ static struct bio *bio_chain_clone(struct bio **old, struct bio **next,
/* split the bio. We'll release it either in the next
call, or it will have to be released outside */
- bp = bio_split(old_chain, (len - total) / 512ULL);
+ bp = bio_split(old_chain, (len - total) / SECTOR_SIZE);
if (!bp)
goto err_out;
@@ -857,7 +887,7 @@ static int rbd_do_request(struct request *rq,
struct timespec mtime = CURRENT_TIME;
struct rbd_request *req_data;
struct ceph_osd_request_head *reqhead;
- struct rbd_image_header *header = &dev->header;
+ struct ceph_osd_client *osdc;
req_data = kzalloc(sizeof(*req_data), GFP_NOIO);
if (!req_data) {
@@ -874,15 +904,13 @@ static int rbd_do_request(struct request *rq,
dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs);
- down_read(&header->snap_rwsem);
+ down_read(&dev->header_rwsem);
- req = ceph_osdc_alloc_request(&dev->client->osdc, flags,
- snapc,
- ops,
- false,
- GFP_NOIO, pages, bio);
+ osdc = &dev->rbd_client->client->osdc;
+ req = ceph_osdc_alloc_request(osdc, flags, snapc, ops,
+ false, GFP_NOIO, pages, bio);
if (!req) {
- up_read(&header->snap_rwsem);
+ up_read(&dev->header_rwsem);
ret = -ENOMEM;
goto done_pages;
}
@@ -909,27 +937,27 @@ static int rbd_do_request(struct request *rq,
layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
layout->fl_pg_preferred = cpu_to_le32(-1);
layout->fl_pg_pool = cpu_to_le32(dev->poolid);
- ceph_calc_raw_layout(&dev->client->osdc, layout, snapid,
- ofs, &len, &bno, req, ops);
+ ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno,
+ req, ops);
ceph_osdc_build_request(req, ofs, &len,
ops,
snapc,
&mtime,
req->r_oid, req->r_oid_len);
- up_read(&header->snap_rwsem);
+ up_read(&dev->header_rwsem);
if (linger_req) {
- ceph_osdc_set_request_linger(&dev->client->osdc, req);
+ ceph_osdc_set_request_linger(osdc, req);
*linger_req = req;
}
- ret = ceph_osdc_start_request(&dev->client->osdc, req, false);
+ ret = ceph_osdc_start_request(osdc, req, false);
if (ret < 0)
goto done_err;
if (!rbd_cb) {
- ret = ceph_osdc_wait_request(&dev->client->osdc, req);
+ ret = ceph_osdc_wait_request(osdc, req);
if (ver)
*ver = le64_to_cpu(req->r_reassert_version.version);
dout("reassert_ver=%lld\n",
@@ -1213,8 +1241,8 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
rc = __rbd_update_snaps(dev);
mutex_unlock(&ctl_mutex);
if (rc)
- pr_warning(DRV_NAME "%d got notification but failed to update"
- " snaps: %d\n", dev->major, rc);
+ pr_warning(RBD_DRV_NAME "%d got notification but failed to "
+ " update snaps: %d\n", dev->major, rc);
rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
}
@@ -1227,7 +1255,7 @@ static int rbd_req_sync_watch(struct rbd_device *dev,
u64 ver)
{
struct ceph_osd_req_op *ops;
- struct ceph_osd_client *osdc = &dev->client->osdc;
+ struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_WATCH, 0);
if (ret < 0)
@@ -1314,7 +1342,7 @@ static int rbd_req_sync_notify(struct rbd_device *dev,
const char *obj)
{
struct ceph_osd_req_op *ops;
- struct ceph_osd_client *osdc = &dev->client->osdc;
+ struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
struct ceph_osd_event *event;
struct rbd_notify_info info;
int payload_len = sizeof(u32) + sizeof(u32);
@@ -1421,9 +1449,7 @@ static void rbd_rq_fn(struct request_queue *q)
struct request *rq;
struct bio_pair *bp = NULL;
- rq = blk_fetch_request(q);
-
- while (1) {
+ while ((rq = blk_fetch_request(q))) {
struct bio *bio;
struct bio *rq_bio, *next_bio = NULL;
bool do_write;
@@ -1441,32 +1467,32 @@ static void rbd_rq_fn(struct request_queue *q)
/* filter out block requests we don't understand */
if ((rq->cmd_type != REQ_TYPE_FS)) {
__blk_end_request_all(rq, 0);
- goto next;
+ continue;
}
/* deduce our operation (read, write) */
do_write = (rq_data_dir(rq) == WRITE);
size = blk_rq_bytes(rq);
- ofs = blk_rq_pos(rq) * 512ULL;
+ ofs = blk_rq_pos(rq) * SECTOR_SIZE;
rq_bio = rq->bio;
if (do_write && rbd_dev->read_only) {
__blk_end_request_all(rq, -EROFS);
- goto next;
+ continue;
}
spin_unlock_irq(q->queue_lock);
dout("%s 0x%x bytes at 0x%llx\n",
do_write ? "write" : "read",
- size, blk_rq_pos(rq) * 512ULL);
+ size, blk_rq_pos(rq) * SECTOR_SIZE);
num_segs = rbd_get_num_segments(&rbd_dev->header, ofs, size);
coll = rbd_alloc_coll(num_segs);
if (!coll) {
spin_lock_irq(q->queue_lock);
__blk_end_request_all(rq, -ENOMEM);
- goto next;
+ continue;
}
do {
@@ -1512,8 +1538,6 @@ next_seg:
if (bp)
bio_pair_release(bp);
spin_lock_irq(q->queue_lock);
-next:
- rq = blk_fetch_request(q);
}
}
@@ -1526,13 +1550,17 @@ static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
struct bio_vec *bvec)
{
struct rbd_device *rbd_dev = q->queuedata;
- unsigned int chunk_sectors = 1 << (rbd_dev->header.obj_order - 9);
- sector_t sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
- unsigned int bio_sectors = bmd->bi_size >> 9;
+ unsigned int chunk_sectors;
+ sector_t sector;
+ unsigned int bio_sectors;
int max;
+ chunk_sectors = 1 << (rbd_dev->header.obj_order - SECTOR_SHIFT);
+ sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
+ bio_sectors = bmd->bi_size >> SECTOR_SHIFT;
+
max = (chunk_sectors - ((sector & (chunk_sectors - 1))
- + bio_sectors)) << 9;
+ + bio_sectors)) << SECTOR_SHIFT;
if (max < 0)
max = 0; /* bio_add cannot handle a negative return */
if (max <= bvec->bv_len && bio_sectors == 0)
@@ -1565,15 +1593,16 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
ssize_t rc;
struct rbd_image_header_ondisk *dh;
int snap_count = 0;
- u64 snap_names_len = 0;
u64 ver;
+ size_t len;
+ /*
+ * First reads the fixed-size header to determine the number
+ * of snapshots, then re-reads it, along with all snapshot
+ * records as well as their stored names.
+ */
+ len = sizeof (*dh);
while (1) {
- int len = sizeof(*dh) +
- snap_count * sizeof(struct rbd_image_snap_ondisk) +
- snap_names_len;
-
- rc = -ENOMEM;
dh = kmalloc(len, GFP_KERNEL);
if (!dh)
return -ENOMEM;
@@ -1588,21 +1617,22 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL);
if (rc < 0) {
- if (rc == -ENXIO) {
+ if (rc == -ENXIO)
pr_warning("unrecognized header format"
" for image %s", rbd_dev->obj);
- }
goto out_dh;
}
- if (snap_count != header->total_snaps) {
- snap_count = header->total_snaps;
- snap_names_len = header->snap_names_len;
- rbd_header_free(header);
- kfree(dh);
- continue;
- }
- break;
+ if (snap_count == header->total_snaps)
+ break;
+
+ snap_count = header->total_snaps;
+ len = sizeof (*dh) +
+ snap_count * sizeof(struct rbd_image_snap_ondisk) +
+ header->snap_names_len;
+
+ rbd_header_free(header);
+ kfree(dh);
}
header->obj_version = ver;
@@ -1623,13 +1653,14 @@ static int rbd_header_add_snap(struct rbd_device *dev,
int ret;
void *data, *p, *e;
u64 ver;
+ struct ceph_mon_client *monc;
/* we should create a snapshot only if we're pointing at the head */
if (dev->cur_snap)
return -EINVAL;
- ret = ceph_monc_create_snapid(&dev->client->monc, dev->poolid,
- &new_snapid);
+ monc = &dev->rbd_client->client->monc;
+ ret = ceph_monc_create_snapid(monc, dev->poolid, &new_snapid);
dout("created snapid=%lld\n", new_snapid);
if (ret < 0)
return ret;
@@ -1684,9 +1715,9 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
return ret;
/* resized? */
- set_capacity(rbd_dev->disk, h.image_size / 512ULL);
+ set_capacity(rbd_dev->disk, h.image_size / SECTOR_SIZE);
- down_write(&rbd_dev->header.snap_rwsem);
+ down_write(&rbd_dev->header_rwsem);
snap_seq = rbd_dev->header.snapc->seq;
if (rbd_dev->header.total_snaps &&
@@ -1711,7 +1742,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
ret = __rbd_init_snaps_header(rbd_dev);
- up_write(&rbd_dev->header.snap_rwsem);
+ up_write(&rbd_dev->header_rwsem);
return ret;
}
@@ -1721,6 +1752,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
struct gendisk *disk;
struct request_queue *q;
int rc;
+ u64 segment_size;
u64 total_size = 0;
/* contact OSD, request size info about the object being mapped */
@@ -1733,7 +1765,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
if (rc)
return rc;
- rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size);
+ rc = rbd_header_set_snap(rbd_dev, &total_size);
if (rc)
return rc;
@@ -1743,7 +1775,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
if (!disk)
goto out;
- snprintf(disk->disk_name, sizeof(disk->disk_name), DRV_NAME "%d",
+ snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d",
rbd_dev->id);
disk->major = rbd_dev->major;
disk->first_minor = 0;
@@ -1756,11 +1788,15 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
if (!q)
goto out_disk;
+ /* We use the default size, but let's be explicit about it. */
+ blk_queue_physical_block_size(q, SECTOR_SIZE);
+
/* set io sizes to object size */
- blk_queue_max_hw_sectors(q, rbd_obj_bytes(&rbd_dev->header) / 512ULL);
- blk_queue_max_segment_size(q, rbd_obj_bytes(&rbd_dev->header));
- blk_queue_io_min(q, rbd_obj_bytes(&rbd_dev->header));
- blk_queue_io_opt(q, rbd_obj_bytes(&rbd_dev->header));
+ segment_size = rbd_obj_bytes(&rbd_dev->header);
+ blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE);
+ blk_queue_max_segment_size(q, segment_size);
+ blk_queue_io_min(q, segment_size);
+ blk_queue_io_opt(q, segment_size);
blk_queue_merge_bvec(q, rbd_merge_bvec);
disk->queue = q;
@@ -1771,7 +1807,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
rbd_dev->q = q;
/* finally, announce the disk to the world */
- set_capacity(disk, total_size / 512ULL);
+ set_capacity(disk, total_size / SECTOR_SIZE);
add_disk(disk);
pr_info("%s: added with size 0x%llx\n",
@@ -1788,10 +1824,15 @@ out:
sysfs
*/
+static struct rbd_device *dev_to_rbd_dev(struct device *dev)
+{
+ return container_of(dev, struct rbd_device, dev);
+}
+
static ssize_t rbd_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size);
}
@@ -1799,7 +1840,7 @@ static ssize_t rbd_size_show(struct device *dev,
static ssize_t rbd_major_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
return sprintf(buf, "%d\n", rbd_dev->major);
}
@@ -1807,15 +1848,16 @@ static ssize_t rbd_major_show(struct device *dev,
static ssize_t rbd_client_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
- return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client));
+ return sprintf(buf, "client%lld\n",
+ ceph_client_id(rbd_dev->rbd_client->client));
}
static ssize_t rbd_pool_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
return sprintf(buf, "%s\n", rbd_dev->pool_name);
}
@@ -1823,7 +1865,7 @@ static ssize_t rbd_pool_show(struct device *dev,
static ssize_t rbd_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
return sprintf(buf, "%s\n", rbd_dev->obj);
}
@@ -1832,7 +1874,7 @@ static ssize_t rbd_snap_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
return sprintf(buf, "%s\n", rbd_dev->snap_name);
}
@@ -1842,7 +1884,7 @@ static ssize_t rbd_image_refresh(struct device *dev,
const char *buf,
size_t size)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
int rc;
int ret = size;
@@ -1907,7 +1949,7 @@ static ssize_t rbd_snap_size_show(struct device *dev,
{
struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
- return sprintf(buf, "%lld\n", (long long)snap->size);
+ return sprintf(buf, "%zd\n", snap->size);
}
static ssize_t rbd_snap_id_show(struct device *dev,
@@ -1916,7 +1958,7 @@ static ssize_t rbd_snap_id_show(struct device *dev,
{
struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
- return sprintf(buf, "%lld\n", (long long)snap->id);
+ return sprintf(buf, "%llu\n", (unsigned long long) snap->id);
}
static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL);
@@ -2088,19 +2130,9 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
return 0;
}
-
-static void rbd_root_dev_release(struct device *dev)
-{
-}
-
-static struct device rbd_root_dev = {
- .init_name = "rbd",
- .release = rbd_root_dev_release,
-};
-
static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
{
- int ret = -ENOMEM;
+ int ret;
struct device *dev;
struct rbd_snap *snap;
@@ -2114,7 +2146,7 @@ static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
dev_set_name(dev, "%d", rbd_dev->id);
ret = device_register(dev);
if (ret < 0)
- goto done_free;
+ goto out;
list_for_each_entry(snap, &rbd_dev->snaps, node) {
ret = rbd_register_snap_dev(rbd_dev, snap,
@@ -2122,10 +2154,7 @@ static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
if (ret < 0)
break;
}
-
- mutex_unlock(&ctl_mutex);
- return 0;
-done_free:
+out:
mutex_unlock(&ctl_mutex);
return ret;
}
@@ -2154,104 +2183,250 @@ static int rbd_init_watch_dev(struct rbd_device *rbd_dev)
return ret;
}
+static atomic64_t rbd_id_max = ATOMIC64_INIT(0);
+
+/*
+ * Get a unique rbd identifier for the given new rbd_dev, and add
+ * the rbd_dev to the global list. The minimum rbd id is 1.
+ */
+static void rbd_id_get(struct rbd_device *rbd_dev)
+{
+ rbd_dev->id = atomic64_inc_return(&rbd_id_max);
+
+ spin_lock(&rbd_dev_list_lock);
+ list_add_tail(&rbd_dev->node, &rbd_dev_list);
+ spin_unlock(&rbd_dev_list_lock);
+}
+
+/*
+ * Remove an rbd_dev from the global list, and record that its
+ * identifier is no longer in use.
+ */
+static void rbd_id_put(struct rbd_device *rbd_dev)
+{
+ struct list_head *tmp;
+ int rbd_id = rbd_dev->id;
+ int max_id;
+
+ BUG_ON(rbd_id < 1);
+
+ spin_lock(&rbd_dev_list_lock);
+ list_del_init(&rbd_dev->node);
+
+ /*
+ * If the id being "put" is not the current maximum, there
+ * is nothing special we need to do.
+ */
+ if (rbd_id != atomic64_read(&rbd_id_max)) {
+ spin_unlock(&rbd_dev_list_lock);
+ return;
+ }
+
+ /*
+ * We need to update the current maximum id. Search the
+ * list to find out what it is. We're more likely to find
+ * the maximum at the end, so search the list backward.
+ */
+ max_id = 0;
+ list_for_each_prev(tmp, &rbd_dev_list) {
+ struct rbd_device *rbd_dev;
+
+ rbd_dev = list_entry(tmp, struct rbd_device, node);
+ if (rbd_id > max_id)
+ max_id = rbd_id;
+ }
+ spin_unlock(&rbd_dev_list_lock);
+
+ /*
+ * The max id could have been updated by rbd_id_get(), in
+ * which case it now accurately reflects the new maximum.
+ * Be careful not to overwrite the maximum value in that
+ * case.
+ */
+ atomic64_cmpxchg(&rbd_id_max, rbd_id, max_id);
+}
+
+/*
+ * Skips over white space at *buf, and updates *buf to point to the
+ * first found non-space character (if any). Returns the length of
+ * the token (string of non-white space characters) found. Note
+ * that *buf must be terminated with '\0'.
+ */
+static inline size_t next_token(const char **buf)
+{
+ /*
+ * These are the characters that produce nonzero for
+ * isspace() in the "C" and "POSIX" locales.
+ */
+ const char *spaces = " \f\n\r\t\v";
+
+ *buf += strspn(*buf, spaces); /* Find start of token */
+
+ return strcspn(*buf, spaces); /* Return token length */
+}
+
+/*
+ * Finds the next token in *buf, and if the provided token buffer is
+ * big enough, copies the found token into it. The result, if
+ * copied, is guaranteed to be terminated with '\0'. Note that *buf
+ * must be terminated with '\0' on entry.
+ *
+ * Returns the length of the token found (not including the '\0').
+ * Return value will be 0 if no token is found, and it will be >=
+ * token_size if the token would not fit.
+ *
+ * The *buf pointer will be updated to point beyond the end of the
+ * found token. Note that this occurs even if the token buffer is
+ * too small to hold it.
+ */
+static inline size_t copy_token(const char **buf,
+ char *token,
+ size_t token_size)
+{
+ size_t len;
+
+ len = next_token(buf);
+ if (len < token_size) {
+ memcpy(token, *buf, len);
+ *(token + len) = '\0';
+ }
+ *buf += len;
+
+ return len;
+}
+
+/*
+ * This fills in the pool_name, obj, obj_len, snap_name, obj_len,
+ * rbd_dev, rbd_md_name, and name fields of the given rbd_dev, based
+ * on the list of monitor addresses and other options provided via
+ * /sys/bus/rbd/add.
+ */
+static int rbd_add_parse_args(struct rbd_device *rbd_dev,
+ const char *buf,
+ const char **mon_addrs,
+ size_t *mon_addrs_size,
+ char *options,
+ size_t options_size)
+{
+ size_t len;
+
+ /* The first four tokens are required */
+
+ len = next_token(&buf);
+ if (!len)
+ return -EINVAL;
+ *mon_addrs_size = len + 1;
+ *mon_addrs = buf;
+
+ buf += len;
+
+ len = copy_token(&buf, options, options_size);
+ if (!len || len >= options_size)
+ return -EINVAL;
+
+ len = copy_token(&buf, rbd_dev->pool_name, sizeof (rbd_dev->pool_name));
+ if (!len || len >= sizeof (rbd_dev->pool_name))
+ return -EINVAL;
+
+ len = copy_token(&buf, rbd_dev->obj, sizeof (rbd_dev->obj));
+ if (!len || len >= sizeof (rbd_dev->obj))
+ return -EINVAL;
+
+ /* We have the object length in hand, save it. */
+
+ rbd_dev->obj_len = len;
+
+ BUILD_BUG_ON(RBD_MAX_MD_NAME_LEN
+ < RBD_MAX_OBJ_NAME_LEN + sizeof (RBD_SUFFIX));
+ sprintf(rbd_dev->obj_md_name, "%s%s", rbd_dev->obj, RBD_SUFFIX);
+
+ /*
+ * The snapshot name is optional, but it's an error if it's
+ * too long. If no snapshot is supplied, fill in the default.
+ */
+ len = copy_token(&buf, rbd_dev->snap_name, sizeof (rbd_dev->snap_name));
+ if (!len)
+ memcpy(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME,
+ sizeof (RBD_SNAP_HEAD_NAME));
+ else if (len >= sizeof (rbd_dev->snap_name))
+ return -EINVAL;
+
+ return 0;
+}
+
static ssize_t rbd_add(struct bus_type *bus,
const char *buf,
size_t count)
{
- struct ceph_osd_client *osdc;
struct rbd_device *rbd_dev;
- ssize_t rc = -ENOMEM;
- int irc, new_id = 0;
- struct list_head *tmp;
- char *mon_dev_name;
- char *options;
+ const char *mon_addrs = NULL;
+ size_t mon_addrs_size = 0;
+ char *options = NULL;
+ struct ceph_osd_client *osdc;
+ int rc = -ENOMEM;
if (!try_module_get(THIS_MODULE))
return -ENODEV;
- mon_dev_name = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
- if (!mon_dev_name)
- goto err_out_mod;
-
- options = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
- if (!options)
- goto err_mon_dev;
-
- /* new rbd_device object */
rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
if (!rbd_dev)
- goto err_out_opt;
+ goto err_nomem;
+ options = kmalloc(count, GFP_KERNEL);
+ if (!options)
+ goto err_nomem;
/* static rbd_device initialization */
spin_lock_init(&rbd_dev->lock);
INIT_LIST_HEAD(&rbd_dev->node);
INIT_LIST_HEAD(&rbd_dev->snaps);
+ init_rwsem(&rbd_dev->header_rwsem);
- init_rwsem(&rbd_dev->header.snap_rwsem);
+ init_rwsem(&rbd_dev->header_rwsem);
/* generate unique id: find highest unique id, add one */
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- list_for_each(tmp, &rbd_dev_list) {
- struct rbd_device *rbd_dev;
+ rbd_id_get(rbd_dev);
- rbd_dev = list_entry(tmp, struct rbd_device, node);
- if (rbd_dev->id >= new_id)
- new_id = rbd_dev->id + 1;
- }
-
- rbd_dev->id = new_id;
-
- /* add to global list */
- list_add_tail(&rbd_dev->node, &rbd_dev_list);
+ /* Fill in the device name, now that we have its id. */
+ BUILD_BUG_ON(DEV_NAME_LEN
+ < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH);
+ sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->id);
/* parse add command */
- if (sscanf(buf, "%" __stringify(RBD_MAX_OPT_LEN) "s "
- "%" __stringify(RBD_MAX_OPT_LEN) "s "
- "%" __stringify(RBD_MAX_POOL_NAME_LEN) "s "
- "%" __stringify(RBD_MAX_OBJ_NAME_LEN) "s"
- "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
- mon_dev_name, options, rbd_dev->pool_name,
- rbd_dev->obj, rbd_dev->snap_name) < 4) {
- rc = -EINVAL;
- goto err_out_slot;
- }
-
- if (rbd_dev->snap_name[0] == 0)
- rbd_dev->snap_name[0] = '-';
-
- rbd_dev->obj_len = strlen(rbd_dev->obj);
- snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s",
- rbd_dev->obj, RBD_SUFFIX);
-
- /* initialize rest of new object */
- snprintf(rbd_dev->name, DEV_NAME_LEN, DRV_NAME "%d", rbd_dev->id);
- rc = rbd_get_client(rbd_dev, mon_dev_name, options);
- if (rc < 0)
- goto err_out_slot;
+ rc = rbd_add_parse_args(rbd_dev, buf, &mon_addrs, &mon_addrs_size,
+ options, count);
+ if (rc)
+ goto err_put_id;
- mutex_unlock(&ctl_mutex);
+ rbd_dev->rbd_client = rbd_get_client(mon_addrs, mon_addrs_size - 1,
+ options);
+ if (IS_ERR(rbd_dev->rbd_client)) {
+ rc = PTR_ERR(rbd_dev->rbd_client);
+ goto err_put_id;
+ }
/* pick the pool */
- osdc = &rbd_dev->client->osdc;
+ osdc = &rbd_dev->rbd_client->client->osdc;
rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name);
if (rc < 0)
goto err_out_client;
rbd_dev->poolid = rc;
/* register our block device */
- irc = register_blkdev(0, rbd_dev->name);
- if (irc < 0) {
- rc = irc;
+ rc = register_blkdev(0, rbd_dev->name);
+ if (rc < 0)
goto err_out_client;
- }
- rbd_dev->major = irc;
+ rbd_dev->major = rc;
rc = rbd_bus_add_dev(rbd_dev);
if (rc)
goto err_out_blkdev;
- /* set up and announce blkdev mapping */
+ /*
+ * At this point cleanup in the event of an error is the job
+ * of the sysfs code (initiated by rbd_bus_del_dev()).
+ *
+ * Set up and announce blkdev mapping.
+ */
rc = rbd_init_disk(rbd_dev);
if (rc)
goto err_out_bus;
@@ -2263,35 +2438,26 @@ static ssize_t rbd_add(struct bus_type *bus,
return count;
err_out_bus:
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- list_del_init(&rbd_dev->node);
- mutex_unlock(&ctl_mutex);
-
/* this will also clean up rest of rbd_dev stuff */
rbd_bus_del_dev(rbd_dev);
kfree(options);
- kfree(mon_dev_name);
return rc;
err_out_blkdev:
unregister_blkdev(rbd_dev->major, rbd_dev->name);
err_out_client:
rbd_put_client(rbd_dev);
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-err_out_slot:
- list_del_init(&rbd_dev->node);
- mutex_unlock(&ctl_mutex);
-
- kfree(rbd_dev);
-err_out_opt:
+err_put_id:
+ rbd_id_put(rbd_dev);
+err_nomem:
kfree(options);
-err_mon_dev:
- kfree(mon_dev_name);
-err_out_mod:
+ kfree(rbd_dev);
+
dout("Error adding device %s\n", buf);
module_put(THIS_MODULE);
- return rc;
+
+ return (ssize_t) rc;
}
static struct rbd_device *__rbd_get_dev(unsigned long id)
@@ -2299,22 +2465,28 @@ static struct rbd_device *__rbd_get_dev(unsigned long id)
struct list_head *tmp;
struct rbd_device *rbd_dev;
+ spin_lock(&rbd_dev_list_lock);
list_for_each(tmp, &rbd_dev_list) {
rbd_dev = list_entry(tmp, struct rbd_device, node);
- if (rbd_dev->id == id)
+ if (rbd_dev->id == id) {
+ spin_unlock(&rbd_dev_list_lock);
return rbd_dev;
+ }
}
+ spin_unlock(&rbd_dev_list_lock);
return NULL;
}
static void rbd_dev_release(struct device *dev)
{
- struct rbd_device *rbd_dev =
- container_of(dev, struct rbd_device, dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
- if (rbd_dev->watch_request)
- ceph_osdc_unregister_linger_request(&rbd_dev->client->osdc,
+ if (rbd_dev->watch_request) {
+ struct ceph_client *client = rbd_dev->rbd_client->client;
+
+ ceph_osdc_unregister_linger_request(&client->osdc,
rbd_dev->watch_request);
+ }
if (rbd_dev->watch_event)
rbd_req_sync_unwatch(rbd_dev, rbd_dev->obj_md_name);
@@ -2323,6 +2495,9 @@ static void rbd_dev_release(struct device *dev)
/* clean up and free blkdev */
rbd_free_disk(rbd_dev);
unregister_blkdev(rbd_dev->major, rbd_dev->name);
+
+ /* done with the id, and with the rbd_dev */
+ rbd_id_put(rbd_dev);
kfree(rbd_dev);
/* release module ref */
@@ -2355,8 +2530,6 @@ static ssize_t rbd_remove(struct bus_type *bus,
goto done;
}
- list_del_init(&rbd_dev->node);
-
__rbd_remove_all_snaps(rbd_dev);
rbd_bus_del_dev(rbd_dev);
@@ -2370,7 +2543,7 @@ static ssize_t rbd_snap_add(struct device *dev,
const char *buf,
size_t count)
{
- struct rbd_device *rbd_dev = dev_to_rbd(dev);
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
int ret;
char *name = kmalloc(count + 1, GFP_KERNEL);
if (!name)
@@ -2406,12 +2579,6 @@ err_unlock:
return ret;
}
-static struct bus_attribute rbd_bus_attrs[] = {
- __ATTR(add, S_IWUSR, NULL, rbd_add),
- __ATTR(remove, S_IWUSR, NULL, rbd_remove),
- __ATTR_NULL
-};
-
/*
* create control files in sysfs
* /sys/bus/rbd/...
@@ -2420,21 +2587,21 @@ static int rbd_sysfs_init(void)
{
int ret;
- rbd_bus_type.bus_attrs = rbd_bus_attrs;
-
- ret = bus_register(&rbd_bus_type);
- if (ret < 0)
+ ret = device_register(&rbd_root_dev);
+ if (ret < 0)
return ret;
- ret = device_register(&rbd_root_dev);
+ ret = bus_register(&rbd_bus_type);
+ if (ret < 0)
+ device_unregister(&rbd_root_dev);
return ret;
}
static void rbd_sysfs_cleanup(void)
{
- device_unregister(&rbd_root_dev);
bus_unregister(&rbd_bus_type);
+ device_unregister(&rbd_root_dev);
}
int __init rbd_init(void)
@@ -2444,8 +2611,7 @@ int __init rbd_init(void)
rc = rbd_sysfs_init();
if (rc)
return rc;
- spin_lock_init(&node_lock);
- pr_info("loaded " DRV_NAME_LONG "\n");
+ pr_info("loaded " RBD_DRV_NAME_LONG "\n");
return 0;
}
diff --git a/drivers/block/rbd_types.h b/drivers/block/rbd_types.h
index fc6c678aa2cb..950708688f17 100644
--- a/drivers/block/rbd_types.h
+++ b/drivers/block/rbd_types.h
@@ -41,10 +41,6 @@
#define RBD_HEADER_SIGNATURE "RBD"
#define RBD_HEADER_VERSION "001.005"
-struct rbd_info {
- __le64 max_id;
-} __attribute__ ((packed));
-
struct rbd_image_snap_ondisk {
__le64 id;
__le64 image_size;
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 48e8fee9f2d4..9dcf76a10bb6 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -839,10 +839,7 @@ static struct vio_driver vdc_port_driver = {
.id_table = vdc_port_match,
.probe = vdc_port_probe,
.remove = vdc_port_remove,
- .driver = {
- .name = "vdc_port",
- .owner = THIS_MODULE,
- }
+ .name = "vdc_port",
};
static int __init vdc_init(void)
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 51a972704db5..ff540520bada 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -52,7 +52,6 @@
#include <linux/io.h>
#include <linux/gfp.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 9c09d6f05dc9..308c8599ab55 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -39,7 +39,6 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <linux/device.h>
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 194224d07f7c..c4fc2f3fc32c 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -38,7 +38,6 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 049c0594a76b..6e8d96189684 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -38,7 +38,6 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index f4837a893dfa..57501ca9204b 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -31,7 +31,6 @@
#include <linux/kthread.h>
#include <linux/delay.h>
-#include <asm/system.h>
/*
* The apm_bios device is one of the misc char devices.
diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c
index ed8303f9890c..7d34b203718a 100644
--- a/drivers/char/ds1302.c
+++ b/drivers/char/ds1302.c
@@ -24,7 +24,6 @@
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <asm/rtc.h>
#if defined(CONFIG_M32R)
#include <asm/m32r.h>
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 53c524e7b829..a082d00b0f11 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -37,7 +37,6 @@
#include <linux/efi.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define EFI_RTC_VERSION "0.4"
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index f773a9dd14f3..21cb980f1157 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -56,7 +56,6 @@
#include <linux/workqueue.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/rtc.h>
/*
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0833896cf6f2..3845ab44c330 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -36,7 +36,6 @@
#include <linux/io.h>
#include <asm/current.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/div64.h>
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 2aa3977aae5e..9eb360ff8cab 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
-#include <asm/system.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index cf82fedae099..e53fc24c6af3 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -118,8 +118,8 @@ enum kcs_states {
#define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH
/* Timeouts in microseconds. */
-#define IBF_RETRY_TIMEOUT 1000000
-#define OBF_RETRY_TIMEOUT 1000000
+#define IBF_RETRY_TIMEOUT 5000000
+#define OBF_RETRY_TIMEOUT 5000000
#define MAX_ERROR_RETRIES 10
#define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 58c0e6387cf7..2c29942b1326 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/errno.h>
-#include <asm/system.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
@@ -46,6 +45,7 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/rcupdate.h>
+#include <linux/interrupt.h>
#define PFX "IPMI message handler: "
@@ -53,6 +53,8 @@
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
+static void smi_recv_tasklet(unsigned long);
+static void handle_new_recv_msgs(ipmi_smi_t intf);
static int initialized;
@@ -355,12 +357,15 @@ struct ipmi_smi {
int curr_seq;
/*
- * Messages that were delayed for some reason (out of memory,
- * for instance), will go in here to be processed later in a
- * periodic timer interrupt.
+ * Messages queued for delivery. If delivery fails (out of memory
+ * for instance), They will stay in here to be processed later in a
+ * periodic timer interrupt. The tasklet is for handling received
+ * messages directly from the handler.
*/
spinlock_t waiting_msgs_lock;
struct list_head waiting_msgs;
+ atomic_t watchdog_pretimeouts_to_deliver;
+ struct tasklet_struct recv_tasklet;
/*
* The list of command receivers that are registered for commands
@@ -493,6 +498,8 @@ static void clean_up_interface_data(ipmi_smi_t intf)
struct cmd_rcvr *rcvr, *rcvr2;
struct list_head list;
+ tasklet_kill(&intf->recv_tasklet);
+
free_smi_msg_list(&intf->waiting_msgs);
free_recv_msg_list(&intf->waiting_events);
@@ -2786,12 +2793,17 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
return;
}
-void ipmi_poll_interface(ipmi_user_t user)
+static void ipmi_poll(ipmi_smi_t intf)
{
- ipmi_smi_t intf = user->intf;
-
if (intf->handlers->poll)
intf->handlers->poll(intf->send_info);
+ /* In case something came in */
+ handle_new_recv_msgs(intf);
+}
+
+void ipmi_poll_interface(ipmi_user_t user)
+{
+ ipmi_poll(user->intf);
}
EXPORT_SYMBOL(ipmi_poll_interface);
@@ -2860,6 +2872,10 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
#endif
spin_lock_init(&intf->waiting_msgs_lock);
INIT_LIST_HEAD(&intf->waiting_msgs);
+ tasklet_init(&intf->recv_tasklet,
+ smi_recv_tasklet,
+ (unsigned long) intf);
+ atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);
spin_lock_init(&intf->events_lock);
INIT_LIST_HEAD(&intf->waiting_events);
intf->waiting_events_count = 0;
@@ -3622,11 +3638,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
}
/*
- * Handle a new message. Return 1 if the message should be requeued,
+ * Handle a received message. Return 1 if the message should be requeued,
* 0 if the message should be freed, or -1 if the message should not
* be freed or requeued.
*/
-static int handle_new_recv_msg(ipmi_smi_t intf,
+static int handle_one_recv_msg(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
int requeue;
@@ -3784,12 +3800,72 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
return requeue;
}
+/*
+ * If there are messages in the queue or pretimeouts, handle them.
+ */
+static void handle_new_recv_msgs(ipmi_smi_t intf)
+{
+ struct ipmi_smi_msg *smi_msg;
+ unsigned long flags = 0;
+ int rv;
+ int run_to_completion = intf->run_to_completion;
+
+ /* See if any waiting messages need to be processed. */
+ if (!run_to_completion)
+ spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+ while (!list_empty(&intf->waiting_msgs)) {
+ smi_msg = list_entry(intf->waiting_msgs.next,
+ struct ipmi_smi_msg, link);
+ list_del(&smi_msg->link);
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+ rv = handle_one_recv_msg(intf, smi_msg);
+ if (!run_to_completion)
+ spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+ if (rv == 0) {
+ /* Message handled */
+ ipmi_free_smi_msg(smi_msg);
+ } else if (rv < 0) {
+ /* Fatal error on the message, del but don't free. */
+ } else {
+ /*
+ * To preserve message order, quit if we
+ * can't handle a message.
+ */
+ list_add(&smi_msg->link, &intf->waiting_msgs);
+ break;
+ }
+ }
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+
+ /*
+ * If the pretimout count is non-zero, decrement one from it and
+ * deliver pretimeouts to all the users.
+ */
+ if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) {
+ ipmi_user_t user;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(user, &intf->users, link) {
+ if (user->handler->ipmi_watchdog_pretimeout)
+ user->handler->ipmi_watchdog_pretimeout(
+ user->handler_data);
+ }
+ rcu_read_unlock();
+ }
+}
+
+static void smi_recv_tasklet(unsigned long val)
+{
+ handle_new_recv_msgs((ipmi_smi_t) val);
+}
+
/* Handle a new message from the lower layer. */
void ipmi_smi_msg_received(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
unsigned long flags = 0; /* keep us warning-free. */
- int rv;
int run_to_completion;
@@ -3843,31 +3919,11 @@ void ipmi_smi_msg_received(ipmi_smi_t intf,
run_to_completion = intf->run_to_completion;
if (!run_to_completion)
spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
- if (!list_empty(&intf->waiting_msgs)) {
- list_add_tail(&msg->link, &intf->waiting_msgs);
- if (!run_to_completion)
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
- goto out;
- }
+ list_add_tail(&msg->link, &intf->waiting_msgs);
if (!run_to_completion)
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
- rv = handle_new_recv_msg(intf, msg);
- if (rv > 0) {
- /*
- * Could not handle the message now, just add it to a
- * list to handle later.
- */
- run_to_completion = intf->run_to_completion;
- if (!run_to_completion)
- spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
- list_add_tail(&msg->link, &intf->waiting_msgs);
- if (!run_to_completion)
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
- } else if (rv == 0) {
- ipmi_free_smi_msg(msg);
- }
-
+ tasklet_schedule(&intf->recv_tasklet);
out:
return;
}
@@ -3875,16 +3931,8 @@ EXPORT_SYMBOL(ipmi_smi_msg_received);
void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
{
- ipmi_user_t user;
-
- rcu_read_lock();
- list_for_each_entry_rcu(user, &intf->users, link) {
- if (!user->handler->ipmi_watchdog_pretimeout)
- continue;
-
- user->handler->ipmi_watchdog_pretimeout(user->handler_data);
- }
- rcu_read_unlock();
+ atomic_set(&intf->watchdog_pretimeouts_to_deliver, 1);
+ tasklet_schedule(&intf->recv_tasklet);
}
EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
@@ -3998,28 +4046,12 @@ static void ipmi_timeout_handler(long timeout_period)
ipmi_smi_t intf;
struct list_head timeouts;
struct ipmi_recv_msg *msg, *msg2;
- struct ipmi_smi_msg *smi_msg, *smi_msg2;
unsigned long flags;
int i;
rcu_read_lock();
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
- /* See if any waiting messages need to be processed. */
- spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
- list_for_each_entry_safe(smi_msg, smi_msg2,
- &intf->waiting_msgs, link) {
- if (!handle_new_recv_msg(intf, smi_msg)) {
- list_del(&smi_msg->link);
- ipmi_free_smi_msg(smi_msg);
- } else {
- /*
- * To preserve message order, quit if we
- * can't handle a message.
- */
- break;
- }
- }
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+ tasklet_schedule(&intf->recv_tasklet);
/*
* Go through the seq table and find any messages that
@@ -4173,12 +4205,48 @@ EXPORT_SYMBOL(ipmi_free_recv_msg);
#ifdef CONFIG_IPMI_PANIC_EVENT
+static atomic_t panic_done_count = ATOMIC_INIT(0);
+
static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
{
+ atomic_dec(&panic_done_count);
}
static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
{
+ atomic_dec(&panic_done_count);
+}
+
+/*
+ * Inside a panic, send a message and wait for a response.
+ */
+static void ipmi_panic_request_and_wait(ipmi_smi_t intf,
+ struct ipmi_addr *addr,
+ struct kernel_ipmi_msg *msg)
+{
+ struct ipmi_smi_msg smi_msg;
+ struct ipmi_recv_msg recv_msg;
+ int rv;
+
+ smi_msg.done = dummy_smi_done_handler;
+ recv_msg.done = dummy_recv_done_handler;
+ atomic_add(2, &panic_done_count);
+ rv = i_ipmi_request(NULL,
+ intf,
+ addr,
+ 0,
+ msg,
+ intf,
+ &smi_msg,
+ &recv_msg,
+ 0,
+ intf->channels[0].address,
+ intf->channels[0].lun,
+ 0, 1); /* Don't retry, and don't wait. */
+ if (rv)
+ atomic_sub(2, &panic_done_count);
+ while (atomic_read(&panic_done_count) != 0)
+ ipmi_poll(intf);
}
#ifdef CONFIG_IPMI_PANIC_STRING
@@ -4217,8 +4285,6 @@ static void send_panic_events(char *str)
unsigned char data[16];
struct ipmi_system_interface_addr *si;
struct ipmi_addr addr;
- struct ipmi_smi_msg smi_msg;
- struct ipmi_recv_msg recv_msg;
si = (struct ipmi_system_interface_addr *) &addr;
si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
@@ -4246,9 +4312,6 @@ static void send_panic_events(char *str)
data[7] = str[2];
}
- smi_msg.done = dummy_smi_done_handler;
- recv_msg.done = dummy_recv_done_handler;
-
/* For every registered interface, send the event. */
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
if (!intf->handlers)
@@ -4258,18 +4321,7 @@ static void send_panic_events(char *str)
intf->run_to_completion = 1;
/* Send the event announcing the panic. */
intf->handlers->set_run_to_completion(intf->send_info, 1);
- i_ipmi_request(NULL,
- intf,
- &addr,
- 0,
- &msg,
- intf,
- &smi_msg,
- &recv_msg,
- 0,
- intf->channels[0].address,
- intf->channels[0].lun,
- 0, 1); /* Don't retry, and don't wait. */
+ ipmi_panic_request_and_wait(intf, &addr, &msg);
}
#ifdef CONFIG_IPMI_PANIC_STRING
@@ -4317,18 +4369,7 @@ static void send_panic_events(char *str)
msg.data = NULL;
msg.data_len = 0;
intf->null_user_handler = device_id_fetcher;
- i_ipmi_request(NULL,
- intf,
- &addr,
- 0,
- &msg,
- intf,
- &smi_msg,
- &recv_msg,
- 0,
- intf->channels[0].address,
- intf->channels[0].lun,
- 0, 1); /* Don't retry, and don't wait. */
+ ipmi_panic_request_and_wait(intf, &addr, &msg);
if (intf->local_event_generator) {
/* Request the event receiver from the local MC. */
@@ -4337,18 +4378,7 @@ static void send_panic_events(char *str)
msg.data = NULL;
msg.data_len = 0;
intf->null_user_handler = event_receiver_fetcher;
- i_ipmi_request(NULL,
- intf,
- &addr,
- 0,
- &msg,
- intf,
- &smi_msg,
- &recv_msg,
- 0,
- intf->channels[0].address,
- intf->channels[0].lun,
- 0, 1); /* no retry, and no wait. */
+ ipmi_panic_request_and_wait(intf, &addr, &msg);
}
intf->null_user_handler = NULL;
@@ -4405,18 +4435,7 @@ static void send_panic_events(char *str)
strncpy(data+5, p, 11);
p += size;
- i_ipmi_request(NULL,
- intf,
- &addr,
- 0,
- &msg,
- intf,
- &smi_msg,
- &recv_msg,
- 0,
- intf->channels[0].address,
- intf->channels[0].lun,
- 0, 1); /* no retry, and no wait. */
+ ipmi_panic_request_and_wait(intf, &addr, &msg);
}
}
#endif /* CONFIG_IPMI_PANIC_STRING */
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 50fcf9c04569..1e638fff40ea 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -41,7 +41,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <asm/system.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/timer.h>
@@ -171,7 +170,6 @@ struct smi_info {
struct si_sm_handlers *handlers;
enum si_type si_type;
spinlock_t si_lock;
- spinlock_t msg_lock;
struct list_head xmit_msgs;
struct list_head hp_xmit_msgs;
struct ipmi_smi_msg *curr_msg;
@@ -320,16 +318,8 @@ static int register_xaction_notifier(struct notifier_block *nb)
static void deliver_recv_msg(struct smi_info *smi_info,
struct ipmi_smi_msg *msg)
{
- /* Deliver the message to the upper layer with the lock
- released. */
-
- if (smi_info->run_to_completion) {
- ipmi_smi_msg_received(smi_info->intf, msg);
- } else {
- spin_unlock(&(smi_info->si_lock));
- ipmi_smi_msg_received(smi_info->intf, msg);
- spin_lock(&(smi_info->si_lock));
- }
+ /* Deliver the message to the upper layer. */
+ ipmi_smi_msg_received(smi_info->intf, msg);
}
static void return_hosed_msg(struct smi_info *smi_info, int cCode)
@@ -358,13 +348,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
struct timeval t;
#endif
- /*
- * No need to save flags, we aleady have interrupts off and we
- * already hold the SMI lock.
- */
- if (!smi_info->run_to_completion)
- spin_lock(&(smi_info->msg_lock));
-
/* Pick the high priority queue first. */
if (!list_empty(&(smi_info->hp_xmit_msgs))) {
entry = smi_info->hp_xmit_msgs.next;
@@ -402,9 +385,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
rv = SI_SM_CALL_WITHOUT_DELAY;
}
out:
- if (!smi_info->run_to_completion)
- spin_unlock(&(smi_info->msg_lock));
-
return rv;
}
@@ -481,9 +461,7 @@ static void handle_flags(struct smi_info *smi_info)
start_clear_flags(smi_info);
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
- spin_unlock(&(smi_info->si_lock));
ipmi_smi_watchdog_pretimeout(smi_info->intf);
- spin_lock(&(smi_info->si_lock));
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */
smi_info->curr_msg = ipmi_alloc_smi_msg();
@@ -889,19 +867,6 @@ static void sender(void *send_info,
printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
- /*
- * last_timeout_jiffies is updated here to avoid
- * smi_timeout() handler passing very large time_diff
- * value to smi_event_handler() that causes
- * the send command to abort.
- */
- smi_info->last_timeout_jiffies = jiffies;
-
- mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
-
- if (smi_info->thread)
- wake_up_process(smi_info->thread);
-
if (smi_info->run_to_completion) {
/*
* If we are running to completion, then throw it in
@@ -924,16 +889,29 @@ static void sender(void *send_info,
return;
}
- spin_lock_irqsave(&smi_info->msg_lock, flags);
+ spin_lock_irqsave(&smi_info->si_lock, flags);
if (priority > 0)
list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
else
list_add_tail(&msg->link, &smi_info->xmit_msgs);
- spin_unlock_irqrestore(&smi_info->msg_lock, flags);
- spin_lock_irqsave(&smi_info->si_lock, flags);
- if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL)
+ if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
+ /*
+ * last_timeout_jiffies is updated here to avoid
+ * smi_timeout() handler passing very large time_diff
+ * value to smi_event_handler() that causes
+ * the send command to abort.
+ */
+ smi_info->last_timeout_jiffies = jiffies;
+
+ mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
+
+ if (smi_info->thread)
+ wake_up_process(smi_info->thread);
+
start_next_msg(smi_info);
+ smi_event_handler(smi_info, 0);
+ }
spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
@@ -1034,16 +1012,19 @@ static int ipmi_thread(void *data)
static void poll(void *send_info)
{
struct smi_info *smi_info = send_info;
- unsigned long flags;
+ unsigned long flags = 0;
+ int run_to_completion = smi_info->run_to_completion;
/*
* Make sure there is some delay in the poll loop so we can
* drive time forward and timeout things.
*/
udelay(10);
- spin_lock_irqsave(&smi_info->si_lock, flags);
+ if (!run_to_completion)
+ spin_lock_irqsave(&smi_info->si_lock, flags);
smi_event_handler(smi_info, 10);
- spin_unlock_irqrestore(&smi_info->si_lock, flags);
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
static void request_events(void *send_info)
@@ -1680,10 +1661,8 @@ static struct smi_info *smi_info_alloc(void)
{
struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (info) {
+ if (info)
spin_lock_init(&info->si_lock);
- spin_lock_init(&info->msg_lock);
- }
return info;
}
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 34767a6d7f42..7ed356e52035 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -153,7 +153,7 @@
#endif
static DEFINE_MUTEX(ipmi_watchdog_mutex);
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static ipmi_user_t watchdog_user;
static int watchdog_ifnum;
@@ -320,7 +320,7 @@ module_param(start_now, int, 0444);
MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as"
"soon as the driver is loaded.");
-module_param(nowayout, int, 0644);
+module_param(nowayout, bool, 0644);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=CONFIG_WATCHDOG_NOWAYOUT)");
@@ -520,6 +520,7 @@ static void panic_halt_ipmi_heartbeat(void)
msg.cmd = IPMI_WDOG_RESET_TIMER;
msg.data = NULL;
msg.data_len = 0;
+ atomic_add(2, &panic_done_count);
rv = ipmi_request_supply_msgs(watchdog_user,
(struct ipmi_addr *) &addr,
0,
@@ -528,8 +529,8 @@ static void panic_halt_ipmi_heartbeat(void)
&panic_halt_heartbeat_smi_msg,
&panic_halt_heartbeat_recv_msg,
1);
- if (!rv)
- atomic_add(2, &panic_done_count);
+ if (rv)
+ atomic_sub(2, &panic_done_count);
}
static struct ipmi_smi_msg panic_halt_smi_msg = {
@@ -553,16 +554,18 @@ static void panic_halt_ipmi_set_timeout(void)
/* Wait for the messages to be free. */
while (atomic_read(&panic_done_count) != 0)
ipmi_poll_interface(watchdog_user);
+ atomic_add(2, &panic_done_count);
rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
&panic_halt_recv_msg,
&send_heartbeat_now);
- if (!rv) {
- atomic_add(2, &panic_done_count);
- if (send_heartbeat_now)
- panic_halt_ipmi_heartbeat();
- } else
+ if (rv) {
+ atomic_sub(2, &panic_done_count);
printk(KERN_WARNING PFX
"Unable to extend the watchdog timeout.");
+ } else {
+ if (send_heartbeat_now)
+ panic_halt_ipmi_heartbeat();
+ }
while (atomic_read(&panic_done_count) != 0)
ipmi_poll_interface(watchdog_user);
}
@@ -1164,7 +1167,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
if (code == SYS_POWER_OFF || code == SYS_HALT) {
/* Disable the WDT if we are shutting down. */
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
- panic_halt_ipmi_set_timeout();
+ ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
/* Set a long timer to let the reboot happens, but
reboot if it hangs, but only if the watchdog
@@ -1172,7 +1175,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
timeout = 120;
pretimeout = 0;
ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
- panic_halt_ipmi_set_timeout();
+ ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
}
}
return NOTIFY_OK;
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index f43485607063..a741e418b456 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -135,7 +135,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
/* if you have more than 8 printers, remember to increase LP_NO */
#define LP_NO 8
@@ -706,16 +705,13 @@ static long lp_compat_ioctl(struct file *file, unsigned int cmd,
{
unsigned int minor;
struct timeval par_timeout;
- struct compat_timeval __user *tc;
int ret;
minor = iminor(file->f_path.dentry->d_inode);
mutex_lock(&lp_mutex);
switch (cmd) {
case LPSETTIMEOUT:
- tc = compat_ptr(arg);
- if (get_user(par_timeout.tv_sec, &tc->tv_sec) ||
- get_user(par_timeout.tv_usec, &tc->tv_usec)) {
+ if (compat_get_timeval(&par_timeout, compat_ptr(arg))) {
ret = -EFAULT;
break;
}
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 1aeaaba680d2..47ff7e470d87 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -28,7 +28,6 @@
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/sn/addrs.h>
#include <asm/sn/intr.h>
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 5c0d96a820fa..8b78750f1efe 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -44,7 +44,6 @@
#include <linux/slab.h>
#include <linux/numa.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <asm/pgtable.h>
#include <linux/atomic.h>
#include <asm/tlbflush.h>
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index 492dbfb2efd6..881c9e595939 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -56,7 +56,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include "smapi.h"
#include "mwavedd.h"
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index eaade8a1ecd7..9df78e2cc45d 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -111,7 +111,6 @@
#include <linux/uaccess.h>
#include <linux/mutex.h>
-#include <asm/system.h>
static DEFINE_MUTEX(nvram_mutex);
static DEFINE_SPINLOCK(nvram_state_lock);
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index bf586ae1ee83..d45c3345b4af 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -32,7 +32,6 @@
#include <asm/io.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
/*****************************************************************************/
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index f6453df4921c..0a484b4a1b02 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -60,7 +60,6 @@
#include <linux/ioctl.h>
#include <linux/synclink.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 872e09a02d23..af9437488b6c 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -83,7 +83,6 @@
#include <linux/ratelimit.h>
#include <asm/current.h>
-#include <asm/system.h>
#ifdef CONFIG_X86
#include <asm/hpet.h>
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 1ee8ce7d2762..45713f0e7d61 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -54,7 +54,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/sonypi.h>
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index e90e1c74fd4c..31ba11ca75e1 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -89,7 +89,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#ifdef CONFIG_OF
/* For open firmware. */
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 9b3cd08cd0ed..165e1febae53 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -8,3 +8,40 @@ config HAVE_CLK_PREPARE
config HAVE_MACH_CLKDEV
bool
+
+config COMMON_CLK
+ bool
+ select HAVE_CLK_PREPARE
+ ---help---
+ The common clock framework is a single definition of struct
+ clk, useful across many platforms, as well as an
+ implementation of the clock API in include/linux/clk.h.
+ Architectures utilizing the common struct clk should select
+ this option.
+
+menu "Common Clock Framework"
+ depends on COMMON_CLK
+
+config COMMON_CLK_DISABLE_UNUSED
+ bool "Disabled unused clocks at boot"
+ depends on COMMON_CLK
+ ---help---
+ Traverses the entire clock tree and disables any clocks that are
+ enabled in hardware but have not been enabled by any device drivers.
+ This saves power and keeps the software model of the clock in line
+ with reality.
+
+ If in doubt, say "N".
+
+config COMMON_CLK_DEBUG
+ bool "DebugFS representation of clock tree"
+ depends on COMMON_CLK
+ select DEBUG_FS
+ ---help---
+ Creates a directory hierchy in debugfs for visualizing the clk
+ tree structure. Each directory contains read-only members
+ that export information specific to that clk node: clk_rate,
+ clk_flags, clk_prepare_count, clk_enable_count &
+ clk_notifier_count.
+
+endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa172c9..1f736bc11c4b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,4 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
+obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
+ clk-mux.o clk-divider.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
new file mode 100644
index 000000000000..d5ac6a75ea57
--- /dev/null
+++ b/drivers/clk/clk-divider.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Adjustable divider clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/*
+ * DOC: basic adjustable divider clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable. clk->rate = parent->rate / divisor
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+
+#define div_mask(d) ((1 << (d->width)) - 1)
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned int div;
+
+ div = readl(divider->reg) >> divider->shift;
+ div &= div_mask(divider);
+
+ if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+ div++;
+
+ return parent_rate / div;
+}
+EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ int i, bestdiv = 0;
+ unsigned long parent_rate, best = 0, now, maxdiv;
+
+ if (!rate)
+ rate = 1;
+
+ maxdiv = (1 << divider->width);
+
+ if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ maxdiv--;
+
+ if (!best_parent_rate) {
+ parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+ bestdiv = DIV_ROUND_UP(parent_rate, rate);
+ bestdiv = bestdiv == 0 ? 1 : bestdiv;
+ bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+ return bestdiv;
+ }
+
+ /*
+ * The maximum divider we can use without overflowing
+ * unsigned long in rate * i below
+ */
+ maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+ for (i = 1; i <= maxdiv; i++) {
+ parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+ MULT_ROUND_UP(rate, i));
+ now = parent_rate / i;
+ if (now <= rate && now > best) {
+ bestdiv = i;
+ best = now;
+ *best_parent_rate = parent_rate;
+ }
+ }
+
+ if (!bestdiv) {
+ bestdiv = (1 << divider->width);
+ if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ bestdiv--;
+ *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
+ }
+
+ return bestdiv;
+}
+
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int div;
+ div = clk_divider_bestdiv(hw, rate, prate);
+
+ if (prate)
+ return *prate / div;
+ else {
+ unsigned long r;
+ r = __clk_get_rate(__clk_get_parent(hw->clk));
+ return r / div;
+ }
+}
+EXPORT_SYMBOL_GPL(clk_divider_round_rate);
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned int div;
+ unsigned long flags = 0;
+ u32 val;
+
+ div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate;
+
+ if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+ div--;
+
+ if (div > div_mask(divider))
+ div = div_mask(divider);
+
+ if (divider->lock)
+ spin_lock_irqsave(divider->lock, flags);
+
+ val = readl(divider->reg);
+ val &= ~(div_mask(divider) << divider->shift);
+ val |= div << divider->shift;
+ writel(val, divider->reg);
+
+ if (divider->lock)
+ spin_unlock_irqrestore(divider->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_divider_set_rate);
+
+struct clk_ops clk_divider_ops = {
+ .recalc_rate = clk_divider_recalc_rate,
+ .round_rate = clk_divider_round_rate,
+ .set_rate = clk_divider_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_ops);
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_divider_flags, spinlock_t *lock)
+{
+ struct clk_divider *div;
+ struct clk *clk;
+
+ div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
+
+ if (!div) {
+ pr_err("%s: could not allocate divider clk\n", __func__);
+ return NULL;
+ }
+
+ /* struct clk_divider assignments */
+ div->reg = reg;
+ div->shift = shift;
+ div->width = width;
+ div->flags = clk_divider_flags;
+ div->lock = lock;
+
+ if (parent_name) {
+ div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+ if (!div->parent[0])
+ goto out;
+ }
+
+ clk = clk_register(dev, name,
+ &clk_divider_ops, &div->hw,
+ div->parent,
+ (parent_name ? 1 : 0),
+ flags);
+ if (clk)
+ return clk;
+
+out:
+ kfree(div->parent[0]);
+ kfree(div);
+
+ return NULL;
+}
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
new file mode 100644
index 000000000000..90c79fb5d1bd
--- /dev/null
+++ b/drivers/clk/clk-fixed-rate.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Fixed rate clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic fixed-rate clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parents are prepared
+ * enable - clk_enable only ensures parents are enabled
+ * rate - rate is always a fixed value. No clk_set_rate support
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
+
+static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return to_clk_fixed_rate(hw)->fixed_rate;
+}
+EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
+
+struct clk_ops clk_fixed_rate_ops = {
+ .recalc_rate = clk_fixed_rate_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
+
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ unsigned long fixed_rate)
+{
+ struct clk_fixed_rate *fixed;
+ char **parent_names = NULL;
+ u8 len;
+
+ fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
+
+ if (!fixed) {
+ pr_err("%s: could not allocate fixed clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* struct clk_fixed_rate assignments */
+ fixed->fixed_rate = fixed_rate;
+
+ if (parent_name) {
+ parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
+
+ if (! parent_names)
+ goto out;
+
+ len = sizeof(char) * strlen(parent_name);
+
+ parent_names[0] = kmalloc(len, GFP_KERNEL);
+
+ if (!parent_names[0])
+ goto out;
+
+ strncpy(parent_names[0], parent_name, len);
+ }
+
+out:
+ return clk_register(dev, name,
+ &clk_fixed_rate_ops, &fixed->hw,
+ parent_names,
+ (parent_name ? 1 : 0),
+ flags);
+}
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
new file mode 100644
index 000000000000..b5902e2ef2fd
--- /dev/null
+++ b/drivers/clk/clk-gate.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Gated clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/**
+ * DOC: basic gatable clock which can gate and ungate it's ouput
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gating
+ * rate - inherits rate from parent. No clk_set_rate support
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+static void clk_gate_set_bit(struct clk_gate *gate)
+{
+ u32 reg;
+ unsigned long flags = 0;
+
+ if (gate->lock)
+ spin_lock_irqsave(gate->lock, flags);
+
+ reg = readl(gate->reg);
+ reg |= BIT(gate->bit_idx);
+ writel(reg, gate->reg);
+
+ if (gate->lock)
+ spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static void clk_gate_clear_bit(struct clk_gate *gate)
+{
+ u32 reg;
+ unsigned long flags = 0;
+
+ if (gate->lock)
+ spin_lock_irqsave(gate->lock, flags);
+
+ reg = readl(gate->reg);
+ reg &= ~BIT(gate->bit_idx);
+ writel(reg, gate->reg);
+
+ if (gate->lock)
+ spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static int clk_gate_enable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+
+ if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+ clk_gate_clear_bit(gate);
+ else
+ clk_gate_set_bit(gate);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_enable);
+
+static void clk_gate_disable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+
+ if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+ clk_gate_set_bit(gate);
+ else
+ clk_gate_clear_bit(gate);
+}
+EXPORT_SYMBOL_GPL(clk_gate_disable);
+
+static int clk_gate_is_enabled(struct clk_hw *hw)
+{
+ u32 reg;
+ struct clk_gate *gate = to_clk_gate(hw);
+
+ reg = readl(gate->reg);
+
+ /* if a set bit disables this clk, flip it before masking */
+ if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+ reg ^= BIT(gate->bit_idx);
+
+ reg &= BIT(gate->bit_idx);
+
+ return reg ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
+
+struct clk_ops clk_gate_ops = {
+ .enable = clk_gate_enable,
+ .disable = clk_gate_disable,
+ .is_enabled = clk_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(clk_gate_ops);
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, spinlock_t *lock)
+{
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+
+ if (!gate) {
+ pr_err("%s: could not allocate gated clk\n", __func__);
+ return NULL;
+ }
+
+ /* struct clk_gate assignments */
+ gate->reg = reg;
+ gate->bit_idx = bit_idx;
+ gate->flags = clk_gate_flags;
+ gate->lock = lock;
+
+ if (parent_name) {
+ gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+ if (!gate->parent[0])
+ goto out;
+ }
+
+ clk = clk_register(dev, name,
+ &clk_gate_ops, &gate->hw,
+ gate->parent,
+ (parent_name ? 1 : 0),
+ flags);
+ if (clk)
+ return clk;
+out:
+ kfree(gate->parent[0]);
+ kfree(gate);
+
+ return NULL;
+}
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
new file mode 100644
index 000000000000..c71ad1f41a97
--- /dev/null
+++ b/drivers/clk/clk-mux.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Simple multiplexer clock implementation
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic adjustable multiplexer clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is only affected by parent switching. No clk_set_rate support
+ * parent - parent is adjustable through clk_set_parent
+ */
+
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+
+static u8 clk_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_mux *mux = to_clk_mux(hw);
+ u32 val;
+
+ /*
+ * FIXME need a mux-specific flag to determine if val is bitwise or numeric
+ * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
+ * to 0x7 (index starts at one)
+ * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
+ * val = 0x4 really means "bit 2, index starts at bit 0"
+ */
+ val = readl(mux->reg) >> mux->shift;
+ val &= (1 << mux->width) - 1;
+
+ if (val && (mux->flags & CLK_MUX_INDEX_BIT))
+ val = ffs(val) - 1;
+
+ if (val && (mux->flags & CLK_MUX_INDEX_ONE))
+ val--;
+
+ if (val >= __clk_get_num_parents(hw->clk))
+ return -EINVAL;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_mux *mux = to_clk_mux(hw);
+ u32 val;
+ unsigned long flags = 0;
+
+ if (mux->flags & CLK_MUX_INDEX_BIT)
+ index = (1 << ffs(index));
+
+ if (mux->flags & CLK_MUX_INDEX_ONE)
+ index++;
+
+ if (mux->lock)
+ spin_lock_irqsave(mux->lock, flags);
+
+ val = readl(mux->reg);
+ val &= ~(((1 << mux->width) - 1) << mux->shift);
+ val |= index << mux->shift;
+ writel(val, mux->reg);
+
+ if (mux->lock)
+ spin_unlock_irqrestore(mux->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_mux_set_parent);
+
+struct clk_ops clk_mux_ops = {
+ .get_parent = clk_mux_get_parent,
+ .set_parent = clk_mux_set_parent,
+};
+EXPORT_SYMBOL_GPL(clk_mux_ops);
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+ char **parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags, spinlock_t *lock)
+{
+ struct clk_mux *mux;
+
+ mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
+
+ if (!mux) {
+ pr_err("%s: could not allocate mux clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* struct clk_mux assignments */
+ mux->reg = reg;
+ mux->shift = shift;
+ mux->width = width;
+ mux->flags = clk_mux_flags;
+ mux->lock = lock;
+
+ return clk_register(dev, name, &clk_mux_ops, &mux->hw,
+ parent_names, num_parents, flags);
+}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 000000000000..9cf6f59e3e19
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Standard functionality for the common clock API. See Documentation/clk.txt
+ */
+
+#include <linux/clk-private.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+static DEFINE_SPINLOCK(enable_lock);
+static DEFINE_MUTEX(prepare_lock);
+
+static HLIST_HEAD(clk_root_list);
+static HLIST_HEAD(clk_orphan_list);
+static LIST_HEAD(clk_notifier_list);
+
+/*** debugfs support ***/
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+#include <linux/debugfs.h>
+
+static struct dentry *rootdir;
+static struct dentry *orphandir;
+static int inited = 0;
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+{
+ struct dentry *d;
+ int ret = -ENOMEM;
+
+ if (!clk || !pdentry) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ d = debugfs_create_dir(clk->name, pdentry);
+ if (!d)
+ goto out;
+
+ clk->dentry = d;
+
+ d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry,
+ (u32 *)&clk->rate);
+ if (!d)
+ goto err_out;
+
+ d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
+ (u32 *)&clk->flags);
+ if (!d)
+ goto err_out;
+
+ d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry,
+ (u32 *)&clk->prepare_count);
+ if (!d)
+ goto err_out;
+
+ d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry,
+ (u32 *)&clk->enable_count);
+ if (!d)
+ goto err_out;
+
+ d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry,
+ (u32 *)&clk->notifier_count);
+ if (!d)
+ goto err_out;
+
+ ret = 0;
+ goto out;
+
+err_out:
+ debugfs_remove(clk->dentry);
+out:
+ return ret;
+}
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+ int ret = -EINVAL;;
+
+ if (!clk || !pdentry)
+ goto out;
+
+ ret = clk_debug_create_one(clk, pdentry);
+
+ if (ret)
+ goto out;
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node)
+ clk_debug_create_subtree(child, clk->dentry);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/**
+ * clk_debug_register - add a clk node to the debugfs clk tree
+ * @clk: the clk being added to the debugfs clk tree
+ *
+ * Dynamically adds a clk to the debugfs clk tree if debugfs has been
+ * initialized. Otherwise it bails out early since the debugfs clk tree
+ * will be created lazily by clk_debug_init as part of a late_initcall.
+ *
+ * Caller must hold prepare_lock. Only clk_init calls this function (so
+ * far) so this is taken care.
+ */
+static int clk_debug_register(struct clk *clk)
+{
+ struct clk *parent;
+ struct dentry *pdentry;
+ int ret = 0;
+
+ if (!inited)
+ goto out;
+
+ parent = clk->parent;
+
+ /*
+ * Check to see if a clk is a root clk. Also check that it is
+ * safe to add this clk to debugfs
+ */
+ if (!parent)
+ if (clk->flags & CLK_IS_ROOT)
+ pdentry = rootdir;
+ else
+ pdentry = orphandir;
+ else
+ if (parent->dentry)
+ pdentry = parent->dentry;
+ else
+ goto out;
+
+ ret = clk_debug_create_subtree(clk, pdentry);
+
+out:
+ return ret;
+}
+
+/**
+ * clk_debug_init - lazily create the debugfs clk tree visualization
+ *
+ * clks are often initialized very early during boot before memory can
+ * be dynamically allocated and well before debugfs is setup.
+ * clk_debug_init walks the clk tree hierarchy while holding
+ * prepare_lock and creates the topology as part of a late_initcall,
+ * thus insuring that clks initialized very early will still be
+ * represented in the debugfs clk tree. This function should only be
+ * called once at boot-time, and all other clks added dynamically will
+ * be done so with clk_debug_register.
+ */
+static int __init clk_debug_init(void)
+{
+ struct clk *clk;
+ struct hlist_node *tmp;
+
+ rootdir = debugfs_create_dir("clk", NULL);
+
+ if (!rootdir)
+ return -ENOMEM;
+
+ orphandir = debugfs_create_dir("orphans", rootdir);
+
+ if (!orphandir)
+ return -ENOMEM;
+
+ mutex_lock(&prepare_lock);
+
+ hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+ clk_debug_create_subtree(clk, rootdir);
+
+ hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+ clk_debug_create_subtree(clk, orphandir);
+
+ inited = 1;
+
+ mutex_unlock(&prepare_lock);
+
+ return 0;
+}
+late_initcall(clk_debug_init);
+#else
+static inline int clk_debug_register(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DEBUG */
+
+#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED
+/* caller must hold prepare_lock */
+static void clk_disable_unused_subtree(struct clk *clk)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+ unsigned long flags;
+
+ if (!clk)
+ goto out;
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node)
+ clk_disable_unused_subtree(child);
+
+ spin_lock_irqsave(&enable_lock, flags);
+
+ if (clk->enable_count)
+ goto unlock_out;
+
+ if (clk->flags & CLK_IGNORE_UNUSED)
+ goto unlock_out;
+
+ if (__clk_is_enabled(clk) && clk->ops->disable)
+ clk->ops->disable(clk->hw);
+
+unlock_out:
+ spin_unlock_irqrestore(&enable_lock, flags);
+
+out:
+ return;
+}
+
+static int clk_disable_unused(void)
+{
+ struct clk *clk;
+ struct hlist_node *tmp;
+
+ mutex_lock(&prepare_lock);
+
+ hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+ clk_disable_unused_subtree(clk);
+
+ hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+ clk_disable_unused_subtree(clk);
+
+ mutex_unlock(&prepare_lock);
+
+ return 0;
+}
+late_initcall(clk_disable_unused);
+#else
+static inline int clk_disable_unused(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */
+
+/*** helper functions ***/
+
+inline const char *__clk_get_name(struct clk *clk)
+{
+ return !clk ? NULL : clk->name;
+}
+
+inline struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+ return !clk ? NULL : clk->hw;
+}
+
+inline u8 __clk_get_num_parents(struct clk *clk)
+{
+ return !clk ? -EINVAL : clk->num_parents;
+}
+
+inline struct clk *__clk_get_parent(struct clk *clk)
+{
+ return !clk ? NULL : clk->parent;
+}
+
+inline int __clk_get_enable_count(struct clk *clk)
+{
+ return !clk ? -EINVAL : clk->enable_count;
+}
+
+inline int __clk_get_prepare_count(struct clk *clk)
+{
+ return !clk ? -EINVAL : clk->prepare_count;
+}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+ unsigned long ret;
+
+ if (!clk) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = clk->rate;
+
+ if (clk->flags & CLK_IS_ROOT)
+ goto out;
+
+ if (!clk->parent)
+ ret = -ENODEV;
+
+out:
+ return ret;
+}
+
+inline unsigned long __clk_get_flags(struct clk *clk)
+{
+ return !clk ? -EINVAL : clk->flags;
+}
+
+int __clk_is_enabled(struct clk *clk)
+{
+ int ret;
+
+ if (!clk)
+ return -EINVAL;
+
+ /*
+ * .is_enabled is only mandatory for clocks that gate
+ * fall back to software usage counter if .is_enabled is missing
+ */
+ if (!clk->ops->is_enabled) {
+ ret = clk->enable_count ? 1 : 0;
+ goto out;
+ }
+
+ ret = clk->ops->is_enabled(clk->hw);
+out:
+ return ret;
+}
+
+static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+{
+ struct clk *child;
+ struct clk *ret;
+ struct hlist_node *tmp;
+
+ if (!strcmp(clk->name, name))
+ return clk;
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+ ret = __clk_lookup_subtree(name, child);
+ if (ret)
+ return ret;
+ }
+
+ return NULL;
+}
+
+struct clk *__clk_lookup(const char *name)
+{
+ struct clk *root_clk;
+ struct clk *ret;
+ struct hlist_node *tmp;
+
+ if (!name)
+ return NULL;
+
+ /* search the 'proper' clk tree first */
+ hlist_for_each_entry(root_clk, tmp, &clk_root_list, child_node) {
+ ret = __clk_lookup_subtree(name, root_clk);
+ if (ret)
+ return ret;
+ }
+
+ /* if not found, then search the orphan tree */
+ hlist_for_each_entry(root_clk, tmp, &clk_orphan_list, child_node) {
+ ret = __clk_lookup_subtree(name, root_clk);
+ if (ret)
+ return ret;
+ }
+
+ return NULL;
+}
+
+/*** clk api ***/
+
+void __clk_unprepare(struct clk *clk)
+{
+ if (!clk)
+ return;
+
+ if (WARN_ON(clk->prepare_count == 0))
+ return;
+
+ if (--clk->prepare_count > 0)
+ return;
+
+ WARN_ON(clk->enable_count > 0);
+
+ if (clk->ops->unprepare)
+ clk->ops->unprepare(clk->hw);
+
+ __clk_unprepare(clk->parent);
+}
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: the clk being unprepare
+ *
+ * clk_unprepare may sleep, which differentiates it from clk_disable. In a
+ * simple case, clk_unprepare can be used instead of clk_disable to gate a clk
+ * if the operation may sleep. One example is a clk which is accessed over
+ * I2c. In the complex case a clk gate operation may require a fast and a slow
+ * part. It is this reason that clk_unprepare and clk_disable are not mutually
+ * exclusive. In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_unprepare(struct clk *clk)
+{
+ mutex_lock(&prepare_lock);
+ __clk_unprepare(clk);
+ mutex_unlock(&prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int __clk_prepare(struct clk *clk)
+{
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ if (clk->prepare_count == 0) {
+ ret = __clk_prepare(clk->parent);
+ if (ret)
+ return ret;
+
+ if (clk->ops->prepare) {
+ ret = clk->ops->prepare(clk->hw);
+ if (ret) {
+ __clk_unprepare(clk->parent);
+ return ret;
+ }
+ }
+ }
+
+ clk->prepare_count++;
+
+ return 0;
+}
+
+/**
+ * clk_prepare - prepare a clock source
+ * @clk: the clk being prepared
+ *
+ * clk_prepare may sleep, which differentiates it from clk_enable. In a simple
+ * case, clk_prepare can be used instead of clk_enable to ungate a clk if the
+ * operation may sleep. One example is a clk which is accessed over I2c. In
+ * the complex case a clk ungate operation may require a fast and a slow part.
+ * It is this reason that clk_prepare and clk_enable are not mutually
+ * exclusive. In fact clk_prepare must be called before clk_enable.
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_prepare(struct clk *clk)
+{
+ int ret;
+
+ mutex_lock(&prepare_lock);
+ ret = __clk_prepare(clk);
+ mutex_unlock(&prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+static void __clk_disable(struct clk *clk)
+{
+ if (!clk)
+ return;
+
+ if (WARN_ON(clk->enable_count == 0))
+ return;
+
+ if (--clk->enable_count > 0)
+ return;
+
+ if (clk->ops->disable)
+ clk->ops->disable(clk->hw);
+
+ __clk_disable(clk->parent);
+}
+
+/**
+ * clk_disable - gate a clock
+ * @clk: the clk being gated
+ *
+ * clk_disable must not sleep, which differentiates it from clk_unprepare. In
+ * a simple case, clk_disable can be used instead of clk_unprepare to gate a
+ * clk if the operation is fast and will never sleep. One example is a
+ * SoC-internal clk which is controlled via simple register writes. In the
+ * complex case a clk gate operation may require a fast and a slow part. It is
+ * this reason that clk_unprepare and clk_disable are not mutually exclusive.
+ * In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&enable_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+static int __clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ if (WARN_ON(clk->prepare_count == 0))
+ return -ESHUTDOWN;
+
+ if (clk->enable_count == 0) {
+ ret = __clk_enable(clk->parent);
+
+ if (ret)
+ return ret;
+
+ if (clk->ops->enable) {
+ ret = clk->ops->enable(clk->hw);
+ if (ret) {
+ __clk_disable(clk->parent);
+ return ret;
+ }
+ }
+ }
+
+ clk->enable_count++;
+ return 0;
+}
+
+/**
+ * clk_enable - ungate a clock
+ * @clk: the clk being ungated
+ *
+ * clk_enable must not sleep, which differentiates it from clk_prepare. In a
+ * simple case, clk_enable can be used instead of clk_prepare to ungate a clk
+ * if the operation will never sleep. One example is a SoC-internal clk which
+ * is controlled via simple register writes. In the complex case a clk ungate
+ * operation may require a fast and a slow part. It is this reason that
+ * clk_enable and clk_prepare are not mutually exclusive. In fact clk_prepare
+ * must be called before clk_enable. Returns 0 on success, -EERROR
+ * otherwise.
+ */
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&enable_lock, flags);
+ ret = __clk_enable(clk);
+ spin_unlock_irqrestore(&enable_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk. Does not query the hardware. If
+ * clk is NULL then returns -EINVAL.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+ unsigned long rate;
+
+ mutex_lock(&prepare_lock);
+ rate = __clk_get_rate(clk);
+ mutex_unlock(&prepare_lock);
+
+ return rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long unused;
+
+ if (!clk)
+ return -EINVAL;
+
+ if (!clk->ops->round_rate)
+ return clk->rate;
+
+ if (clk->flags & CLK_SET_RATE_PARENT)
+ return clk->ops->round_rate(clk->hw, rate, &unused);
+ else
+ return clk->ops->round_rate(clk->hw, rate, NULL);
+}
+
+/**
+ * clk_round_rate - round the given rate for a clk
+ * @clk: the clk for which we are rounding a rate
+ * @rate: the rate which is to be rounded
+ *
+ * Takes in a rate as input and rounds it to a rate that the clk can actually
+ * use which is then returned. If clk doesn't support round_rate operation
+ * then the parent rate is returned.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long ret;
+
+ mutex_lock(&prepare_lock);
+ ret = __clk_round_rate(clk, rate);
+ mutex_unlock(&prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+/**
+ * __clk_notify - call clk notifier chain
+ * @clk: struct clk * that is changing rate
+ * @msg: clk notifier type (see include/linux/clk.h)
+ * @old_rate: old clk rate
+ * @new_rate: new clk rate
+ *
+ * Triggers a notifier call chain on the clk rate-change notification
+ * for 'clk'. Passes a pointer to the struct clk and the previous
+ * and current rates to the notifier callback. Intended to be called by
+ * internal clock code only. Returns NOTIFY_DONE from the last driver
+ * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
+ * a driver returns that.
+ */
+static int __clk_notify(struct clk *clk, unsigned long msg,
+ unsigned long old_rate, unsigned long new_rate)
+{
+ struct clk_notifier *cn;
+ struct clk_notifier_data cnd;
+ int ret = NOTIFY_DONE;
+
+ cnd.clk = clk;
+ cnd.old_rate = old_rate;
+ cnd.new_rate = new_rate;
+
+ list_for_each_entry(cn, &clk_notifier_list, node) {
+ if (cn->clk == clk) {
+ ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
+ &cnd);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * __clk_recalc_rates
+ * @clk: first clk in the subtree
+ * @msg: notification type (see include/linux/clk.h)
+ *
+ * Walks the subtree of clks starting with clk and recalculates rates as it
+ * goes. Note that if a clk does not implement the .recalc_rate callback then
+ * it is assumed that the clock will take on the rate of it's parent.
+ *
+ * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
+ * if necessary.
+ *
+ * Caller must hold prepare_lock.
+ */
+static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+{
+ unsigned long old_rate;
+ unsigned long parent_rate = 0;
+ struct hlist_node *tmp;
+ struct clk *child;
+
+ old_rate = clk->rate;
+
+ if (clk->parent)
+ parent_rate = clk->parent->rate;
+
+ if (clk->ops->recalc_rate)
+ clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+ else
+ clk->rate = parent_rate;
+
+ /*
+ * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
+ * & ABORT_RATE_CHANGE notifiers
+ */
+ if (clk->notifier_count && msg)
+ __clk_notify(clk, msg, old_rate, clk->rate);
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node)
+ __clk_recalc_rates(child, msg);
+}
+
+/**
+ * __clk_speculate_rates
+ * @clk: first clk in the subtree
+ * @parent_rate: the "future" rate of clk's parent
+ *
+ * Walks the subtree of clks starting with clk, speculating rates as it
+ * goes and firing off PRE_RATE_CHANGE notifications as necessary.
+ *
+ * Unlike clk_recalc_rates, clk_speculate_rates exists only for sending
+ * pre-rate change notifications and returns early if no clks in the
+ * subtree have subscribed to the notifications. Note that if a clk does not
+ * implement the .recalc_rate callback then it is assumed that the clock will
+ * take on the rate of it's parent.
+ *
+ * Caller must hold prepare_lock.
+ */
+static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+{
+ struct hlist_node *tmp;
+ struct clk *child;
+ unsigned long new_rate;
+ int ret = NOTIFY_DONE;
+
+ if (clk->ops->recalc_rate)
+ new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+ else
+ new_rate = parent_rate;
+
+ /* abort the rate change if a driver returns NOTIFY_BAD */
+ if (clk->notifier_count)
+ ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
+
+ if (ret == NOTIFY_BAD)
+ goto out;
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+ ret = __clk_speculate_rates(child, new_rate);
+ if (ret == NOTIFY_BAD)
+ break;
+ }
+
+out:
+ return ret;
+}
+
+static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+
+ clk->new_rate = new_rate;
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+ if (child->ops->recalc_rate)
+ child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
+ else
+ child->new_rate = new_rate;
+ clk_calc_subtree(child, child->new_rate);
+ }
+}
+
+/*
+ * calculate the new rates returning the topmost clock that has to be
+ * changed.
+ */
+static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+{
+ struct clk *top = clk;
+ unsigned long best_parent_rate = clk->parent->rate;
+ unsigned long new_rate;
+
+ if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) {
+ clk->new_rate = clk->rate;
+ return NULL;
+ }
+
+ if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) {
+ top = clk_calc_new_rates(clk->parent, rate);
+ new_rate = clk->new_rate = clk->parent->new_rate;
+
+ goto out;
+ }
+
+ if (clk->flags & CLK_SET_RATE_PARENT)
+ new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
+ else
+ new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
+
+ if (best_parent_rate != clk->parent->rate) {
+ top = clk_calc_new_rates(clk->parent, best_parent_rate);
+
+ goto out;
+ }
+
+out:
+ clk_calc_subtree(clk, new_rate);
+
+ return top;
+}
+
+/*
+ * Notify about rate changes in a subtree. Always walk down the whole tree
+ * so that in case of an error we can walk down the whole tree again and
+ * abort the change.
+ */
+static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+{
+ struct hlist_node *tmp;
+ struct clk *child, *fail_clk = NULL;
+ int ret = NOTIFY_DONE;
+
+ if (clk->rate == clk->new_rate)
+ return 0;
+
+ if (clk->notifier_count) {
+ ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
+ if (ret == NOTIFY_BAD)
+ fail_clk = clk;
+ }
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+ clk = clk_propagate_rate_change(child, event);
+ if (clk)
+ fail_clk = clk;
+ }
+
+ return fail_clk;
+}
+
+/*
+ * walk down a subtree and set the new rates notifying the rate
+ * change on the way
+ */
+static void clk_change_rate(struct clk *clk)
+{
+ struct clk *child;
+ unsigned long old_rate;
+ struct hlist_node *tmp;
+
+ old_rate = clk->rate;
+
+ if (clk->ops->set_rate)
+ clk->ops->set_rate(clk->hw, clk->new_rate);
+
+ if (clk->ops->recalc_rate)
+ clk->rate = clk->ops->recalc_rate(clk->hw,
+ clk->parent->rate);
+ else
+ clk->rate = clk->parent->rate;
+
+ if (clk->notifier_count && old_rate != clk->rate)
+ __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
+
+ hlist_for_each_entry(child, tmp, &clk->children, child_node)
+ clk_change_rate(child);
+}
+
+/**
+ * clk_set_rate - specify a new rate for clk
+ * @clk: the clk whose rate is being changed
+ * @rate: the new rate for clk
+ *
+ * In the simplest case clk_set_rate will only change the rate of clk.
+ *
+ * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call
+ * will fail; only when the clk is disabled will it be able to change
+ * its rate.
+ *
+ * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to
+ * recursively propagate up to clk's parent; whether or not this happens
+ * depends on the outcome of clk's .round_rate implementation. If
+ * *parent_rate is 0 after calling .round_rate then upstream parent
+ * propagation is ignored. If *parent_rate comes back with a new rate
+ * for clk's parent then we propagate up to clk's parent and set it's
+ * rate. Upward propagation will continue until either a clk does not
+ * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting
+ * changes to clk's parent_rate. If there is a failure during upstream
+ * propagation then clk_set_rate will unwind and restore each clk's rate
+ * that had been successfully changed. Afterwards a rate change abort
+ * notification will be propagated downstream, starting from the clk
+ * that failed.
+ *
+ * At the end of all of the rate setting, clk_set_rate internally calls
+ * __clk_recalc_rates and propagates the rate changes downstream,
+ * starting from the highest clk whose rate was changed. This has the
+ * added benefit of propagating post-rate change notifiers.
+ *
+ * Note that while post-rate change and rate change abort notifications
+ * are guaranteed to be sent to a clk only once per call to
+ * clk_set_rate, pre-change notifications will be sent for every clk
+ * whose rate is changed. Stacking pre-change notifications is noisy
+ * for the drivers subscribed to them, but this allows drivers to react
+ * to intermediate clk rate changes up until the point where the final
+ * rate is achieved at the end of upstream propagation.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk *top, *fail_clk;
+ int ret = 0;
+
+ /* prevent racing with updates to the clock topology */
+ mutex_lock(&prepare_lock);
+
+ /* bail early if nothing to do */
+ if (rate == clk->rate)
+ goto out;
+
+ /* calculate new rates and get the topmost changed clock */
+ top = clk_calc_new_rates(clk, rate);
+ if (!top) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* notify that we are about to change rates */
+ fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
+ if (fail_clk) {
+ pr_warn("%s: failed to set %s rate\n", __func__,
+ fail_clk->name);
+ clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* change the rates */
+ clk_change_rate(top);
+
+ mutex_unlock(&prepare_lock);
+
+ return 0;
+out:
+ mutex_unlock(&prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+/**
+ * clk_get_parent - return the parent of a clk
+ * @clk: the clk whose parent gets returned
+ *
+ * Simply returns clk->parent. Returns NULL if clk is NULL.
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+ struct clk *parent;
+
+ mutex_lock(&prepare_lock);
+ parent = __clk_get_parent(clk);
+ mutex_unlock(&prepare_lock);
+
+ return parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/*
+ * .get_parent is mandatory for clocks with multiple possible parents. It is
+ * optional for single-parent clocks. Always call .get_parent if it is
+ * available and WARN if it is missing for multi-parent clocks.
+ *
+ * For single-parent clocks without .get_parent, first check to see if the
+ * .parents array exists, and if so use it to avoid an expensive tree
+ * traversal. If .parents does not exist then walk the tree with __clk_lookup.
+ */
+static struct clk *__clk_init_parent(struct clk *clk)
+{
+ struct clk *ret = NULL;
+ u8 index;
+
+ /* handle the trivial cases */
+
+ if (!clk->num_parents)
+ goto out;
+
+ if (clk->num_parents == 1) {
+ if (IS_ERR_OR_NULL(clk->parent))
+ ret = clk->parent = __clk_lookup(clk->parent_names[0]);
+ ret = clk->parent;
+ goto out;
+ }
+
+ if (!clk->ops->get_parent) {
+ WARN(!clk->ops->get_parent,
+ "%s: multi-parent clocks must implement .get_parent\n",
+ __func__);
+ goto out;
+ };
+
+ /*
+ * Do our best to cache parent clocks in clk->parents. This prevents
+ * unnecessary and expensive calls to __clk_lookup. We don't set
+ * clk->parent here; that is done by the calling function
+ */
+
+ index = clk->ops->get_parent(clk->hw);
+
+ if (!clk->parents)
+ clk->parents =
+ kmalloc((sizeof(struct clk*) * clk->num_parents),
+ GFP_KERNEL);
+
+ if (!clk->parents)
+ ret = __clk_lookup(clk->parent_names[index]);
+ else if (!clk->parents[index])
+ ret = clk->parents[index] =
+ __clk_lookup(clk->parent_names[index]);
+ else
+ ret = clk->parents[index];
+
+out:
+ return ret;
+}
+
+void __clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+#ifdef CONFIG_COMMON_CLK_DEBUG
+ struct dentry *d;
+ struct dentry *new_parent_d;
+#endif
+
+ if (!clk || !new_parent)
+ return;
+
+ hlist_del(&clk->child_node);
+
+ if (new_parent)
+ hlist_add_head(&clk->child_node, &new_parent->children);
+ else
+ hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+ if (!inited)
+ goto out;
+
+ if (new_parent)
+ new_parent_d = new_parent->dentry;
+ else
+ new_parent_d = orphandir;
+
+ d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
+ new_parent_d, clk->name);
+ if (d)
+ clk->dentry = d;
+ else
+ pr_debug("%s: failed to rename debugfs entry for %s\n",
+ __func__, clk->name);
+out:
+#endif
+
+ clk->parent = new_parent;
+
+ __clk_recalc_rates(clk, POST_RATE_CHANGE);
+}
+
+static int __clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk *old_parent;
+ unsigned long flags;
+ int ret = -EINVAL;
+ u8 i;
+
+ old_parent = clk->parent;
+
+ /* find index of new parent clock using cached parent ptrs */
+ for (i = 0; i < clk->num_parents; i++)
+ if (clk->parents[i] == parent)
+ break;
+
+ /*
+ * find index of new parent clock using string name comparison
+ * also try to cache the parent to avoid future calls to __clk_lookup
+ */
+ if (i == clk->num_parents)
+ for (i = 0; i < clk->num_parents; i++)
+ if (!strcmp(clk->parent_names[i], parent->name)) {
+ clk->parents[i] = __clk_lookup(parent->name);
+ break;
+ }
+
+ if (i == clk->num_parents) {
+ pr_debug("%s: clock %s is not a possible parent of clock %s\n",
+ __func__, parent->name, clk->name);
+ goto out;
+ }
+
+ /* migrate prepare and enable */
+ if (clk->prepare_count)
+ __clk_prepare(parent);
+
+ /* FIXME replace with clk_is_enabled(clk) someday */
+ spin_lock_irqsave(&enable_lock, flags);
+ if (clk->enable_count)
+ __clk_enable(parent);
+ spin_unlock_irqrestore(&enable_lock, flags);
+
+ /* change clock input source */
+ ret = clk->ops->set_parent(clk->hw, i);
+
+ /* clean up old prepare and enable */
+ spin_lock_irqsave(&enable_lock, flags);
+ if (clk->enable_count)
+ __clk_disable(old_parent);
+ spin_unlock_irqrestore(&enable_lock, flags);
+
+ if (clk->prepare_count)
+ __clk_unprepare(old_parent);
+
+out:
+ return ret;
+}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as it's new input source. If clk has the
+ * CLK_SET_PARENT_GATE flag set then clk must be gated for this
+ * operation to succeed. After successfully changing clk's parent
+ * clk_set_parent will update the clk topology, sysfs topology and
+ * propagate rate recalculation via __clk_recalc_rates. Returns 0 on
+ * success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ int ret = 0;
+
+ if (!clk || !clk->ops)
+ return -EINVAL;
+
+ if (!clk->ops->set_parent)
+ return -ENOSYS;
+
+ /* prevent racing with updates to the clock topology */
+ mutex_lock(&prepare_lock);
+
+ if (clk->parent == parent)
+ goto out;
+
+ /* propagate PRE_RATE_CHANGE notifications */
+ if (clk->notifier_count)
+ ret = __clk_speculate_rates(clk, parent->rate);
+
+ /* abort if a driver objects */
+ if (ret == NOTIFY_STOP)
+ goto out;
+
+ /* only re-parent if the clock is not in use */
+ if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count)
+ ret = -EBUSY;
+ else
+ ret = __clk_set_parent(clk, parent);
+
+ /* propagate ABORT_RATE_CHANGE if .set_parent failed */
+ if (ret) {
+ __clk_recalc_rates(clk, ABORT_RATE_CHANGE);
+ goto out;
+ }
+
+ /* propagate rate recalculation downstream */
+ __clk_reparent(clk, parent);
+
+out:
+ mutex_unlock(&prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+/**
+ * __clk_init - initialize the data structures in a struct clk
+ * @dev: device initializing this clk, placeholder for now
+ * @clk: clk being initialized
+ *
+ * Initializes the lists in struct clk, queries the hardware for the
+ * parent and rate and sets them both.
+ *
+ * Any struct clk passed into __clk_init must have the following members
+ * populated:
+ * .name
+ * .ops
+ * .hw
+ * .parent_names
+ * .num_parents
+ * .flags
+ *
+ * Essentially, everything that would normally be passed into clk_register is
+ * assumed to be initialized already in __clk_init. The other members may be
+ * populated, but are optional.
+ *
+ * __clk_init is only exposed via clk-private.h and is intended for use with
+ * very large numbers of clocks that need to be statically initialized. It is
+ * a layering violation to include clk-private.h from any code which implements
+ * a clock's .ops; as such any statically initialized clock data MUST be in a
+ * separate C file from the logic that implements it's operations.
+ */
+void __clk_init(struct device *dev, struct clk *clk)
+{
+ int i;
+ struct clk *orphan;
+ struct hlist_node *tmp, *tmp2;
+
+ if (!clk)
+ return;
+
+ mutex_lock(&prepare_lock);
+
+ /* check to see if a clock with this name is already registered */
+ if (__clk_lookup(clk->name))
+ goto out;
+
+ /* throw a WARN if any entries in parent_names are NULL */
+ for (i = 0; i < clk->num_parents; i++)
+ WARN(!clk->parent_names[i],
+ "%s: invalid NULL in %s's .parent_names\n",
+ __func__, clk->name);
+
+ /*
+ * Allocate an array of struct clk *'s to avoid unnecessary string
+ * look-ups of clk's possible parents. This can fail for clocks passed
+ * in to clk_init during early boot; thus any access to clk->parents[]
+ * must always check for a NULL pointer and try to populate it if
+ * necessary.
+ *
+ * If clk->parents is not NULL we skip this entire block. This allows
+ * for clock drivers to statically initialize clk->parents.
+ */
+ if (clk->num_parents && !clk->parents) {
+ clk->parents = kmalloc((sizeof(struct clk*) * clk->num_parents),
+ GFP_KERNEL);
+ /*
+ * __clk_lookup returns NULL for parents that have not been
+ * clk_init'd; thus any access to clk->parents[] must check
+ * for a NULL pointer. We can always perform lazy lookups for
+ * missing parents later on.
+ */
+ if (clk->parents)
+ for (i = 0; i < clk->num_parents; i++)
+ clk->parents[i] =
+ __clk_lookup(clk->parent_names[i]);
+ }
+
+ clk->parent = __clk_init_parent(clk);
+
+ /*
+ * Populate clk->parent if parent has already been __clk_init'd. If
+ * parent has not yet been __clk_init'd then place clk in the orphan
+ * list. If clk has set the CLK_IS_ROOT flag then place it in the root
+ * clk list.
+ *
+ * Every time a new clk is clk_init'd then we walk the list of orphan
+ * clocks and re-parent any that are children of the clock currently
+ * being clk_init'd.
+ */
+ if (clk->parent)
+ hlist_add_head(&clk->child_node,
+ &clk->parent->children);
+ else if (clk->flags & CLK_IS_ROOT)
+ hlist_add_head(&clk->child_node, &clk_root_list);
+ else
+ hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+ /*
+ * Set clk's rate. The preferred method is to use .recalc_rate. For
+ * simple clocks and lazy developers the default fallback is to use the
+ * parent's rate. If a clock doesn't have a parent (or is orphaned)
+ * then rate is set to zero.
+ */
+ if (clk->ops->recalc_rate)
+ clk->rate = clk->ops->recalc_rate(clk->hw,
+ __clk_get_rate(clk->parent));
+ else if (clk->parent)
+ clk->rate = clk->parent->rate;
+ else
+ clk->rate = 0;
+
+ /*
+ * walk the list of orphan clocks and reparent any that are children of
+ * this clock
+ */
+ hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node)
+ for (i = 0; i < orphan->num_parents; i++)
+ if (!strcmp(clk->name, orphan->parent_names[i])) {
+ __clk_reparent(orphan, clk);
+ break;
+ }
+
+ /*
+ * optional platform-specific magic
+ *
+ * The .init callback is not used by any of the basic clock types, but
+ * exists for weird hardware that must perform initialization magic.
+ * Please consider other ways of solving initialization problems before
+ * using this callback, as it's use is discouraged.
+ */
+ if (clk->ops->init)
+ clk->ops->init(clk->hw);
+
+ clk_debug_register(clk);
+
+out:
+ mutex_unlock(&prepare_lock);
+
+ return;
+}
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @name: clock name
+ * @ops: operations this clock supports
+ * @hw: link to hardware-specific clock data
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes. It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API.
+ */
+struct clk *clk_register(struct device *dev, const char *name,
+ const struct clk_ops *ops, struct clk_hw *hw,
+ char **parent_names, u8 num_parents, unsigned long flags)
+{
+ struct clk *clk;
+
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return NULL;
+
+ clk->name = name;
+ clk->ops = ops;
+ clk->hw = hw;
+ clk->flags = flags;
+ clk->parent_names = parent_names;
+ clk->num_parents = num_parents;
+ hw->clk = clk;
+
+ __clk_init(dev, clk);
+
+ return clk;
+}
+EXPORT_SYMBOL_GPL(clk_register);
+
+/*** clk rate change notifiers ***/
+
+/**
+ * clk_notifier_register - add a clk rate change notifier
+ * @clk: struct clk * to watch
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request notification when clk's rate changes. This uses an SRCU
+ * notifier because we want it to block and notifier unregistrations are
+ * uncommon. The callbacks associated with the notifier must not
+ * re-enter into the clk framework by calling any top-level clk APIs;
+ * this will cause a nested prepare_lock mutex.
+ *
+ * Pre-change notifier callbacks will be passed the current, pre-change
+ * rate of the clk via struct clk_notifier_data.old_rate. The new,
+ * post-change rate of the clk is passed via struct
+ * clk_notifier_data.new_rate.
+ *
+ * Post-change notifiers will pass the now-current, post-change rate of
+ * the clk in both struct clk_notifier_data.old_rate and struct
+ * clk_notifier_data.new_rate.
+ *
+ * Abort-change notifiers are effectively the opposite of pre-change
+ * notifiers: the original pre-change clk rate is passed in via struct
+ * clk_notifier_data.new_rate and the failed post-change rate is passed
+ * in via struct clk_notifier_data.old_rate.
+ *
+ * clk_notifier_register() must be called from non-atomic context.
+ * Returns -EINVAL if called with null arguments, -ENOMEM upon
+ * allocation failure; otherwise, passes along the return value of
+ * srcu_notifier_chain_register().
+ */
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
+{
+ struct clk_notifier *cn;
+ int ret = -ENOMEM;
+
+ if (!clk || !nb)
+ return -EINVAL;
+
+ mutex_lock(&prepare_lock);
+
+ /* search the list of notifiers for this clk */
+ list_for_each_entry(cn, &clk_notifier_list, node)
+ if (cn->clk == clk)
+ break;
+
+ /* if clk wasn't in the notifier list, allocate new clk_notifier */
+ if (cn->clk != clk) {
+ cn = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
+ if (!cn)
+ goto out;
+
+ cn->clk = clk;
+ srcu_init_notifier_head(&cn->notifier_head);
+
+ list_add(&cn->node, &clk_notifier_list);
+ }
+
+ ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
+
+ clk->notifier_count++;
+
+out:
+ mutex_unlock(&prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_register);
+
+/**
+ * clk_notifier_unregister - remove a clk rate change notifier
+ * @clk: struct clk *
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request no further notification for changes to 'clk' and frees memory
+ * allocated in clk_notifier_register.
+ *
+ * Returns -EINVAL if called with null arguments; otherwise, passes
+ * along the return value of srcu_notifier_chain_unregister().
+ */
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
+{
+ struct clk_notifier *cn = NULL;
+ int ret = -EINVAL;
+
+ if (!clk || !nb)
+ return -EINVAL;
+
+ mutex_lock(&prepare_lock);
+
+ list_for_each_entry(cn, &clk_notifier_list, node)
+ if (cn->clk == clk)
+ break;
+
+ if (cn->clk == clk) {
+ ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
+
+ clk->notifier_count--;
+
+ /* XXX the notifier code should handle this better */
+ if (!cn->notifier_head.head) {
+ srcu_cleanup_notifier_head(&cn->notifier_head);
+ kfree(cn);
+ }
+
+ } else {
+ ret = -ENOENT;
+ }
+
+ mutex_unlock(&prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_unregister);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 999d6a03e436..5138927a416c 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -26,7 +26,6 @@ config CLKSRC_DBX500_PRCMU
config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
bool "Clocksource PRCMU Timer sched_clock"
depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK)
- select HAVE_SCHED_CLOCK
default y
help
Use the always on PRCMU Timer as sched_clock
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index f5002015d82e..a22ffa5bff9f 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -22,11 +22,11 @@ static struct cpufreq_frequency_table freq_table[] = {
},
[1] = {
.index = 1,
- .frequency = 300000,
+ .frequency = 400000,
},
[2] = {
.index = 2,
- .frequency = 600000,
+ .frequency = 800000,
},
[3] = {
/* Used for MAX_OPP, if available */
@@ -113,12 +113,9 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
- if (!prcmu_is_u8400()) {
- freq_table[1].frequency = 400000;
- freq_table[2].frequency = 800000;
- if (prcmu_has_arm_maxopp())
- freq_table[3].frequency = 1000000;
- }
+ if (prcmu_has_arm_maxopp())
+ freq_table[3].frequency = 1000000;
+
pr_info("db8500-cpufreq : Available frequencies:\n");
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 67bbb06d0460..17fa04d08be9 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <linux/regulator/consumer.h>
-#include <asm/system.h>
#include <asm/smp_plat.h>
#include <asm/cpu.h>
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index cf7e1ee005a2..334cc2f1e9f1 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -27,7 +27,6 @@
#include <asm/timer.h> /* Needed for recalibrate_cpu_khz() */
#include <asm/msr.h>
-#include <asm/system.h>
#include <asm/cpu_device_id.h>
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 4a6c46dea8a0..cf9da362d64f 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -201,7 +201,6 @@ config PL330_DMA
tristate "DMA API Driver for PL330"
select DMA_ENGINE
depends on ARM_AMBA
- select PL330
help
Select if your platform has one or more PL330 DMACs.
You need to provide platform specific settings via
@@ -231,7 +230,7 @@ config IMX_SDMA
config IMX_DMA
tristate "i.MX DMA support"
- depends on IMX_HAVE_DMA_V1
+ depends on ARCH_MXC
select DMA_ENGINE
help
Support the i.MX DMA engine. This engine is integrated into
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 8a281584458b..c301a8ec31aa 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -85,6 +85,8 @@
#include <linux/slab.h>
#include <asm/hardware/pl080.h>
+#include "dmaengine.h"
+
#define DRIVER_NAME "pl08xdmac"
static struct amba_driver pl08x_amba_driver;
@@ -649,7 +651,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
}
if ((bd.srcbus.addr % bd.srcbus.buswidth) ||
- (bd.srcbus.addr % bd.srcbus.buswidth)) {
+ (bd.dstbus.addr % bd.dstbus.buswidth)) {
dev_err(&pl08x->adev->dev,
"%s src & dst address must be aligned to src"
" & dst width if peripheral is flow controller",
@@ -919,13 +921,10 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
struct pl08x_txd *txd = to_pl08x_txd(tx);
unsigned long flags;
+ dma_cookie_t cookie;
spin_lock_irqsave(&plchan->lock, flags);
-
- plchan->chan.cookie += 1;
- if (plchan->chan.cookie < 0)
- plchan->chan.cookie = 1;
- tx->cookie = plchan->chan.cookie;
+ cookie = dma_cookie_assign(tx);
/* Put this onto the pending list */
list_add_tail(&txd->node, &plchan->pend_list);
@@ -945,7 +944,7 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
spin_unlock_irqrestore(&plchan->lock, flags);
- return tx->cookie;
+ return cookie;
}
static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
@@ -965,31 +964,17 @@ static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *txstate)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
enum dma_status ret;
- u32 bytesleft = 0;
- last_used = plchan->chan.cookie;
- last_complete = plchan->lc;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
- if (ret == DMA_SUCCESS) {
- dma_set_tx_state(txstate, last_complete, last_used, 0);
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_SUCCESS)
return ret;
- }
/*
* This cookie not complete yet
+ * Get number of bytes left in the active transactions and queue
*/
- last_used = plchan->chan.cookie;
- last_complete = plchan->lc;
-
- /* Get number of bytes left in the active transactions and queue */
- bytesleft = pl08x_getbytes_chan(plchan);
-
- dma_set_tx_state(txstate, last_complete, last_used,
- bytesleft);
+ dma_set_residue(txstate, pl08x_getbytes_chan(plchan));
if (plchan->state == PL08X_CHAN_PAUSED)
return DMA_PAUSED;
@@ -1139,6 +1124,8 @@ static int dma_set_runtime_config(struct dma_chan *chan,
cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
+ plchan->device_fc = config->device_fc;
+
if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
plchan->src_addr = config->src_addr;
plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
@@ -1326,7 +1313,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
struct pl08x_driver_data *pl08x = plchan->host;
@@ -1370,7 +1357,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
return NULL;
}
- if (plchan->cd->device_fc)
+ if (plchan->device_fc)
tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER :
PL080_FLOW_PER2MEM_PER;
else
@@ -1541,7 +1528,7 @@ static void pl08x_tasklet(unsigned long data)
if (txd) {
/* Update last completed */
- plchan->lc = txd->tx.cookie;
+ dma_cookie_complete(&txd->tx);
}
/* If a new descriptor is queued, set it up plchan->at is NULL here */
@@ -1722,8 +1709,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
chan->name);
chan->chan.device = dmadev;
- chan->chan.cookie = 0;
- chan->lc = 0;
+ dma_cookie_init(&chan->chan);
spin_lock_init(&chan->lock);
INIT_LIST_HEAD(&chan->pend_list);
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index f4aed5fc2cb6..7aa58d204892 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -27,6 +27,7 @@
#include <linux/of_device.h>
#include "at_hdmac_regs.h"
+#include "dmaengine.h"
/*
* Glossary
@@ -192,27 +193,6 @@ static void atc_desc_chain(struct at_desc **first, struct at_desc **prev,
}
/**
- * atc_assign_cookie - compute and assign new cookie
- * @atchan: channel we work on
- * @desc: descriptor to assign cookie for
- *
- * Called with atchan->lock held and bh disabled
- */
-static dma_cookie_t
-atc_assign_cookie(struct at_dma_chan *atchan, struct at_desc *desc)
-{
- dma_cookie_t cookie = atchan->chan_common.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- atchan->chan_common.cookie = cookie;
- desc->txd.cookie = cookie;
-
- return cookie;
-}
-
-/**
* atc_dostart - starts the DMA engine for real
* @atchan: the channel we want to start
* @first: first descriptor in the list we want to begin with
@@ -269,7 +249,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
dev_vdbg(chan2dev(&atchan->chan_common),
"descriptor %u complete\n", txd->cookie);
- atchan->completed_cookie = txd->cookie;
+ dma_cookie_complete(txd);
/* move children to free_list */
list_splice_init(&desc->tx_list, &atchan->free_list);
@@ -547,7 +527,7 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx)
unsigned long flags;
spin_lock_irqsave(&atchan->lock, flags);
- cookie = atc_assign_cookie(atchan, desc);
+ cookie = dma_cookie_assign(tx);
if (list_empty(&atchan->active_list)) {
dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
@@ -659,14 +639,16 @@ err_desc_get:
* @sg_len: number of entries in @scatterlist
* @direction: DMA direction
* @flags: tx descriptor status flags
+ * @context: transaction context (ignored)
*/
static struct dma_async_tx_descriptor *
atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
struct at_dma_slave *atslave = chan->private;
+ struct dma_slave_config *sconfig = &atchan->dma_sconfig;
struct at_desc *first = NULL;
struct at_desc *prev = NULL;
u32 ctrla;
@@ -688,19 +670,18 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return NULL;
}
- reg_width = atslave->reg_width;
-
ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
ctrlb = ATC_IEN;
switch (direction) {
case DMA_MEM_TO_DEV:
+ reg_width = convert_buswidth(sconfig->dst_addr_width);
ctrla |= ATC_DST_WIDTH(reg_width);
ctrlb |= ATC_DST_ADDR_MODE_FIXED
| ATC_SRC_ADDR_MODE_INCR
| ATC_FC_MEM2PER
| ATC_SIF(AT_DMA_MEM_IF) | ATC_DIF(AT_DMA_PER_IF);
- reg = atslave->tx_reg;
+ reg = sconfig->dst_addr;
for_each_sg(sgl, sg, sg_len, i) {
struct at_desc *desc;
u32 len;
@@ -728,13 +709,14 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
}
break;
case DMA_DEV_TO_MEM:
+ reg_width = convert_buswidth(sconfig->src_addr_width);
ctrla |= ATC_SRC_WIDTH(reg_width);
ctrlb |= ATC_DST_ADDR_MODE_INCR
| ATC_SRC_ADDR_MODE_FIXED
| ATC_FC_PER2MEM
| ATC_SIF(AT_DMA_PER_IF) | ATC_DIF(AT_DMA_MEM_IF);
- reg = atslave->rx_reg;
+ reg = sconfig->src_addr;
for_each_sg(sgl, sg, sg_len, i) {
struct at_desc *desc;
u32 len;
@@ -810,12 +792,15 @@ err_out:
* atc_dma_cyclic_fill_desc - Fill one period decriptor
*/
static int
-atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
+atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
unsigned int period_index, dma_addr_t buf_addr,
- size_t period_len, enum dma_transfer_direction direction)
+ unsigned int reg_width, size_t period_len,
+ enum dma_transfer_direction direction)
{
- u32 ctrla;
- unsigned int reg_width = atslave->reg_width;
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma_slave *atslave = chan->private;
+ struct dma_slave_config *sconfig = &atchan->dma_sconfig;
+ u32 ctrla;
/* prepare common CRTLA value */
ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla
@@ -826,7 +811,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
switch (direction) {
case DMA_MEM_TO_DEV:
desc->lli.saddr = buf_addr + (period_len * period_index);
- desc->lli.daddr = atslave->tx_reg;
+ desc->lli.daddr = sconfig->dst_addr;
desc->lli.ctrla = ctrla;
desc->lli.ctrlb = ATC_DST_ADDR_MODE_FIXED
| ATC_SRC_ADDR_MODE_INCR
@@ -836,7 +821,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
break;
case DMA_DEV_TO_MEM:
- desc->lli.saddr = atslave->rx_reg;
+ desc->lli.saddr = sconfig->src_addr;
desc->lli.daddr = buf_addr + (period_len * period_index);
desc->lli.ctrla = ctrla;
desc->lli.ctrlb = ATC_DST_ADDR_MODE_INCR
@@ -860,16 +845,20 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
* @buf_len: total number of bytes for the entire buffer
* @period_len: number of bytes for each period
* @direction: transfer direction, to or from device
+ * @context: transfer context (ignored)
*/
static struct dma_async_tx_descriptor *
atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
- size_t period_len, enum dma_transfer_direction direction)
+ size_t period_len, enum dma_transfer_direction direction,
+ void *context)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
struct at_dma_slave *atslave = chan->private;
+ struct dma_slave_config *sconfig = &atchan->dma_sconfig;
struct at_desc *first = NULL;
struct at_desc *prev = NULL;
unsigned long was_cyclic;
+ unsigned int reg_width;
unsigned int periods = buf_len / period_len;
unsigned int i;
@@ -889,8 +878,13 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
return NULL;
}
+ if (sconfig->direction == DMA_MEM_TO_DEV)
+ reg_width = convert_buswidth(sconfig->dst_addr_width);
+ else
+ reg_width = convert_buswidth(sconfig->src_addr_width);
+
/* Check for too big/unaligned periods and unaligned DMA buffer */
- if (atc_dma_cyclic_check_values(atslave->reg_width, buf_addr,
+ if (atc_dma_cyclic_check_values(reg_width, buf_addr,
period_len, direction))
goto err_out;
@@ -902,8 +896,8 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
if (!desc)
goto err_desc_get;
- if (atc_dma_cyclic_fill_desc(atslave, desc, i, buf_addr,
- period_len, direction))
+ if (atc_dma_cyclic_fill_desc(chan, desc, i, buf_addr,
+ reg_width, period_len, direction))
goto err_desc_get;
atc_desc_chain(&first, &prev, desc);
@@ -926,6 +920,23 @@ err_out:
return NULL;
}
+static int set_runtime_config(struct dma_chan *chan,
+ struct dma_slave_config *sconfig)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+
+ /* Check if it is chan is configured for slave transfers */
+ if (!chan->private)
+ return -EINVAL;
+
+ memcpy(&atchan->dma_sconfig, sconfig, sizeof(*sconfig));
+
+ convert_burst(&atchan->dma_sconfig.src_maxburst);
+ convert_burst(&atchan->dma_sconfig.dst_maxburst);
+
+ return 0;
+}
+
static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
unsigned long arg)
@@ -986,6 +997,8 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
clear_bit(ATC_IS_CYCLIC, &atchan->status);
spin_unlock_irqrestore(&atchan->lock, flags);
+ } else if (cmd == DMA_SLAVE_CONFIG) {
+ return set_runtime_config(chan, (struct dma_slave_config *)arg);
} else {
return -ENXIO;
}
@@ -1016,26 +1029,20 @@ atc_tx_status(struct dma_chan *chan,
spin_lock_irqsave(&atchan->lock, flags);
- last_complete = atchan->completed_cookie;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
if (ret != DMA_SUCCESS) {
atc_cleanup_descriptors(atchan);
- last_complete = atchan->completed_cookie;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
}
+ last_complete = chan->completed_cookie;
+ last_used = chan->cookie;
+
spin_unlock_irqrestore(&atchan->lock, flags);
if (ret != DMA_SUCCESS)
- dma_set_tx_state(txstate, last_complete, last_used,
- atc_first_active(atchan)->len);
- else
- dma_set_tx_state(txstate, last_complete, last_used, 0);
+ dma_set_residue(txstate, atc_first_active(atchan)->len);
if (atc_chan_is_paused(atchan))
ret = DMA_PAUSED;
@@ -1129,7 +1136,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
spin_lock_irqsave(&atchan->lock, flags);
atchan->descs_allocated = i;
list_splice(&tmp_list, &atchan->free_list);
- atchan->completed_cookie = chan->cookie = 1;
+ dma_cookie_init(chan);
spin_unlock_irqrestore(&atchan->lock, flags);
/* channel parameters */
@@ -1329,7 +1336,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
struct at_dma_chan *atchan = &atdma->chan[i];
atchan->chan_common.device = &atdma->dma_common;
- atchan->chan_common.cookie = atchan->completed_cookie = 1;
+ dma_cookie_init(&atchan->chan_common);
list_add_tail(&atchan->chan_common.device_node,
&atdma->dma_common.channels);
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index a8d3277d60b5..897a8bcaec90 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -207,8 +207,8 @@ enum atc_status {
* @save_cfg: configuration register that is saved on suspend/resume cycle
* @save_dscr: for cyclic operations, preserve next descriptor address in
* the cyclic list on suspend/resume cycle
+ * @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG
* @lock: serializes enqueue/dequeue operations to descriptors lists
- * @completed_cookie: identifier for the most recently completed operation
* @active_list: list of descriptors dmaengine is being running on
* @queue: list of descriptors ready to be submitted to engine
* @free_list: list of descriptors usable by the channel
@@ -223,11 +223,11 @@ struct at_dma_chan {
struct tasklet_struct tasklet;
u32 save_cfg;
u32 save_dscr;
+ struct dma_slave_config dma_sconfig;
spinlock_t lock;
/* these other elements are all protected by lock */
- dma_cookie_t completed_cookie;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
@@ -245,6 +245,36 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
return container_of(dchan, struct at_dma_chan, chan_common);
}
+/*
+ * Fix sconfig's burst size according to at_hdmac. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3, 32 -> 4, 64 -> 5, 128 -> 6, 256 -> 7.
+ *
+ * This can be done by finding most significant bit set.
+ */
+static inline void convert_burst(u32 *maxburst)
+{
+ if (*maxburst > 1)
+ *maxburst = fls(*maxburst) - 2;
+ else
+ *maxburst = 0;
+}
+
+/*
+ * Fix sconfig's bus width according to at_hdmac.
+ * 1 byte -> 0, 2 bytes -> 1, 4 bytes -> 2.
+ */
+static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
+{
+ switch (addr_width) {
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ return 1;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ return 2;
+ default:
+ /* For 1 byte width or fallback */
+ return 0;
+ }
+}
/*-- Controller ------------------------------------------------------*/
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index d65a718c0f9b..dc89455f5550 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -24,6 +24,7 @@
#include <mach/coh901318.h>
#include "coh901318_lli.h"
+#include "dmaengine.h"
#define COHC_2_DEV(cohc) (&cohc->chan.dev->device)
@@ -59,7 +60,6 @@ struct coh901318_base {
struct coh901318_chan {
spinlock_t lock;
int allocated;
- int completed;
int id;
int stopped;
@@ -318,20 +318,6 @@ static int coh901318_prep_linked_list(struct coh901318_chan *cohc,
return 0;
}
-static dma_cookie_t
-coh901318_assign_cookie(struct coh901318_chan *cohc,
- struct coh901318_desc *cohd)
-{
- dma_cookie_t cookie = cohc->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- cohc->chan.cookie = cookie;
- cohd->desc.cookie = cookie;
-
- return cookie;
-}
static struct coh901318_desc *
coh901318_desc_get(struct coh901318_chan *cohc)
@@ -705,7 +691,7 @@ static void dma_tasklet(unsigned long data)
callback_param = cohd_fin->desc.callback_param;
/* sign this job as completed on the channel */
- cohc->completed = cohd_fin->desc.cookie;
+ dma_cookie_complete(&cohd_fin->desc);
/* release the lli allocation and remove the descriptor */
coh901318_lli_free(&cohc->base->pool, &cohd_fin->lli);
@@ -929,7 +915,7 @@ static int coh901318_alloc_chan_resources(struct dma_chan *chan)
coh901318_config(cohc, NULL);
cohc->allocated = 1;
- cohc->completed = chan->cookie = 1;
+ dma_cookie_init(chan);
spin_unlock_irqrestore(&cohc->lock, flags);
@@ -966,16 +952,16 @@ coh901318_tx_submit(struct dma_async_tx_descriptor *tx)
desc);
struct coh901318_chan *cohc = to_coh901318_chan(tx->chan);
unsigned long flags;
+ dma_cookie_t cookie;
spin_lock_irqsave(&cohc->lock, flags);
-
- tx->cookie = coh901318_assign_cookie(cohc, cohd);
+ cookie = dma_cookie_assign(tx);
coh901318_desc_queue(cohc, cohd);
spin_unlock_irqrestore(&cohc->lock, flags);
- return tx->cookie;
+ return cookie;
}
static struct dma_async_tx_descriptor *
@@ -1035,7 +1021,7 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
static struct dma_async_tx_descriptor *
coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct coh901318_chan *cohc = to_coh901318_chan(chan);
struct coh901318_lli *lli;
@@ -1165,17 +1151,12 @@ coh901318_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct coh901318_chan *cohc = to_coh901318_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- int ret;
-
- last_complete = cohc->completed;
- last_used = chan->cookie;
+ enum dma_status ret;
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
+ /* FIXME: should be conditional on ret != DMA_SUCCESS? */
+ dma_set_residue(txstate, coh901318_get_bytes_left(chan));
- dma_set_tx_state(txstate, last_complete, last_used,
- coh901318_get_bytes_left(chan));
if (ret == DMA_IN_PROGRESS && cohc->stopped)
ret = DMA_PAUSED;
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index a6c6051ec858..767bcc31b365 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -510,8 +510,8 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v
dma_chan_name(chan));
list_del_rcu(&device->global_node);
} else if (err)
- pr_debug("dmaengine: failed to get %s: (%d)\n",
- dma_chan_name(chan), err);
+ pr_debug("%s: failed to get %s: (%d)\n",
+ __func__, dma_chan_name(chan), err);
else
break;
if (--device->privatecnt == 0)
@@ -564,8 +564,8 @@ void dmaengine_get(void)
list_del_rcu(&device->global_node);
break;
} else if (err)
- pr_err("dmaengine: failed to get %s: (%d)\n",
- dma_chan_name(chan), err);
+ pr_err("%s: failed to get %s: (%d)\n",
+ __func__, dma_chan_name(chan), err);
}
}
diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h
new file mode 100644
index 000000000000..17f983a4e9ba
--- /dev/null
+++ b/drivers/dma/dmaengine.h
@@ -0,0 +1,89 @@
+/*
+ * The contents of this file are private to DMA engine drivers, and is not
+ * part of the API to be used by DMA engine users.
+ */
+#ifndef DMAENGINE_H
+#define DMAENGINE_H
+
+#include <linux/bug.h>
+#include <linux/dmaengine.h>
+
+/**
+ * dma_cookie_init - initialize the cookies for a DMA channel
+ * @chan: dma channel to initialize
+ */
+static inline void dma_cookie_init(struct dma_chan *chan)
+{
+ chan->cookie = DMA_MIN_COOKIE;
+ chan->completed_cookie = DMA_MIN_COOKIE;
+}
+
+/**
+ * dma_cookie_assign - assign a DMA engine cookie to the descriptor
+ * @tx: descriptor needing cookie
+ *
+ * Assign a unique non-zero per-channel cookie to the descriptor.
+ * Note: caller is expected to hold a lock to prevent concurrency.
+ */
+static inline dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx)
+{
+ struct dma_chan *chan = tx->chan;
+ dma_cookie_t cookie;
+
+ cookie = chan->cookie + 1;
+ if (cookie < DMA_MIN_COOKIE)
+ cookie = DMA_MIN_COOKIE;
+ tx->cookie = chan->cookie = cookie;
+
+ return cookie;
+}
+
+/**
+ * dma_cookie_complete - complete a descriptor
+ * @tx: descriptor to complete
+ *
+ * Mark this descriptor complete by updating the channels completed
+ * cookie marker. Zero the descriptors cookie to prevent accidental
+ * repeated completions.
+ *
+ * Note: caller is expected to hold a lock to prevent concurrency.
+ */
+static inline void dma_cookie_complete(struct dma_async_tx_descriptor *tx)
+{
+ BUG_ON(tx->cookie < DMA_MIN_COOKIE);
+ tx->chan->completed_cookie = tx->cookie;
+ tx->cookie = 0;
+}
+
+/**
+ * dma_cookie_status - report cookie status
+ * @chan: dma channel
+ * @cookie: cookie we are interested in
+ * @state: dma_tx_state structure to return last/used cookies
+ *
+ * Report the status of the cookie, filling in the state structure if
+ * non-NULL. No locking is required.
+ */
+static inline enum dma_status dma_cookie_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *state)
+{
+ dma_cookie_t used, complete;
+
+ used = chan->cookie;
+ complete = chan->completed_cookie;
+ barrier();
+ if (state) {
+ state->last = complete;
+ state->used = used;
+ state->residue = 0;
+ }
+ return dma_async_is_complete(cookie, complete, used);
+}
+
+static inline void dma_set_residue(struct dma_tx_state *state, u32 residue)
+{
+ if (state)
+ state->residue = residue;
+}
+
+#endif
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 9b592b02b5f4..7439079f5eed 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -9,6 +9,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
@@ -22,6 +23,7 @@
#include <linux/slab.h>
#include "dw_dmac_regs.h"
+#include "dmaengine.h"
/*
* This supports the Synopsys "DesignWare AHB Central DMA Controller",
@@ -33,19 +35,23 @@
* which does not support descriptor writeback.
*/
-#define DWC_DEFAULT_CTLLO(private) ({ \
- struct dw_dma_slave *__slave = (private); \
- int dms = __slave ? __slave->dst_master : 0; \
- int sms = __slave ? __slave->src_master : 1; \
- u8 smsize = __slave ? __slave->src_msize : DW_DMA_MSIZE_16; \
- u8 dmsize = __slave ? __slave->dst_msize : DW_DMA_MSIZE_16; \
+#define DWC_DEFAULT_CTLLO(_chan) ({ \
+ struct dw_dma_slave *__slave = (_chan->private); \
+ struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \
+ struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \
+ int _dms = __slave ? __slave->dst_master : 0; \
+ int _sms = __slave ? __slave->src_master : 1; \
+ u8 _smsize = __slave ? _sconfig->src_maxburst : \
+ DW_DMA_MSIZE_16; \
+ u8 _dmsize = __slave ? _sconfig->dst_maxburst : \
+ DW_DMA_MSIZE_16; \
\
- (DWC_CTLL_DST_MSIZE(dmsize) \
- | DWC_CTLL_SRC_MSIZE(smsize) \
+ (DWC_CTLL_DST_MSIZE(_dmsize) \
+ | DWC_CTLL_SRC_MSIZE(_smsize) \
| DWC_CTLL_LLP_D_EN \
| DWC_CTLL_LLP_S_EN \
- | DWC_CTLL_DMS(dms) \
- | DWC_CTLL_SMS(sms)); \
+ | DWC_CTLL_DMS(_dms) \
+ | DWC_CTLL_SMS(_sms)); \
})
/*
@@ -151,21 +157,6 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
}
}
-/* Called with dwc->lock held and bh disabled */
-static dma_cookie_t
-dwc_assign_cookie(struct dw_dma_chan *dwc, struct dw_desc *desc)
-{
- dma_cookie_t cookie = dwc->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- dwc->chan.cookie = cookie;
- desc->txd.cookie = cookie;
-
- return cookie;
-}
-
static void dwc_initialize(struct dw_dma_chan *dwc)
{
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
@@ -192,7 +183,6 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
/* Enable interrupts */
channel_set_bit(dw, MASK.XFER, dwc->mask);
- channel_set_bit(dw, MASK.BLOCK, dwc->mask);
channel_set_bit(dw, MASK.ERROR, dwc->mask);
dwc->initialized = true;
@@ -245,7 +235,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
spin_lock_irqsave(&dwc->lock, flags);
- dwc->completed = txd->cookie;
+ dma_cookie_complete(txd);
if (callback_required) {
callback = txd->callback;
param = txd->callback_param;
@@ -329,12 +319,6 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
- /*
- * Clear block interrupt flag before scanning so that we don't
- * miss any, and read LLP before RAW_XFER to ensure it is
- * valid if we decide to scan the list.
- */
- dma_writel(dw, CLEAR.BLOCK, dwc->mask);
llp = channel_readl(dwc, LLP);
status_xfer = dma_readl(dw, RAW.XFER);
@@ -470,17 +454,16 @@ EXPORT_SYMBOL(dw_dma_get_dst_addr);
/* called with dwc->lock held and all DMAC interrupts disabled */
static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
- u32 status_block, u32 status_err, u32 status_xfer)
+ u32 status_err, u32 status_xfer)
{
unsigned long flags;
- if (status_block & dwc->mask) {
+ if (dwc->mask) {
void (*callback)(void *param);
void *callback_param;
dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n",
channel_readl(dwc, LLP));
- dma_writel(dw, CLEAR.BLOCK, dwc->mask);
callback = dwc->cdesc->period_callback;
callback_param = dwc->cdesc->period_callback_param;
@@ -520,7 +503,6 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
channel_writel(dwc, CTL_LO, 0);
channel_writel(dwc, CTL_HI, 0);
- dma_writel(dw, CLEAR.BLOCK, dwc->mask);
dma_writel(dw, CLEAR.ERROR, dwc->mask);
dma_writel(dw, CLEAR.XFER, dwc->mask);
@@ -537,36 +519,29 @@ static void dw_dma_tasklet(unsigned long data)
{
struct dw_dma *dw = (struct dw_dma *)data;
struct dw_dma_chan *dwc;
- u32 status_block;
u32 status_xfer;
u32 status_err;
int i;
- status_block = dma_readl(dw, RAW.BLOCK);
status_xfer = dma_readl(dw, RAW.XFER);
status_err = dma_readl(dw, RAW.ERROR);
- dev_vdbg(dw->dma.dev, "tasklet: status_block=%x status_err=%x\n",
- status_block, status_err);
+ dev_vdbg(dw->dma.dev, "tasklet: status_err=%x\n", status_err);
for (i = 0; i < dw->dma.chancnt; i++) {
dwc = &dw->chan[i];
if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
- dwc_handle_cyclic(dw, dwc, status_block, status_err,
- status_xfer);
+ dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
else if (status_err & (1 << i))
dwc_handle_error(dw, dwc);
- else if ((status_block | status_xfer) & (1 << i))
+ else if (status_xfer & (1 << i))
dwc_scan_descriptors(dw, dwc);
}
/*
- * Re-enable interrupts. Block Complete interrupts are only
- * enabled if the INT_EN bit in the descriptor is set. This
- * will trigger a scan before the whole list is done.
+ * Re-enable interrupts.
*/
channel_set_bit(dw, MASK.XFER, dw->all_chan_mask);
- channel_set_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask);
}
@@ -583,7 +558,6 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
* softirq handler.
*/
channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
status = dma_readl(dw, STATUS_INT);
@@ -594,7 +568,6 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
/* Try to recover */
channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1);
- channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1);
channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1);
channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1);
channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1);
@@ -615,7 +588,7 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
- cookie = dwc_assign_cookie(dwc, desc);
+ cookie = dma_cookie_assign(tx);
/*
* REVISIT: We should attempt to chain as many descriptors as
@@ -674,7 +647,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
else
src_width = dst_width = 0;
- ctllo = DWC_DEFAULT_CTLLO(chan->private)
+ ctllo = DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(dst_width)
| DWC_CTLL_SRC_WIDTH(src_width)
| DWC_CTLL_DST_INC
@@ -731,10 +704,11 @@ err_desc_get:
static struct dma_async_tx_descriptor *
dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma_slave *dws = chan->private;
+ struct dma_slave_config *sconfig = &dwc->dma_sconfig;
struct dw_desc *prev;
struct dw_desc *first;
u32 ctllo;
@@ -750,25 +724,34 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (unlikely(!dws || !sg_len))
return NULL;
- reg_width = dws->reg_width;
prev = first = NULL;
switch (direction) {
case DMA_MEM_TO_DEV:
- ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+ reg_width = __fls(sconfig->dst_addr_width);
+ reg = sconfig->dst_addr;
+ ctllo = (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(reg_width)
| DWC_CTLL_DST_FIX
- | DWC_CTLL_SRC_INC
- | DWC_CTLL_FC(dws->fc));
- reg = dws->tx_reg;
+ | DWC_CTLL_SRC_INC);
+
+ ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
+ DWC_CTLL_FC(DW_DMA_FC_D_M2P);
+
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len, dlen, mem;
mem = sg_phys(sg);
len = sg_dma_len(sg);
- mem_width = 2;
- if (unlikely(mem & 3 || len & 3))
+
+ if (!((mem | len) & 7))
+ mem_width = 3;
+ else if (!((mem | len) & 3))
+ mem_width = 2;
+ else if (!((mem | len) & 1))
+ mem_width = 1;
+ else
mem_width = 0;
slave_sg_todev_fill_desc:
@@ -812,21 +795,30 @@ slave_sg_todev_fill_desc:
}
break;
case DMA_DEV_TO_MEM:
- ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+ reg_width = __fls(sconfig->src_addr_width);
+ reg = sconfig->src_addr;
+ ctllo = (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_SRC_WIDTH(reg_width)
| DWC_CTLL_DST_INC
- | DWC_CTLL_SRC_FIX
- | DWC_CTLL_FC(dws->fc));
+ | DWC_CTLL_SRC_FIX);
+
+ ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
+ DWC_CTLL_FC(DW_DMA_FC_D_P2M);
- reg = dws->rx_reg;
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len, dlen, mem;
mem = sg_phys(sg);
len = sg_dma_len(sg);
- mem_width = 2;
- if (unlikely(mem & 3 || len & 3))
+
+ if (!((mem | len) & 7))
+ mem_width = 3;
+ else if (!((mem | len) & 3))
+ mem_width = 2;
+ else if (!((mem | len) & 1))
+ mem_width = 1;
+ else
mem_width = 0;
slave_sg_fromdev_fill_desc:
@@ -890,6 +882,39 @@ err_desc_get:
return NULL;
}
+/*
+ * Fix sconfig's burst size according to dw_dmac. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+ *
+ * NOTE: burst size 2 is not supported by controller.
+ *
+ * This can be done by finding least significant bit set: n & (n - 1)
+ */
+static inline void convert_burst(u32 *maxburst)
+{
+ if (*maxburst > 1)
+ *maxburst = fls(*maxburst) - 2;
+ else
+ *maxburst = 0;
+}
+
+static int
+set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
+{
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+
+ /* Check if it is chan is configured for slave transfers */
+ if (!chan->private)
+ return -EINVAL;
+
+ memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
+
+ convert_burst(&dwc->dma_sconfig.src_maxburst);
+ convert_burst(&dwc->dma_sconfig.dst_maxburst);
+
+ return 0;
+}
+
static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
unsigned long arg)
{
@@ -939,8 +964,11 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
/* Flush all pending and queued descriptors */
list_for_each_entry_safe(desc, _desc, &list, desc_node)
dwc_descriptor_complete(dwc, desc, false);
- } else
+ } else if (cmd == DMA_SLAVE_CONFIG) {
+ return set_runtime_config(chan, (struct dma_slave_config *)arg);
+ } else {
return -ENXIO;
+ }
return 0;
}
@@ -951,28 +979,17 @@ dwc_tx_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- int ret;
-
- last_complete = dwc->completed;
- last_used = chan->cookie;
+ enum dma_status ret;
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
if (ret != DMA_SUCCESS) {
dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
- last_complete = dwc->completed;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
}
if (ret != DMA_SUCCESS)
- dma_set_tx_state(txstate, last_complete, last_used,
- dwc_first_active(dwc)->len);
- else
- dma_set_tx_state(txstate, last_complete, last_used, 0);
+ dma_set_residue(txstate, dwc_first_active(dwc)->len);
if (dwc->paused)
return DMA_PAUSED;
@@ -1004,7 +1021,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
return -EIO;
}
- dwc->completed = chan->cookie = 1;
+ dma_cookie_init(chan);
/*
* NOTE: some controllers may have additional features that we
@@ -1068,7 +1085,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
/* Disable interrupts */
channel_clear_bit(dw, MASK.XFER, dwc->mask);
- channel_clear_bit(dw, MASK.BLOCK, dwc->mask);
channel_clear_bit(dw, MASK.ERROR, dwc->mask);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1120,7 +1136,6 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
return -EBUSY;
}
- dma_writel(dw, CLEAR.BLOCK, dwc->mask);
dma_writel(dw, CLEAR.ERROR, dwc->mask);
dma_writel(dw, CLEAR.XFER, dwc->mask);
@@ -1175,11 +1190,11 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
enum dma_transfer_direction direction)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct dma_slave_config *sconfig = &dwc->dma_sconfig;
struct dw_cyclic_desc *cdesc;
struct dw_cyclic_desc *retval = NULL;
struct dw_desc *desc;
struct dw_desc *last = NULL;
- struct dw_dma_slave *dws = chan->private;
unsigned long was_cyclic;
unsigned int reg_width;
unsigned int periods;
@@ -1203,7 +1218,12 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
}
retval = ERR_PTR(-EINVAL);
- reg_width = dws->reg_width;
+
+ if (direction == DMA_MEM_TO_DEV)
+ reg_width = __ffs(sconfig->dst_addr_width);
+ else
+ reg_width = __ffs(sconfig->src_addr_width);
+
periods = buf_len / period_len;
/* Check for too big/unaligned periods and unaligned DMA buffer. */
@@ -1236,26 +1256,34 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
switch (direction) {
case DMA_MEM_TO_DEV:
- desc->lli.dar = dws->tx_reg;
+ desc->lli.dar = sconfig->dst_addr;
desc->lli.sar = buf_addr + (period_len * i);
- desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+ desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_DST_WIDTH(reg_width)
| DWC_CTLL_SRC_WIDTH(reg_width)
| DWC_CTLL_DST_FIX
| DWC_CTLL_SRC_INC
- | DWC_CTLL_FC(dws->fc)
| DWC_CTLL_INT_EN);
+
+ desc->lli.ctllo |= sconfig->device_fc ?
+ DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
+ DWC_CTLL_FC(DW_DMA_FC_D_M2P);
+
break;
case DMA_DEV_TO_MEM:
desc->lli.dar = buf_addr + (period_len * i);
- desc->lli.sar = dws->rx_reg;
- desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
+ desc->lli.sar = sconfig->src_addr;
+ desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan)
| DWC_CTLL_SRC_WIDTH(reg_width)
| DWC_CTLL_DST_WIDTH(reg_width)
| DWC_CTLL_DST_INC
| DWC_CTLL_SRC_FIX
- | DWC_CTLL_FC(dws->fc)
| DWC_CTLL_INT_EN);
+
+ desc->lli.ctllo |= sconfig->device_fc ?
+ DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
+ DWC_CTLL_FC(DW_DMA_FC_D_P2M);
+
break;
default:
break;
@@ -1322,7 +1350,6 @@ void dw_dma_cyclic_free(struct dma_chan *chan)
while (dma_readl(dw, CH_EN) & dwc->mask)
cpu_relax();
- dma_writel(dw, CLEAR.BLOCK, dwc->mask);
dma_writel(dw, CLEAR.ERROR, dwc->mask);
dma_writel(dw, CLEAR.XFER, dwc->mask);
@@ -1347,7 +1374,6 @@ static void dw_dma_off(struct dw_dma *dw)
dma_writel(dw, CFG, 0);
channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
@@ -1369,7 +1395,7 @@ static int __init dw_probe(struct platform_device *pdev)
int err;
int i;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata || pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS)
return -EINVAL;
@@ -1423,7 +1449,7 @@ static int __init dw_probe(struct platform_device *pdev)
struct dw_dma_chan *dwc = &dw->chan[i];
dwc->chan.device = &dw->dma;
- dwc->chan.cookie = dwc->completed = 1;
+ dma_cookie_init(&dwc->chan);
if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING)
list_add_tail(&dwc->chan.device_node,
&dw->dma.channels);
@@ -1432,7 +1458,7 @@ static int __init dw_probe(struct platform_device *pdev)
/* 7 is highest priority & 0 is lowest. */
if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
- dwc->priority = 7 - i;
+ dwc->priority = pdata->nr_channels - i - 1;
else
dwc->priority = i;
@@ -1449,13 +1475,11 @@ static int __init dw_probe(struct platform_device *pdev)
/* Clear/disable all interrupts on all channels. */
dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
- dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask);
dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
- channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
@@ -1562,6 +1586,10 @@ static int dw_resume_noirq(struct device *dev)
static const struct dev_pm_ops dw_dev_pm_ops = {
.suspend_noirq = dw_suspend_noirq,
.resume_noirq = dw_resume_noirq,
+ .freeze_noirq = dw_suspend_noirq,
+ .thaw_noirq = dw_resume_noirq,
+ .restore_noirq = dw_resume_noirq,
+ .poweroff_noirq = dw_suspend_noirq,
};
static struct platform_driver dw_driver = {
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 5eef6946a367..f298f69ecbf9 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -13,6 +13,18 @@
#define DW_DMA_MAX_NR_CHANNELS 8
+/* flow controller */
+enum dw_dma_fc {
+ DW_DMA_FC_D_M2M,
+ DW_DMA_FC_D_M2P,
+ DW_DMA_FC_D_P2M,
+ DW_DMA_FC_D_P2P,
+ DW_DMA_FC_P_P2M,
+ DW_DMA_FC_SP_P2P,
+ DW_DMA_FC_P_M2P,
+ DW_DMA_FC_DP_P2P,
+};
+
/*
* Redefine this macro to handle differences between 32- and 64-bit
* addressing, big vs. little endian, etc.
@@ -146,13 +158,15 @@ struct dw_dma_chan {
/* these other elements are all protected by lock */
unsigned long flags;
- dma_cookie_t completed;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
struct dw_cyclic_desc *cdesc;
unsigned int descs_allocated;
+
+ /* configuration passed via DMA_SLAVE_CONFIG */
+ struct dma_slave_config dma_sconfig;
};
static inline struct dw_dma_chan_regs __iomem *
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 59e7a965772b..e6f133b78dc2 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -28,6 +28,8 @@
#include <mach/dma.h>
+#include "dmaengine.h"
+
/* M2P registers */
#define M2P_CONTROL 0x0000
#define M2P_CONTROL_STALLINT BIT(0)
@@ -122,7 +124,6 @@ struct ep93xx_dma_desc {
* @lock: lock protecting the fields following
* @flags: flags for the channel
* @buffer: which buffer to use next (0/1)
- * @last_completed: last completed cookie value
* @active: flattened chain of descriptors currently being processed
* @queue: pending descriptors which are handled next
* @free_list: list of free descriptors which can be used
@@ -157,7 +158,6 @@ struct ep93xx_dma_chan {
#define EP93XX_DMA_IS_CYCLIC 0
int buffer;
- dma_cookie_t last_completed;
struct list_head active;
struct list_head queue;
struct list_head free_list;
@@ -703,7 +703,7 @@ static void ep93xx_dma_tasklet(unsigned long data)
desc = ep93xx_dma_get_active(edmac);
if (desc) {
if (desc->complete) {
- edmac->last_completed = desc->txd.cookie;
+ dma_cookie_complete(&desc->txd);
list_splice_init(&edmac->active, &list);
}
callback = desc->txd.callback;
@@ -783,17 +783,10 @@ static dma_cookie_t ep93xx_dma_tx_submit(struct dma_async_tx_descriptor *tx)
unsigned long flags;
spin_lock_irqsave(&edmac->lock, flags);
-
- cookie = edmac->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
+ cookie = dma_cookie_assign(tx);
desc = container_of(tx, struct ep93xx_dma_desc, txd);
- edmac->chan.cookie = cookie;
- desc->txd.cookie = cookie;
-
/*
* If nothing is currently prosessed, we push this descriptor
* directly to the hardware. Otherwise we put the descriptor
@@ -861,8 +854,7 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan)
goto fail_clk_disable;
spin_lock_irq(&edmac->lock);
- edmac->last_completed = 1;
- edmac->chan.cookie = 1;
+ dma_cookie_init(&edmac->chan);
ret = edmac->edma->hw_setup(edmac);
spin_unlock_irq(&edmac->lock);
@@ -983,13 +975,14 @@ fail:
* @sg_len: number of entries in @sgl
* @dir: direction of tha DMA transfer
* @flags: flags for the descriptor
+ * @context: operation context (ignored)
*
* Returns a valid DMA descriptor or %NULL in case of failure.
*/
static struct dma_async_tx_descriptor *
ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction dir,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
struct ep93xx_dma_desc *desc, *first;
@@ -1056,6 +1049,7 @@ fail:
* @buf_len: length of the buffer (in bytes)
* @period_len: lenght of a single period
* @dir: direction of the operation
+ * @context: operation context (ignored)
*
* Prepares a descriptor for cyclic DMA operation. This means that once the
* descriptor is submitted, we will be submitting in a @period_len sized
@@ -1068,7 +1062,7 @@ fail:
static struct dma_async_tx_descriptor *
ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
size_t buf_len, size_t period_len,
- enum dma_transfer_direction dir)
+ enum dma_transfer_direction dir, void *context)
{
struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
struct ep93xx_dma_desc *desc, *first;
@@ -1248,18 +1242,13 @@ static enum dma_status ep93xx_dma_tx_status(struct dma_chan *chan,
struct dma_tx_state *state)
{
struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
- dma_cookie_t last_used, last_completed;
enum dma_status ret;
unsigned long flags;
spin_lock_irqsave(&edmac->lock, flags);
- last_used = chan->cookie;
- last_completed = edmac->last_completed;
+ ret = dma_cookie_status(chan, cookie, state);
spin_unlock_irqrestore(&edmac->lock, flags);
- ret = dma_async_is_complete(cookie, last_completed, last_used);
- dma_set_tx_state(state, last_completed, last_used, 0);
-
return ret;
}
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index b98070c33ca9..8f84761f98ba 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -35,6 +35,7 @@
#include <linux/dmapool.h>
#include <linux/of_platform.h>
+#include "dmaengine.h"
#include "fsldma.h"
#define chan_dbg(chan, fmt, arg...) \
@@ -413,17 +414,10 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
* assign cookies to all of the software descriptors
* that make up this transaction
*/
- cookie = chan->common.cookie;
list_for_each_entry(child, &desc->tx_list, node) {
- cookie++;
- if (cookie < DMA_MIN_COOKIE)
- cookie = DMA_MIN_COOKIE;
-
- child->async_tx.cookie = cookie;
+ cookie = dma_cookie_assign(&child->async_tx);
}
- chan->common.cookie = cookie;
-
/* put this transaction onto the tail of the pending queue */
append_ld_queue(chan, desc);
@@ -765,6 +759,7 @@ fail:
* @sg_len: number of entries in @scatterlist
* @direction: DMA direction
* @flags: DMAEngine flags
+ * @context: transaction context (ignored)
*
* Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
* DMA_SLAVE API, this gets the device-specific information from the
@@ -772,7 +767,8 @@ fail:
*/
static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
- enum dma_transfer_direction direction, unsigned long flags)
+ enum dma_transfer_direction direction, unsigned long flags,
+ void *context)
{
/*
* This operation is not supported on the Freescale DMA controller
@@ -984,19 +980,14 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
struct dma_tx_state *txstate)
{
struct fsldma_chan *chan = to_fsl_chan(dchan);
- dma_cookie_t last_complete;
- dma_cookie_t last_used;
+ enum dma_status ret;
unsigned long flags;
spin_lock_irqsave(&chan->desc_lock, flags);
-
- last_complete = chan->completed_cookie;
- last_used = dchan->cookie;
-
+ ret = dma_cookie_status(dchan, cookie, txstate);
spin_unlock_irqrestore(&chan->desc_lock, flags);
- dma_set_tx_state(txstate, last_complete, last_used, 0);
- return dma_async_is_complete(cookie, last_complete, last_used);
+ return ret;
}
/*----------------------------------------------------------------------------*/
@@ -1087,8 +1078,8 @@ static void dma_do_tasklet(unsigned long data)
desc = to_fsl_desc(chan->ld_running.prev);
cookie = desc->async_tx.cookie;
+ dma_cookie_complete(&desc->async_tx);
- chan->completed_cookie = cookie;
chan_dbg(chan, "completed_cookie=%d\n", cookie);
}
@@ -1303,6 +1294,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
chan->idle = true;
chan->common.device = &fdev->common;
+ dma_cookie_init(&chan->common);
/* find the IRQ line, if it exists in the device tree */
chan->irq = irq_of_parse_and_map(node, 0);
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 9cb5aa57c677..f5c38791fc74 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -137,7 +137,6 @@ struct fsldma_device {
struct fsldma_chan {
char name[8]; /* Channel name */
struct fsldma_chan_regs __iomem *regs;
- dma_cookie_t completed_cookie; /* The maximum cookie completed */
spinlock_t desc_lock; /* Descriptor operation lock */
struct list_head ld_pending; /* Link descriptors queue */
struct list_head ld_running; /* Link descriptors queue */
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 38586ba8da91..a45b5d2a5987 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -5,6 +5,7 @@
* found on i.MX1/21/27
*
* Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2012 Javier Martin, Vista Silicon <javier.martin@vista-silicon.com>
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -22,37 +23,159 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <asm/irq.h>
-#include <mach/dma-v1.h>
+#include <mach/dma.h>
#include <mach/hardware.h>
+#include "dmaengine.h"
+#define IMXDMA_MAX_CHAN_DESCRIPTORS 16
+#define IMX_DMA_CHANNELS 16
+
+#define IMX_DMA_2D_SLOTS 2
+#define IMX_DMA_2D_SLOT_A 0
+#define IMX_DMA_2D_SLOT_B 1
+
+#define IMX_DMA_LENGTH_LOOP ((unsigned int)-1)
+#define IMX_DMA_MEMSIZE_32 (0 << 4)
+#define IMX_DMA_MEMSIZE_8 (1 << 4)
+#define IMX_DMA_MEMSIZE_16 (2 << 4)
+#define IMX_DMA_TYPE_LINEAR (0 << 10)
+#define IMX_DMA_TYPE_2D (1 << 10)
+#define IMX_DMA_TYPE_FIFO (2 << 10)
+
+#define IMX_DMA_ERR_BURST (1 << 0)
+#define IMX_DMA_ERR_REQUEST (1 << 1)
+#define IMX_DMA_ERR_TRANSFER (1 << 2)
+#define IMX_DMA_ERR_BUFFER (1 << 3)
+#define IMX_DMA_ERR_TIMEOUT (1 << 4)
+
+#define DMA_DCR 0x00 /* Control Register */
+#define DMA_DISR 0x04 /* Interrupt status Register */
+#define DMA_DIMR 0x08 /* Interrupt mask Register */
+#define DMA_DBTOSR 0x0c /* Burst timeout status Register */
+#define DMA_DRTOSR 0x10 /* Request timeout Register */
+#define DMA_DSESR 0x14 /* Transfer Error Status Register */
+#define DMA_DBOSR 0x18 /* Buffer overflow status Register */
+#define DMA_DBTOCR 0x1c /* Burst timeout control Register */
+#define DMA_WSRA 0x40 /* W-Size Register A */
+#define DMA_XSRA 0x44 /* X-Size Register A */
+#define DMA_YSRA 0x48 /* Y-Size Register A */
+#define DMA_WSRB 0x4c /* W-Size Register B */
+#define DMA_XSRB 0x50 /* X-Size Register B */
+#define DMA_YSRB 0x54 /* Y-Size Register B */
+#define DMA_SAR(x) (0x80 + ((x) << 6)) /* Source Address Registers */
+#define DMA_DAR(x) (0x84 + ((x) << 6)) /* Destination Address Registers */
+#define DMA_CNTR(x) (0x88 + ((x) << 6)) /* Count Registers */
+#define DMA_CCR(x) (0x8c + ((x) << 6)) /* Control Registers */
+#define DMA_RSSR(x) (0x90 + ((x) << 6)) /* Request source select Registers */
+#define DMA_BLR(x) (0x94 + ((x) << 6)) /* Burst length Registers */
+#define DMA_RTOR(x) (0x98 + ((x) << 6)) /* Request timeout Registers */
+#define DMA_BUCR(x) (0x98 + ((x) << 6)) /* Bus Utilization Registers */
+#define DMA_CCNR(x) (0x9C + ((x) << 6)) /* Channel counter Registers */
+
+#define DCR_DRST (1<<1)
+#define DCR_DEN (1<<0)
+#define DBTOCR_EN (1<<15)
+#define DBTOCR_CNT(x) ((x) & 0x7fff)
+#define CNTR_CNT(x) ((x) & 0xffffff)
+#define CCR_ACRPT (1<<14)
+#define CCR_DMOD_LINEAR (0x0 << 12)
+#define CCR_DMOD_2D (0x1 << 12)
+#define CCR_DMOD_FIFO (0x2 << 12)
+#define CCR_DMOD_EOBFIFO (0x3 << 12)
+#define CCR_SMOD_LINEAR (0x0 << 10)
+#define CCR_SMOD_2D (0x1 << 10)
+#define CCR_SMOD_FIFO (0x2 << 10)
+#define CCR_SMOD_EOBFIFO (0x3 << 10)
+#define CCR_MDIR_DEC (1<<9)
+#define CCR_MSEL_B (1<<8)
+#define CCR_DSIZ_32 (0x0 << 6)
+#define CCR_DSIZ_8 (0x1 << 6)
+#define CCR_DSIZ_16 (0x2 << 6)
+#define CCR_SSIZ_32 (0x0 << 4)
+#define CCR_SSIZ_8 (0x1 << 4)
+#define CCR_SSIZ_16 (0x2 << 4)
+#define CCR_REN (1<<3)
+#define CCR_RPT (1<<2)
+#define CCR_FRC (1<<1)
+#define CCR_CEN (1<<0)
+#define RTOR_EN (1<<15)
+#define RTOR_CLK (1<<14)
+#define RTOR_PSC (1<<13)
+
+enum imxdma_prep_type {
+ IMXDMA_DESC_MEMCPY,
+ IMXDMA_DESC_INTERLEAVED,
+ IMXDMA_DESC_SLAVE_SG,
+ IMXDMA_DESC_CYCLIC,
+};
+
+struct imx_dma_2d_config {
+ u16 xsr;
+ u16 ysr;
+ u16 wsr;
+ int count;
+};
+
+struct imxdma_desc {
+ struct list_head node;
+ struct dma_async_tx_descriptor desc;
+ enum dma_status status;
+ dma_addr_t src;
+ dma_addr_t dest;
+ size_t len;
+ enum dma_transfer_direction direction;
+ enum imxdma_prep_type type;
+ /* For memcpy and interleaved */
+ unsigned int config_port;
+ unsigned int config_mem;
+ /* For interleaved transfers */
+ unsigned int x;
+ unsigned int y;
+ unsigned int w;
+ /* For slave sg and cyclic */
+ struct scatterlist *sg;
+ unsigned int sgcount;
+};
+
struct imxdma_channel {
+ int hw_chaining;
+ struct timer_list watchdog;
struct imxdma_engine *imxdma;
unsigned int channel;
- unsigned int imxdma_channel;
+ struct tasklet_struct dma_tasklet;
+ struct list_head ld_free;
+ struct list_head ld_queue;
+ struct list_head ld_active;
+ int descs_allocated;
enum dma_slave_buswidth word_size;
dma_addr_t per_address;
u32 watermark_level;
struct dma_chan chan;
- spinlock_t lock;
struct dma_async_tx_descriptor desc;
- dma_cookie_t last_completed;
enum dma_status status;
int dma_request;
struct scatterlist *sg_list;
+ u32 ccr_from_device;
+ u32 ccr_to_device;
+ bool enabled_2d;
+ int slot_2d;
};
-#define MAX_DMA_CHANNELS 8
-
struct imxdma_engine {
struct device *dev;
struct device_dma_parameters dma_parms;
struct dma_device dma_device;
- struct imxdma_channel channel[MAX_DMA_CHANNELS];
+ void __iomem *base;
+ struct clk *dma_clk;
+ spinlock_t lock;
+ struct imx_dma_2d_config slots_2d[IMX_DMA_2D_SLOTS];
+ struct imxdma_channel channel[IMX_DMA_CHANNELS];
};
static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
@@ -60,36 +183,418 @@ static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
return container_of(chan, struct imxdma_channel, chan);
}
-static void imxdma_handle(struct imxdma_channel *imxdmac)
+static inline bool imxdma_chan_is_doing_cyclic(struct imxdma_channel *imxdmac)
+{
+ struct imxdma_desc *desc;
+
+ if (!list_empty(&imxdmac->ld_active)) {
+ desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc,
+ node);
+ if (desc->type == IMXDMA_DESC_CYCLIC)
+ return true;
+ }
+ return false;
+}
+
+
+
+static void imx_dmav1_writel(struct imxdma_engine *imxdma, unsigned val,
+ unsigned offset)
+{
+ __raw_writel(val, imxdma->base + offset);
+}
+
+static unsigned imx_dmav1_readl(struct imxdma_engine *imxdma, unsigned offset)
+{
+ return __raw_readl(imxdma->base + offset);
+}
+
+static int imxdma_hw_chain(struct imxdma_channel *imxdmac)
+{
+ if (cpu_is_mx27())
+ return imxdmac->hw_chaining;
+ else
+ return 0;
+}
+
+/*
+ * imxdma_sg_next - prepare next chunk for scatter-gather DMA emulation
+ */
+static inline int imxdma_sg_next(struct imxdma_desc *d)
{
- if (imxdmac->desc.callback)
- imxdmac->desc.callback(imxdmac->desc.callback_param);
- imxdmac->last_completed = imxdmac->desc.cookie;
+ struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ struct scatterlist *sg = d->sg;
+ unsigned long now;
+
+ now = min(d->len, sg->length);
+ if (d->len != IMX_DMA_LENGTH_LOOP)
+ d->len -= now;
+
+ if (d->direction == DMA_DEV_TO_MEM)
+ imx_dmav1_writel(imxdma, sg->dma_address,
+ DMA_DAR(imxdmac->channel));
+ else
+ imx_dmav1_writel(imxdma, sg->dma_address,
+ DMA_SAR(imxdmac->channel));
+
+ imx_dmav1_writel(imxdma, now, DMA_CNTR(imxdmac->channel));
+
+ dev_dbg(imxdma->dev, " %s channel: %d dst 0x%08x, src 0x%08x, "
+ "size 0x%08x\n", __func__, imxdmac->channel,
+ imx_dmav1_readl(imxdma, DMA_DAR(imxdmac->channel)),
+ imx_dmav1_readl(imxdma, DMA_SAR(imxdmac->channel)),
+ imx_dmav1_readl(imxdma, DMA_CNTR(imxdmac->channel)));
+
+ return now;
}
-static void imxdma_irq_handler(int channel, void *data)
+static void imxdma_enable_hw(struct imxdma_desc *d)
{
- struct imxdma_channel *imxdmac = data;
+ struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ int channel = imxdmac->channel;
+ unsigned long flags;
+
+ dev_dbg(imxdma->dev, "%s channel %d\n", __func__, channel);
+
+ local_irq_save(flags);
+
+ imx_dmav1_writel(imxdma, 1 << channel, DMA_DISR);
+ imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_DIMR) &
+ ~(1 << channel), DMA_DIMR);
+ imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) |
+ CCR_CEN | CCR_ACRPT, DMA_CCR(channel));
+
+ if ((cpu_is_mx21() || cpu_is_mx27()) &&
+ d->sg && imxdma_hw_chain(imxdmac)) {
+ d->sg = sg_next(d->sg);
+ if (d->sg) {
+ u32 tmp;
+ imxdma_sg_next(d);
+ tmp = imx_dmav1_readl(imxdma, DMA_CCR(channel));
+ imx_dmav1_writel(imxdma, tmp | CCR_RPT | CCR_ACRPT,
+ DMA_CCR(channel));
+ }
+ }
+
+ local_irq_restore(flags);
+}
+
+static void imxdma_disable_hw(struct imxdma_channel *imxdmac)
+{
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ int channel = imxdmac->channel;
+ unsigned long flags;
+
+ dev_dbg(imxdma->dev, "%s channel %d\n", __func__, channel);
+
+ if (imxdma_hw_chain(imxdmac))
+ del_timer(&imxdmac->watchdog);
+
+ local_irq_save(flags);
+ imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_DIMR) |
+ (1 << channel), DMA_DIMR);
+ imx_dmav1_writel(imxdma, imx_dmav1_readl(imxdma, DMA_CCR(channel)) &
+ ~CCR_CEN, DMA_CCR(channel));
+ imx_dmav1_writel(imxdma, 1 << channel, DMA_DISR);
+ local_irq_restore(flags);
+}
+
+static void imxdma_watchdog(unsigned long data)
+{
+ struct imxdma_channel *imxdmac = (struct imxdma_channel *)data;
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ int channel = imxdmac->channel;
+
+ imx_dmav1_writel(imxdma, 0, DMA_CCR(channel));
- imxdmac->status = DMA_SUCCESS;
- imxdma_handle(imxdmac);
+ /* Tasklet watchdog error handler */
+ tasklet_schedule(&imxdmac->dma_tasklet);
+ dev_dbg(imxdma->dev, "channel %d: watchdog timeout!\n",
+ imxdmac->channel);
}
-static void imxdma_err_handler(int channel, void *data, int error)
+static irqreturn_t imxdma_err_handler(int irq, void *dev_id)
{
- struct imxdma_channel *imxdmac = data;
+ struct imxdma_engine *imxdma = dev_id;
+ unsigned int err_mask;
+ int i, disr;
+ int errcode;
+
+ disr = imx_dmav1_readl(imxdma, DMA_DISR);
+
+ err_mask = imx_dmav1_readl(imxdma, DMA_DBTOSR) |
+ imx_dmav1_readl(imxdma, DMA_DRTOSR) |
+ imx_dmav1_readl(imxdma, DMA_DSESR) |
+ imx_dmav1_readl(imxdma, DMA_DBOSR);
+
+ if (!err_mask)
+ return IRQ_HANDLED;
+
+ imx_dmav1_writel(imxdma, disr & err_mask, DMA_DISR);
+
+ for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+ if (!(err_mask & (1 << i)))
+ continue;
+ errcode = 0;
+
+ if (imx_dmav1_readl(imxdma, DMA_DBTOSR) & (1 << i)) {
+ imx_dmav1_writel(imxdma, 1 << i, DMA_DBTOSR);
+ errcode |= IMX_DMA_ERR_BURST;
+ }
+ if (imx_dmav1_readl(imxdma, DMA_DRTOSR) & (1 << i)) {
+ imx_dmav1_writel(imxdma, 1 << i, DMA_DRTOSR);
+ errcode |= IMX_DMA_ERR_REQUEST;
+ }
+ if (imx_dmav1_readl(imxdma, DMA_DSESR) & (1 << i)) {
+ imx_dmav1_writel(imxdma, 1 << i, DMA_DSESR);
+ errcode |= IMX_DMA_ERR_TRANSFER;
+ }
+ if (imx_dmav1_readl(imxdma, DMA_DBOSR) & (1 << i)) {
+ imx_dmav1_writel(imxdma, 1 << i, DMA_DBOSR);
+ errcode |= IMX_DMA_ERR_BUFFER;
+ }
+ /* Tasklet error handler */
+ tasklet_schedule(&imxdma->channel[i].dma_tasklet);
+
+ printk(KERN_WARNING
+ "DMA timeout on channel %d -%s%s%s%s\n", i,
+ errcode & IMX_DMA_ERR_BURST ? " burst" : "",
+ errcode & IMX_DMA_ERR_REQUEST ? " request" : "",
+ errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
+ errcode & IMX_DMA_ERR_BUFFER ? " buffer" : "");
+ }
+ return IRQ_HANDLED;
+}
+
+static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
+{
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ int chno = imxdmac->channel;
+ struct imxdma_desc *desc;
+
+ spin_lock(&imxdma->lock);
+ if (list_empty(&imxdmac->ld_active)) {
+ spin_unlock(&imxdma->lock);
+ goto out;
+ }
+
+ desc = list_first_entry(&imxdmac->ld_active,
+ struct imxdma_desc,
+ node);
+ spin_unlock(&imxdma->lock);
+
+ if (desc->sg) {
+ u32 tmp;
+ desc->sg = sg_next(desc->sg);
+
+ if (desc->sg) {
+ imxdma_sg_next(desc);
+
+ tmp = imx_dmav1_readl(imxdma, DMA_CCR(chno));
+
+ if (imxdma_hw_chain(imxdmac)) {
+ /* FIXME: The timeout should probably be
+ * configurable
+ */
+ mod_timer(&imxdmac->watchdog,
+ jiffies + msecs_to_jiffies(500));
+
+ tmp |= CCR_CEN | CCR_RPT | CCR_ACRPT;
+ imx_dmav1_writel(imxdma, tmp, DMA_CCR(chno));
+ } else {
+ imx_dmav1_writel(imxdma, tmp & ~CCR_CEN,
+ DMA_CCR(chno));
+ tmp |= CCR_CEN;
+ }
+
+ imx_dmav1_writel(imxdma, tmp, DMA_CCR(chno));
+
+ if (imxdma_chan_is_doing_cyclic(imxdmac))
+ /* Tasklet progression */
+ tasklet_schedule(&imxdmac->dma_tasklet);
+
+ return;
+ }
+
+ if (imxdma_hw_chain(imxdmac)) {
+ del_timer(&imxdmac->watchdog);
+ return;
+ }
+ }
+
+out:
+ imx_dmav1_writel(imxdma, 0, DMA_CCR(chno));
+ /* Tasklet irq */
+ tasklet_schedule(&imxdmac->dma_tasklet);
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+{
+ struct imxdma_engine *imxdma = dev_id;
+ int i, disr;
+
+ if (cpu_is_mx21() || cpu_is_mx27())
+ imxdma_err_handler(irq, dev_id);
+
+ disr = imx_dmav1_readl(imxdma, DMA_DISR);
+
+ dev_dbg(imxdma->dev, "%s called, disr=0x%08x\n", __func__, disr);
+
+ imx_dmav1_writel(imxdma, disr, DMA_DISR);
+ for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+ if (disr & (1 << i))
+ dma_irq_handle_channel(&imxdma->channel[i]);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int imxdma_xfer_desc(struct imxdma_desc *d)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ unsigned long flags;
+ int slot = -1;
+ int i;
+
+ /* Configure and enable */
+ switch (d->type) {
+ case IMXDMA_DESC_INTERLEAVED:
+ /* Try to get a free 2D slot */
+ spin_lock_irqsave(&imxdma->lock, flags);
+ for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
+ if ((imxdma->slots_2d[i].count > 0) &&
+ ((imxdma->slots_2d[i].xsr != d->x) ||
+ (imxdma->slots_2d[i].ysr != d->y) ||
+ (imxdma->slots_2d[i].wsr != d->w)))
+ continue;
+ slot = i;
+ break;
+ }
+ if (slot < 0)
+ return -EBUSY;
+
+ imxdma->slots_2d[slot].xsr = d->x;
+ imxdma->slots_2d[slot].ysr = d->y;
+ imxdma->slots_2d[slot].wsr = d->w;
+ imxdma->slots_2d[slot].count++;
+
+ imxdmac->slot_2d = slot;
+ imxdmac->enabled_2d = true;
+ spin_unlock_irqrestore(&imxdma->lock, flags);
+
+ if (slot == IMX_DMA_2D_SLOT_A) {
+ d->config_mem &= ~CCR_MSEL_B;
+ d->config_port &= ~CCR_MSEL_B;
+ imx_dmav1_writel(imxdma, d->x, DMA_XSRA);
+ imx_dmav1_writel(imxdma, d->y, DMA_YSRA);
+ imx_dmav1_writel(imxdma, d->w, DMA_WSRA);
+ } else {
+ d->config_mem |= CCR_MSEL_B;
+ d->config_port |= CCR_MSEL_B;
+ imx_dmav1_writel(imxdma, d->x, DMA_XSRB);
+ imx_dmav1_writel(imxdma, d->y, DMA_YSRB);
+ imx_dmav1_writel(imxdma, d->w, DMA_WSRB);
+ }
+ /*
+ * We fall-through here intentionally, since a 2D transfer is
+ * similar to MEMCPY just adding the 2D slot configuration.
+ */
+ case IMXDMA_DESC_MEMCPY:
+ imx_dmav1_writel(imxdma, d->src, DMA_SAR(imxdmac->channel));
+ imx_dmav1_writel(imxdma, d->dest, DMA_DAR(imxdmac->channel));
+ imx_dmav1_writel(imxdma, d->config_mem | (d->config_port << 2),
+ DMA_CCR(imxdmac->channel));
+
+ imx_dmav1_writel(imxdma, d->len, DMA_CNTR(imxdmac->channel));
+
+ dev_dbg(imxdma->dev, "%s channel: %d dest=0x%08x src=0x%08x "
+ "dma_length=%d\n", __func__, imxdmac->channel,
+ d->dest, d->src, d->len);
+
+ break;
+ /* Cyclic transfer is the same as slave_sg with special sg configuration. */
+ case IMXDMA_DESC_CYCLIC:
+ case IMXDMA_DESC_SLAVE_SG:
+ if (d->direction == DMA_DEV_TO_MEM) {
+ imx_dmav1_writel(imxdma, imxdmac->per_address,
+ DMA_SAR(imxdmac->channel));
+ imx_dmav1_writel(imxdma, imxdmac->ccr_from_device,
+ DMA_CCR(imxdmac->channel));
+
+ dev_dbg(imxdma->dev, "%s channel: %d sg=%p sgcount=%d "
+ "total length=%d dev_addr=0x%08x (dev2mem)\n",
+ __func__, imxdmac->channel, d->sg, d->sgcount,
+ d->len, imxdmac->per_address);
+ } else if (d->direction == DMA_MEM_TO_DEV) {
+ imx_dmav1_writel(imxdma, imxdmac->per_address,
+ DMA_DAR(imxdmac->channel));
+ imx_dmav1_writel(imxdma, imxdmac->ccr_to_device,
+ DMA_CCR(imxdmac->channel));
+
+ dev_dbg(imxdma->dev, "%s channel: %d sg=%p sgcount=%d "
+ "total length=%d dev_addr=0x%08x (mem2dev)\n",
+ __func__, imxdmac->channel, d->sg, d->sgcount,
+ d->len, imxdmac->per_address);
+ } else {
+ dev_err(imxdma->dev, "%s channel: %d bad dma mode\n",
+ __func__, imxdmac->channel);
+ return -EINVAL;
+ }
+
+ imxdma_sg_next(d);
- imxdmac->status = DMA_ERROR;
- imxdma_handle(imxdmac);
+ break;
+ default:
+ return -EINVAL;
+ }
+ imxdma_enable_hw(d);
+ return 0;
}
-static void imxdma_progression(int channel, void *data,
- struct scatterlist *sg)
+static void imxdma_tasklet(unsigned long data)
{
- struct imxdma_channel *imxdmac = data;
+ struct imxdma_channel *imxdmac = (void *)data;
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ struct imxdma_desc *desc;
- imxdmac->status = DMA_SUCCESS;
- imxdma_handle(imxdmac);
+ spin_lock(&imxdma->lock);
+
+ if (list_empty(&imxdmac->ld_active)) {
+ /* Someone might have called terminate all */
+ goto out;
+ }
+ desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc, node);
+
+ if (desc->desc.callback)
+ desc->desc.callback(desc->desc.callback_param);
+
+ dma_cookie_complete(&desc->desc);
+
+ /* If we are dealing with a cyclic descriptor keep it on ld_active */
+ if (imxdma_chan_is_doing_cyclic(imxdmac))
+ goto out;
+
+ /* Free 2D slot if it was an interleaved transfer */
+ if (imxdmac->enabled_2d) {
+ imxdma->slots_2d[imxdmac->slot_2d].count--;
+ imxdmac->enabled_2d = false;
+ }
+
+ list_move_tail(imxdmac->ld_active.next, &imxdmac->ld_free);
+
+ if (!list_empty(&imxdmac->ld_queue)) {
+ desc = list_first_entry(&imxdmac->ld_queue, struct imxdma_desc,
+ node);
+ list_move_tail(imxdmac->ld_queue.next, &imxdmac->ld_active);
+ if (imxdma_xfer_desc(desc) < 0)
+ dev_warn(imxdma->dev, "%s: channel: %d couldn't xfer desc\n",
+ __func__, imxdmac->channel);
+ }
+out:
+ spin_unlock(&imxdma->lock);
}
static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -97,13 +602,18 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
{
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
struct dma_slave_config *dmaengine_cfg = (void *)arg;
- int ret;
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ unsigned long flags;
unsigned int mode = 0;
switch (cmd) {
case DMA_TERMINATE_ALL:
- imxdmac->status = DMA_ERROR;
- imx_dma_disable(imxdmac->imxdma_channel);
+ imxdma_disable_hw(imxdmac);
+
+ spin_lock_irqsave(&imxdma->lock, flags);
+ list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
+ list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
+ spin_unlock_irqrestore(&imxdma->lock, flags);
return 0;
case DMA_SLAVE_CONFIG:
if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
@@ -128,16 +638,22 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
mode = IMX_DMA_MEMSIZE_32;
break;
}
- ret = imx_dma_config_channel(imxdmac->imxdma_channel,
- mode | IMX_DMA_TYPE_FIFO,
- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
- imxdmac->dma_request, 1);
-
- if (ret)
- return ret;
- imx_dma_config_burstlen(imxdmac->imxdma_channel,
- imxdmac->watermark_level * imxdmac->word_size);
+ imxdmac->hw_chaining = 1;
+ if (!imxdma_hw_chain(imxdmac))
+ return -EINVAL;
+ imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) |
+ ((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) |
+ CCR_REN;
+ imxdmac->ccr_to_device =
+ (IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) |
+ ((mode | IMX_DMA_TYPE_FIFO) << 2) | CCR_REN;
+ imx_dmav1_writel(imxdma, imxdmac->dma_request,
+ DMA_RSSR(imxdmac->channel));
+
+ /* Set burst length */
+ imx_dmav1_writel(imxdma, imxdmac->watermark_level *
+ imxdmac->word_size, DMA_BLR(imxdmac->channel));
return 0;
default:
@@ -151,43 +667,20 @@ static enum dma_status imxdma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
- struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
- dma_cookie_t last_used;
- enum dma_status ret;
-
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, imxdmac->last_completed, last_used);
- dma_set_tx_state(txstate, imxdmac->last_completed, last_used, 0);
-
- return ret;
-}
-
-static dma_cookie_t imxdma_assign_cookie(struct imxdma_channel *imxdma)
-{
- dma_cookie_t cookie = imxdma->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- imxdma->chan.cookie = cookie;
- imxdma->desc.cookie = cookie;
-
- return cookie;
+ return dma_cookie_status(chan, cookie, txstate);
}
static dma_cookie_t imxdma_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct imxdma_channel *imxdmac = to_imxdma_chan(tx->chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
dma_cookie_t cookie;
+ unsigned long flags;
- spin_lock_irq(&imxdmac->lock);
-
- cookie = imxdma_assign_cookie(imxdmac);
-
- imx_dma_enable(imxdmac->imxdma_channel);
-
- spin_unlock_irq(&imxdmac->lock);
+ spin_lock_irqsave(&imxdma->lock, flags);
+ list_move_tail(imxdmac->ld_free.next, &imxdmac->ld_queue);
+ cookie = dma_cookie_assign(tx);
+ spin_unlock_irqrestore(&imxdma->lock, flags);
return cookie;
}
@@ -197,23 +690,52 @@ static int imxdma_alloc_chan_resources(struct dma_chan *chan)
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
struct imx_dma_data *data = chan->private;
- imxdmac->dma_request = data->dma_request;
+ if (data != NULL)
+ imxdmac->dma_request = data->dma_request;
- dma_async_tx_descriptor_init(&imxdmac->desc, chan);
- imxdmac->desc.tx_submit = imxdma_tx_submit;
- /* txd.flags will be overwritten in prep funcs */
- imxdmac->desc.flags = DMA_CTRL_ACK;
+ while (imxdmac->descs_allocated < IMXDMA_MAX_CHAN_DESCRIPTORS) {
+ struct imxdma_desc *desc;
- imxdmac->status = DMA_SUCCESS;
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ break;
+ __memzero(&desc->desc, sizeof(struct dma_async_tx_descriptor));
+ dma_async_tx_descriptor_init(&desc->desc, chan);
+ desc->desc.tx_submit = imxdma_tx_submit;
+ /* txd.flags will be overwritten in prep funcs */
+ desc->desc.flags = DMA_CTRL_ACK;
+ desc->status = DMA_SUCCESS;
+
+ list_add_tail(&desc->node, &imxdmac->ld_free);
+ imxdmac->descs_allocated++;
+ }
- return 0;
+ if (!imxdmac->descs_allocated)
+ return -ENOMEM;
+
+ return imxdmac->descs_allocated;
}
static void imxdma_free_chan_resources(struct dma_chan *chan)
{
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ struct imxdma_desc *desc, *_desc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imxdma->lock, flags);
+
+ imxdma_disable_hw(imxdmac);
+ list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
+ list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
- imx_dma_disable(imxdmac->imxdma_channel);
+ spin_unlock_irqrestore(&imxdma->lock, flags);
+
+ list_for_each_entry_safe(desc, _desc, &imxdmac->ld_free, node) {
+ kfree(desc);
+ imxdmac->descs_allocated--;
+ }
+ INIT_LIST_HEAD(&imxdmac->ld_free);
if (imxdmac->sg_list) {
kfree(imxdmac->sg_list);
@@ -224,27 +746,23 @@ static void imxdma_free_chan_resources(struct dma_chan *chan)
static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
struct scatterlist *sg;
- int i, ret, dma_length = 0;
- unsigned int dmamode;
+ int i, dma_length = 0;
+ struct imxdma_desc *desc;
- if (imxdmac->status == DMA_IN_PROGRESS)
+ if (list_empty(&imxdmac->ld_free) ||
+ imxdma_chan_is_doing_cyclic(imxdmac))
return NULL;
- imxdmac->status = DMA_IN_PROGRESS;
+ desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
for_each_sg(sgl, sg, sg_len, i) {
dma_length += sg->length;
}
- if (direction == DMA_DEV_TO_MEM)
- dmamode = DMA_MODE_READ;
- else
- dmamode = DMA_MODE_WRITE;
-
switch (imxdmac->word_size) {
case DMA_SLAVE_BUSWIDTH_4_BYTES:
if (sgl->length & 3 || sgl->dma_address & 3)
@@ -260,37 +778,41 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
return NULL;
}
- ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
- dma_length, imxdmac->per_address, dmamode);
- if (ret)
- return NULL;
+ desc->type = IMXDMA_DESC_SLAVE_SG;
+ desc->sg = sgl;
+ desc->sgcount = sg_len;
+ desc->len = dma_length;
+ desc->direction = direction;
+ if (direction == DMA_DEV_TO_MEM) {
+ desc->src = imxdmac->per_address;
+ } else {
+ desc->dest = imxdmac->per_address;
+ }
+ desc->desc.callback = NULL;
+ desc->desc.callback_param = NULL;
- return &imxdmac->desc;
+ return &desc->desc;
}
static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
- size_t period_len, enum dma_transfer_direction direction)
+ size_t period_len, enum dma_transfer_direction direction,
+ void *context)
{
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
struct imxdma_engine *imxdma = imxdmac->imxdma;
- int i, ret;
+ struct imxdma_desc *desc;
+ int i;
unsigned int periods = buf_len / period_len;
- unsigned int dmamode;
dev_dbg(imxdma->dev, "%s channel: %d buf_len=%d period_len=%d\n",
__func__, imxdmac->channel, buf_len, period_len);
- if (imxdmac->status == DMA_IN_PROGRESS)
+ if (list_empty(&imxdmac->ld_free) ||
+ imxdma_chan_is_doing_cyclic(imxdmac))
return NULL;
- imxdmac->status = DMA_IN_PROGRESS;
- ret = imx_dma_setup_progression_handler(imxdmac->imxdma_channel,
- imxdma_progression);
- if (ret) {
- dev_err(imxdma->dev, "Failed to setup the DMA handler\n");
- return NULL;
- }
+ desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
if (imxdmac->sg_list)
kfree(imxdmac->sg_list);
@@ -316,62 +838,221 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
imxdmac->sg_list[periods].page_link =
((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
- if (direction == DMA_DEV_TO_MEM)
- dmamode = DMA_MODE_READ;
- else
- dmamode = DMA_MODE_WRITE;
+ desc->type = IMXDMA_DESC_CYCLIC;
+ desc->sg = imxdmac->sg_list;
+ desc->sgcount = periods;
+ desc->len = IMX_DMA_LENGTH_LOOP;
+ desc->direction = direction;
+ if (direction == DMA_DEV_TO_MEM) {
+ desc->src = imxdmac->per_address;
+ } else {
+ desc->dest = imxdmac->per_address;
+ }
+ desc->desc.callback = NULL;
+ desc->desc.callback_param = NULL;
+
+ return &desc->desc;
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
+ struct dma_chan *chan, dma_addr_t dest,
+ dma_addr_t src, size_t len, unsigned long flags)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ struct imxdma_desc *desc;
- ret = imx_dma_setup_sg(imxdmac->imxdma_channel, imxdmac->sg_list, periods,
- IMX_DMA_LENGTH_LOOP, imxdmac->per_address, dmamode);
- if (ret)
+ dev_dbg(imxdma->dev, "%s channel: %d src=0x%x dst=0x%x len=%d\n",
+ __func__, imxdmac->channel, src, dest, len);
+
+ if (list_empty(&imxdmac->ld_free) ||
+ imxdma_chan_is_doing_cyclic(imxdmac))
return NULL;
- return &imxdmac->desc;
+ desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
+
+ desc->type = IMXDMA_DESC_MEMCPY;
+ desc->src = src;
+ desc->dest = dest;
+ desc->len = len;
+ desc->direction = DMA_MEM_TO_MEM;
+ desc->config_port = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
+ desc->config_mem = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
+ desc->desc.callback = NULL;
+ desc->desc.callback_param = NULL;
+
+ return &desc->desc;
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
+ struct dma_chan *chan, struct dma_interleaved_template *xt,
+ unsigned long flags)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ struct imxdma_desc *desc;
+
+ dev_dbg(imxdma->dev, "%s channel: %d src_start=0x%x dst_start=0x%x\n"
+ " src_sgl=%s dst_sgl=%s numf=%d frame_size=%d\n", __func__,
+ imxdmac->channel, xt->src_start, xt->dst_start,
+ xt->src_sgl ? "true" : "false", xt->dst_sgl ? "true" : "false",
+ xt->numf, xt->frame_size);
+
+ if (list_empty(&imxdmac->ld_free) ||
+ imxdma_chan_is_doing_cyclic(imxdmac))
+ return NULL;
+
+ if (xt->frame_size != 1 || xt->numf <= 0 || xt->dir != DMA_MEM_TO_MEM)
+ return NULL;
+
+ desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
+
+ desc->type = IMXDMA_DESC_INTERLEAVED;
+ desc->src = xt->src_start;
+ desc->dest = xt->dst_start;
+ desc->x = xt->sgl[0].size;
+ desc->y = xt->numf;
+ desc->w = xt->sgl[0].icg + desc->x;
+ desc->len = desc->x * desc->y;
+ desc->direction = DMA_MEM_TO_MEM;
+ desc->config_port = IMX_DMA_MEMSIZE_32;
+ desc->config_mem = IMX_DMA_MEMSIZE_32;
+ if (xt->src_sgl)
+ desc->config_mem |= IMX_DMA_TYPE_2D;
+ if (xt->dst_sgl)
+ desc->config_port |= IMX_DMA_TYPE_2D;
+ desc->desc.callback = NULL;
+ desc->desc.callback_param = NULL;
+
+ return &desc->desc;
}
static void imxdma_issue_pending(struct dma_chan *chan)
{
- /*
- * Nothing to do. We only have a single descriptor
- */
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ struct imxdma_desc *desc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imxdma->lock, flags);
+ if (list_empty(&imxdmac->ld_active) &&
+ !list_empty(&imxdmac->ld_queue)) {
+ desc = list_first_entry(&imxdmac->ld_queue,
+ struct imxdma_desc, node);
+
+ if (imxdma_xfer_desc(desc) < 0) {
+ dev_warn(imxdma->dev,
+ "%s: channel: %d couldn't issue DMA xfer\n",
+ __func__, imxdmac->channel);
+ } else {
+ list_move_tail(imxdmac->ld_queue.next,
+ &imxdmac->ld_active);
+ }
+ }
+ spin_unlock_irqrestore(&imxdma->lock, flags);
}
static int __init imxdma_probe(struct platform_device *pdev)
-{
+ {
struct imxdma_engine *imxdma;
int ret, i;
+
imxdma = kzalloc(sizeof(*imxdma), GFP_KERNEL);
if (!imxdma)
return -ENOMEM;
+ if (cpu_is_mx1()) {
+ imxdma->base = MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR);
+ } else if (cpu_is_mx21()) {
+ imxdma->base = MX21_IO_ADDRESS(MX21_DMA_BASE_ADDR);
+ } else if (cpu_is_mx27()) {
+ imxdma->base = MX27_IO_ADDRESS(MX27_DMA_BASE_ADDR);
+ } else {
+ kfree(imxdma);
+ return 0;
+ }
+
+ imxdma->dma_clk = clk_get(NULL, "dma");
+ if (IS_ERR(imxdma->dma_clk))
+ return PTR_ERR(imxdma->dma_clk);
+ clk_enable(imxdma->dma_clk);
+
+ /* reset DMA module */
+ imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR);
+
+ if (cpu_is_mx1()) {
+ ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma);
+ if (ret) {
+ dev_warn(imxdma->dev, "Can't register IRQ for DMA\n");
+ kfree(imxdma);
+ return ret;
+ }
+
+ ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma);
+ if (ret) {
+ dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n");
+ free_irq(MX1_DMA_INT, NULL);
+ kfree(imxdma);
+ return ret;
+ }
+ }
+
+ /* enable DMA module */
+ imx_dmav1_writel(imxdma, DCR_DEN, DMA_DCR);
+
+ /* clear all interrupts */
+ imx_dmav1_writel(imxdma, (1 << IMX_DMA_CHANNELS) - 1, DMA_DISR);
+
+ /* disable interrupts */
+ imx_dmav1_writel(imxdma, (1 << IMX_DMA_CHANNELS) - 1, DMA_DIMR);
+
INIT_LIST_HEAD(&imxdma->dma_device.channels);
dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
+ dma_cap_set(DMA_MEMCPY, imxdma->dma_device.cap_mask);
+ dma_cap_set(DMA_INTERLEAVE, imxdma->dma_device.cap_mask);
+
+ /* Initialize 2D global parameters */
+ for (i = 0; i < IMX_DMA_2D_SLOTS; i++)
+ imxdma->slots_2d[i].count = 0;
+
+ spin_lock_init(&imxdma->lock);
/* Initialize channel parameters */
- for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+ for (i = 0; i < IMX_DMA_CHANNELS; i++) {
struct imxdma_channel *imxdmac = &imxdma->channel[i];
- imxdmac->imxdma_channel = imx_dma_request_by_prio("dmaengine",
- DMA_PRIO_MEDIUM);
- if ((int)imxdmac->channel < 0) {
- ret = -ENODEV;
- goto err_init;
+ if (cpu_is_mx21() || cpu_is_mx27()) {
+ ret = request_irq(MX2x_INT_DMACH0 + i,
+ dma_irq_handler, 0, "DMA", imxdma);
+ if (ret) {
+ dev_warn(imxdma->dev, "Can't register IRQ %d "
+ "for DMA channel %d\n",
+ MX2x_INT_DMACH0 + i, i);
+ goto err_init;
+ }
+ init_timer(&imxdmac->watchdog);
+ imxdmac->watchdog.function = &imxdma_watchdog;
+ imxdmac->watchdog.data = (unsigned long)imxdmac;
}
- imx_dma_setup_handlers(imxdmac->imxdma_channel,
- imxdma_irq_handler, imxdma_err_handler, imxdmac);
-
imxdmac->imxdma = imxdma;
- spin_lock_init(&imxdmac->lock);
+ INIT_LIST_HEAD(&imxdmac->ld_queue);
+ INIT_LIST_HEAD(&imxdmac->ld_free);
+ INIT_LIST_HEAD(&imxdmac->ld_active);
+
+ tasklet_init(&imxdmac->dma_tasklet, imxdma_tasklet,
+ (unsigned long)imxdmac);
imxdmac->chan.device = &imxdma->dma_device;
+ dma_cookie_init(&imxdmac->chan);
imxdmac->channel = i;
/* Add the channel to the DMAC list */
- list_add_tail(&imxdmac->chan.device_node, &imxdma->dma_device.channels);
+ list_add_tail(&imxdmac->chan.device_node,
+ &imxdma->dma_device.channels);
}
imxdma->dev = &pdev->dev;
@@ -382,11 +1063,14 @@ static int __init imxdma_probe(struct platform_device *pdev)
imxdma->dma_device.device_tx_status = imxdma_tx_status;
imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
+ imxdma->dma_device.device_prep_dma_memcpy = imxdma_prep_dma_memcpy;
+ imxdma->dma_device.device_prep_interleaved_dma = imxdma_prep_dma_interleaved;
imxdma->dma_device.device_control = imxdma_control;
imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
platform_set_drvdata(pdev, imxdma);
+ imxdma->dma_device.copy_align = 2; /* 2^2 = 4 bytes alignment */
imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms;
dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff);
@@ -399,9 +1083,13 @@ static int __init imxdma_probe(struct platform_device *pdev)
return 0;
err_init:
- while (--i >= 0) {
- struct imxdma_channel *imxdmac = &imxdma->channel[i];
- imx_dma_free(imxdmac->imxdma_channel);
+
+ if (cpu_is_mx21() || cpu_is_mx27()) {
+ while (--i >= 0)
+ free_irq(MX2x_INT_DMACH0 + i, NULL);
+ } else if cpu_is_mx1() {
+ free_irq(MX1_DMA_INT, NULL);
+ free_irq(MX1_DMA_ERR, NULL);
}
kfree(imxdma);
@@ -415,10 +1103,12 @@ static int __exit imxdma_remove(struct platform_device *pdev)
dma_async_device_unregister(&imxdma->dma_device);
- for (i = 0; i < MAX_DMA_CHANNELS; i++) {
- struct imxdma_channel *imxdmac = &imxdma->channel[i];
-
- imx_dma_free(imxdmac->imxdma_channel);
+ if (cpu_is_mx21() || cpu_is_mx27()) {
+ for (i = 0; i < IMX_DMA_CHANNELS; i++)
+ free_irq(MX2x_INT_DMACH0 + i, NULL);
+ } else if cpu_is_mx1() {
+ free_irq(MX1_DMA_INT, NULL);
+ free_irq(MX1_DMA_ERR, NULL);
}
kfree(imxdma);
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 63540d3e2153..d3e38e28bb6b 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/bitops.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
@@ -41,6 +42,8 @@
#include <mach/dma.h>
#include <mach/hardware.h>
+#include "dmaengine.h"
+
/* SDMA registers */
#define SDMA_H_C0PTR 0x000
#define SDMA_H_INTR 0x004
@@ -259,19 +262,18 @@ struct sdma_channel {
unsigned int pc_from_device, pc_to_device;
unsigned long flags;
dma_addr_t per_address;
- u32 event_mask0, event_mask1;
- u32 watermark_level;
+ unsigned long event_mask[2];
+ unsigned long watermark_level;
u32 shp_addr, per_addr;
struct dma_chan chan;
spinlock_t lock;
struct dma_async_tx_descriptor desc;
- dma_cookie_t last_completed;
enum dma_status status;
unsigned int chn_count;
unsigned int chn_real_count;
};
-#define IMX_DMA_SG_LOOP (1 << 0)
+#define IMX_DMA_SG_LOOP BIT(0)
#define MAX_DMA_CHANNELS 32
#define MXC_SDMA_DEFAULT_PRIORITY 1
@@ -345,9 +347,9 @@ static const struct of_device_id sdma_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, sdma_dt_ids);
-#define SDMA_H_CONFIG_DSPDMA (1 << 12) /* indicates if the DSPDMA is used */
-#define SDMA_H_CONFIG_RTD_PINS (1 << 11) /* indicates if Real-Time Debug pins are enabled */
-#define SDMA_H_CONFIG_ACR (1 << 4) /* indicates if AHB freq /core freq = 2 or 1 */
+#define SDMA_H_CONFIG_DSPDMA BIT(12) /* indicates if the DSPDMA is used */
+#define SDMA_H_CONFIG_RTD_PINS BIT(11) /* indicates if Real-Time Debug pins are enabled */
+#define SDMA_H_CONFIG_ACR BIT(4) /* indicates if AHB freq /core freq = 2 or 1 */
#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/
static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
@@ -362,37 +364,42 @@ static int sdma_config_ownership(struct sdma_channel *sdmac,
{
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
- u32 evt, mcu, dsp;
+ unsigned long evt, mcu, dsp;
if (event_override && mcu_override && dsp_override)
return -EINVAL;
- evt = __raw_readl(sdma->regs + SDMA_H_EVTOVR);
- mcu = __raw_readl(sdma->regs + SDMA_H_HOSTOVR);
- dsp = __raw_readl(sdma->regs + SDMA_H_DSPOVR);
+ evt = readl_relaxed(sdma->regs + SDMA_H_EVTOVR);
+ mcu = readl_relaxed(sdma->regs + SDMA_H_HOSTOVR);
+ dsp = readl_relaxed(sdma->regs + SDMA_H_DSPOVR);
if (dsp_override)
- dsp &= ~(1 << channel);
+ __clear_bit(channel, &dsp);
else
- dsp |= (1 << channel);
+ __set_bit(channel, &dsp);
if (event_override)
- evt &= ~(1 << channel);
+ __clear_bit(channel, &evt);
else
- evt |= (1 << channel);
+ __set_bit(channel, &evt);
if (mcu_override)
- mcu &= ~(1 << channel);
+ __clear_bit(channel, &mcu);
else
- mcu |= (1 << channel);
+ __set_bit(channel, &mcu);
- __raw_writel(evt, sdma->regs + SDMA_H_EVTOVR);
- __raw_writel(mcu, sdma->regs + SDMA_H_HOSTOVR);
- __raw_writel(dsp, sdma->regs + SDMA_H_DSPOVR);
+ writel_relaxed(evt, sdma->regs + SDMA_H_EVTOVR);
+ writel_relaxed(mcu, sdma->regs + SDMA_H_HOSTOVR);
+ writel_relaxed(dsp, sdma->regs + SDMA_H_DSPOVR);
return 0;
}
+static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
+{
+ writel(BIT(channel), sdma->regs + SDMA_H_START);
+}
+
/*
* sdma_run_channel - run a channel and wait till it's done
*/
@@ -404,7 +411,7 @@ static int sdma_run_channel(struct sdma_channel *sdmac)
init_completion(&sdmac->done);
- __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
+ sdma_enable_channel(sdma, channel);
ret = wait_for_completion_timeout(&sdmac->done, HZ);
@@ -451,12 +458,12 @@ static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
{
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
- u32 val;
+ unsigned long val;
u32 chnenbl = chnenbl_ofs(sdma, event);
- val = __raw_readl(sdma->regs + chnenbl);
- val |= (1 << channel);
- __raw_writel(val, sdma->regs + chnenbl);
+ val = readl_relaxed(sdma->regs + chnenbl);
+ __set_bit(channel, &val);
+ writel_relaxed(val, sdma->regs + chnenbl);
}
static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
@@ -464,11 +471,11 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
u32 chnenbl = chnenbl_ofs(sdma, event);
- u32 val;
+ unsigned long val;
- val = __raw_readl(sdma->regs + chnenbl);
- val &= ~(1 << channel);
- __raw_writel(val, sdma->regs + chnenbl);
+ val = readl_relaxed(sdma->regs + chnenbl);
+ __clear_bit(channel, &val);
+ writel_relaxed(val, sdma->regs + chnenbl);
}
static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
@@ -522,7 +529,7 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
else
sdmac->status = DMA_SUCCESS;
- sdmac->last_completed = sdmac->desc.cookie;
+ dma_cookie_complete(&sdmac->desc);
if (sdmac->desc.callback)
sdmac->desc.callback(sdmac->desc.callback_param);
}
@@ -544,10 +551,10 @@ static void mxc_sdma_handle_channel(struct sdma_channel *sdmac)
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
{
struct sdma_engine *sdma = dev_id;
- u32 stat;
+ unsigned long stat;
- stat = __raw_readl(sdma->regs + SDMA_H_INTR);
- __raw_writel(stat, sdma->regs + SDMA_H_INTR);
+ stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
+ writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
while (stat) {
int channel = fls(stat) - 1;
@@ -555,7 +562,7 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
mxc_sdma_handle_channel(sdmac);
- stat &= ~(1 << channel);
+ __clear_bit(channel, &stat);
}
return IRQ_HANDLED;
@@ -663,11 +670,11 @@ static int sdma_load_context(struct sdma_channel *sdmac)
return load_address;
dev_dbg(sdma->dev, "load_address = %d\n", load_address);
- dev_dbg(sdma->dev, "wml = 0x%08x\n", sdmac->watermark_level);
+ dev_dbg(sdma->dev, "wml = 0x%08x\n", (u32)sdmac->watermark_level);
dev_dbg(sdma->dev, "shp_addr = 0x%08x\n", sdmac->shp_addr);
dev_dbg(sdma->dev, "per_addr = 0x%08x\n", sdmac->per_addr);
- dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0);
- dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1);
+ dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", (u32)sdmac->event_mask[0]);
+ dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", (u32)sdmac->event_mask[1]);
mutex_lock(&sdma->channel_0_lock);
@@ -677,8 +684,8 @@ static int sdma_load_context(struct sdma_channel *sdmac)
/* Send by context the event mask,base address for peripheral
* and watermark level
*/
- context->gReg[0] = sdmac->event_mask1;
- context->gReg[1] = sdmac->event_mask0;
+ context->gReg[0] = sdmac->event_mask[1];
+ context->gReg[1] = sdmac->event_mask[0];
context->gReg[2] = sdmac->per_addr;
context->gReg[6] = sdmac->shp_addr;
context->gReg[7] = sdmac->watermark_level;
@@ -701,7 +708,7 @@ static void sdma_disable_channel(struct sdma_channel *sdmac)
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
- __raw_writel(1 << channel, sdma->regs + SDMA_H_STATSTOP);
+ writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
sdmac->status = DMA_ERROR;
}
@@ -711,13 +718,13 @@ static int sdma_config_channel(struct sdma_channel *sdmac)
sdma_disable_channel(sdmac);
- sdmac->event_mask0 = 0;
- sdmac->event_mask1 = 0;
+ sdmac->event_mask[0] = 0;
+ sdmac->event_mask[1] = 0;
sdmac->shp_addr = 0;
sdmac->per_addr = 0;
if (sdmac->event_id0) {
- if (sdmac->event_id0 > 32)
+ if (sdmac->event_id0 >= sdmac->sdma->num_events)
return -EINVAL;
sdma_event_enable(sdmac, sdmac->event_id0);
}
@@ -740,15 +747,14 @@ static int sdma_config_channel(struct sdma_channel *sdmac)
(sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
/* Handle multiple event channels differently */
if (sdmac->event_id1) {
- sdmac->event_mask1 = 1 << (sdmac->event_id1 % 32);
+ sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32);
if (sdmac->event_id1 > 31)
- sdmac->watermark_level |= 1 << 31;
- sdmac->event_mask0 = 1 << (sdmac->event_id0 % 32);
+ __set_bit(31, &sdmac->watermark_level);
+ sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32);
if (sdmac->event_id0 > 31)
- sdmac->watermark_level |= 1 << 30;
+ __set_bit(30, &sdmac->watermark_level);
} else {
- sdmac->event_mask0 = 1 << sdmac->event_id0;
- sdmac->event_mask1 = 1 << (sdmac->event_id0 - 32);
+ __set_bit(sdmac->event_id0, sdmac->event_mask);
}
/* Watermark Level */
sdmac->watermark_level |= sdmac->watermark_level;
@@ -774,7 +780,7 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
return -EINVAL;
}
- __raw_writel(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
+ writel_relaxed(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
return 0;
}
@@ -796,8 +802,6 @@ static int sdma_request_channel(struct sdma_channel *sdmac)
sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
- clk_enable(sdma->clk);
-
sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
init_completion(&sdmac->done);
@@ -810,24 +814,6 @@ out:
return ret;
}
-static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
-{
- __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
-}
-
-static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdmac)
-{
- dma_cookie_t cookie = sdmac->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- sdmac->chan.cookie = cookie;
- sdmac->desc.cookie = cookie;
-
- return cookie;
-}
-
static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
{
return container_of(chan, struct sdma_channel, chan);
@@ -837,14 +823,11 @@ static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
{
unsigned long flags;
struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
- struct sdma_engine *sdma = sdmac->sdma;
dma_cookie_t cookie;
spin_lock_irqsave(&sdmac->lock, flags);
- cookie = sdma_assign_cookie(sdmac);
-
- sdma_enable_channel(sdma, sdmac->channel);
+ cookie = dma_cookie_assign(tx);
spin_unlock_irqrestore(&sdmac->lock, flags);
@@ -875,11 +858,14 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
sdmac->peripheral_type = data->peripheral_type;
sdmac->event_id0 = data->dma_request;
- ret = sdma_set_channel_priority(sdmac, prio);
+
+ clk_enable(sdmac->sdma->clk);
+
+ ret = sdma_request_channel(sdmac);
if (ret)
return ret;
- ret = sdma_request_channel(sdmac);
+ ret = sdma_set_channel_priority(sdmac, prio);
if (ret)
return ret;
@@ -916,7 +902,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
@@ -1014,7 +1000,8 @@ err_out:
static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
- size_t period_len, enum dma_transfer_direction direction)
+ size_t period_len, enum dma_transfer_direction direction,
+ void *context)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
@@ -1128,7 +1115,7 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
last_used = chan->cookie;
- dma_set_tx_state(txstate, sdmac->last_completed, last_used,
+ dma_set_tx_state(txstate, chan->completed_cookie, last_used,
sdmac->chn_count - sdmac->chn_real_count);
return sdmac->status;
@@ -1136,9 +1123,11 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
static void sdma_issue_pending(struct dma_chan *chan)
{
- /*
- * Nothing to do. We only have a single descriptor
- */
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_engine *sdma = sdmac->sdma;
+
+ if (sdmac->status == DMA_IN_PROGRESS)
+ sdma_enable_channel(sdma, sdmac->channel);
}
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
@@ -1230,7 +1219,7 @@ static int __init sdma_init(struct sdma_engine *sdma)
clk_enable(sdma->clk);
/* Be sure SDMA has not started yet */
- __raw_writel(0, sdma->regs + SDMA_H_C0PTR);
+ writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
sdma->channel_control = dma_alloc_coherent(NULL,
MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
@@ -1253,11 +1242,11 @@ static int __init sdma_init(struct sdma_engine *sdma)
/* disable all channels */
for (i = 0; i < sdma->num_events; i++)
- __raw_writel(0, sdma->regs + chnenbl_ofs(sdma, i));
+ writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
/* All channels have priority 0 */
for (i = 0; i < MAX_DMA_CHANNELS; i++)
- __raw_writel(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
+ writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
ret = sdma_request_channel(&sdma->channel[0]);
if (ret)
@@ -1266,16 +1255,16 @@ static int __init sdma_init(struct sdma_engine *sdma)
sdma_config_ownership(&sdma->channel[0], false, true, false);
/* Set Command Channel (Channel Zero) */
- __raw_writel(0x4050, sdma->regs + SDMA_CHN0ADDR);
+ writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR);
/* Set bits of CONFIG register but with static context switching */
/* FIXME: Check whether to set ACR bit depending on clock ratios */
- __raw_writel(0, sdma->regs + SDMA_H_CONFIG);
+ writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
- __raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR);
+ writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
/* Set bits of CONFIG register with given context switching mode */
- __raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+ writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
/* Initializes channel's priorities */
sdma_set_channel_priority(&sdma->channel[0], 7);
@@ -1367,6 +1356,7 @@ static int __init sdma_probe(struct platform_device *pdev)
spin_lock_init(&sdmac->lock);
sdmac->chan.device = &sdma->dma_device;
+ dma_cookie_init(&sdmac->chan);
sdmac->channel = i;
/*
@@ -1387,7 +1377,9 @@ static int __init sdma_probe(struct platform_device *pdev)
sdma_add_scripts(sdma, pdata->script_addrs);
if (pdata) {
- sdma_get_firmware(sdma, pdata->fw_name);
+ ret = sdma_get_firmware(sdma, pdata->fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
} else {
/*
* Because that device tree does not encode ROM script address,
@@ -1396,15 +1388,12 @@ static int __init sdma_probe(struct platform_device *pdev)
*/
ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
&fw_name);
- if (ret) {
- dev_err(&pdev->dev, "failed to get firmware name\n");
- goto err_init;
- }
-
- ret = sdma_get_firmware(sdma, fw_name);
- if (ret) {
- dev_err(&pdev->dev, "failed to get firmware\n");
- goto err_init;
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware name\n");
+ else {
+ ret = sdma_get_firmware(sdma, fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
}
}
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index 74f70aadf9e4..c900ca7aaec4 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -29,6 +29,8 @@
#include <linux/intel_mid_dma.h>
#include <linux/module.h>
+#include "dmaengine.h"
+
#define MAX_CHAN 4 /*max ch across controllers*/
#include "intel_mid_dma_regs.h"
@@ -288,7 +290,7 @@ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
struct intel_mid_dma_lli *llitem;
void *param_txd = NULL;
- midc->completed = txd->cookie;
+ dma_cookie_complete(txd);
callback_txd = txd->callback;
param_txd = txd->callback_param;
@@ -434,14 +436,7 @@ static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
dma_cookie_t cookie;
spin_lock_bh(&midc->lock);
- cookie = midc->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- midc->chan.cookie = cookie;
- desc->txd.cookie = cookie;
-
+ cookie = dma_cookie_assign(tx);
if (list_empty(&midc->active_list))
list_add_tail(&desc->desc_node, &midc->active_list);
@@ -482,31 +477,18 @@ static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- int ret;
+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+ enum dma_status ret;
- last_complete = midc->completed;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
if (ret != DMA_SUCCESS) {
spin_lock_bh(&midc->lock);
midc_scan_descriptors(to_middma_device(chan->device), midc);
spin_unlock_bh(&midc->lock);
- last_complete = midc->completed;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
}
- if (txstate) {
- txstate->last = last_complete;
- txstate->used = last_used;
- txstate->residue = 0;
- }
return ret;
}
@@ -732,13 +714,14 @@ err_desc_get:
* @sg_len: length of sg txn
* @direction: DMA transfer dirtn
* @flags: DMA flags
+ * @context: transfer context (ignored)
*
* Prepares LLI based periphral transfer
*/
static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct intel_mid_dma_chan *midc = NULL;
struct intel_mid_dma_slave *mids = NULL;
@@ -832,7 +815,6 @@ static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
/*trying to free ch in use!!!!!*/
pr_err("ERR_MDMA: trying to free ch in use\n");
}
- pm_runtime_put(&mid->pdev->dev);
spin_lock_bh(&midc->lock);
midc->descs_allocated = 0;
list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
@@ -853,6 +835,7 @@ static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
/* Disable CH interrupts */
iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
+ pm_runtime_put(&mid->pdev->dev);
}
/**
@@ -886,7 +869,7 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
pm_runtime_put(&mid->pdev->dev);
return -EIO;
}
- midc->completed = chan->cookie = 1;
+ dma_cookie_init(chan);
spin_lock_bh(&midc->lock);
while (midc->descs_allocated < DESCS_PER_CHANNEL) {
@@ -1056,7 +1039,8 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
}
err_status &= mid->intr_mask;
if (err_status) {
- iowrite32(MASK_INTR_REG(err_status), mid->dma_base + MASK_ERR);
+ iowrite32((err_status << INT_MASK_WE),
+ mid->dma_base + MASK_ERR);
call_tasklet = 1;
}
if (call_tasklet)
@@ -1118,7 +1102,7 @@ static int mid_setup_dma(struct pci_dev *pdev)
struct intel_mid_dma_chan *midch = &dma->ch[i];
midch->chan.device = &dma->common;
- midch->chan.cookie = 1;
+ dma_cookie_init(&midch->chan);
midch->ch_id = dma->chan_base + i;
pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id);
diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
index c83d35b97bd8..1bfa9268feaf 100644
--- a/drivers/dma/intel_mid_dma_regs.h
+++ b/drivers/dma/intel_mid_dma_regs.h
@@ -165,7 +165,6 @@ union intel_mid_dma_cfg_hi {
* @dma_base: MMIO register space DMA engine base pointer
* @ch_id: DMA channel id
* @lock: channel spinlock
- * @completed: DMA cookie
* @active_list: current active descriptors
* @queue: current queued up descriptors
* @free_list: current free descriptors
@@ -183,7 +182,6 @@ struct intel_mid_dma_chan {
void __iomem *dma_base;
int ch_id;
spinlock_t lock;
- dma_cookie_t completed;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index a4d6cb0c0343..31493d80e0e9 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -40,6 +40,8 @@
#include "registers.h"
#include "hw.h"
+#include "../dmaengine.h"
+
int ioat_pending_level = 4;
module_param(ioat_pending_level, int, 0644);
MODULE_PARM_DESC(ioat_pending_level,
@@ -107,6 +109,7 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c
chan->reg_base = device->reg_base + (0x80 * (idx + 1));
spin_lock_init(&chan->cleanup_lock);
chan->common.device = dma;
+ dma_cookie_init(&chan->common);
list_add_tail(&chan->common.device_node, &dma->channels);
device->idx[idx] = chan;
init_timer(&chan->timer);
@@ -235,12 +238,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
spin_lock_bh(&ioat->desc_lock);
/* cookie incr and addition to used_list must be atomic */
- cookie = c->cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
- c->cookie = cookie;
- tx->cookie = cookie;
+ cookie = dma_cookie_assign(tx);
dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie);
/* write address into NextDescriptor field of last desc in chain */
@@ -603,8 +601,7 @@ static void __cleanup(struct ioat_dma_chan *ioat, unsigned long phys_complete)
*/
dump_desc_dbg(ioat, desc);
if (tx->cookie) {
- chan->completed_cookie = tx->cookie;
- tx->cookie = 0;
+ dma_cookie_complete(tx);
ioat_dma_unmap(chan, tx->flags, desc->len, desc->hw);
ioat->active -= desc->hw->tx_cnt;
if (tx->callback) {
@@ -733,13 +730,15 @@ ioat_dma_tx_status(struct dma_chan *c, dma_cookie_t cookie,
{
struct ioat_chan_common *chan = to_chan_common(c);
struct ioatdma_device *device = chan->device;
+ enum dma_status ret;
- if (ioat_tx_status(c, cookie, txstate) == DMA_SUCCESS)
- return DMA_SUCCESS;
+ ret = dma_cookie_status(c, cookie, txstate);
+ if (ret == DMA_SUCCESS)
+ return ret;
device->cleanup_fn((unsigned long) c);
- return ioat_tx_status(c, cookie, txstate);
+ return dma_cookie_status(c, cookie, txstate);
}
static void ioat1_dma_start_null_desc(struct ioat_dma_chan *ioat)
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index 5216c8a92a21..c7888bccd974 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -90,7 +90,6 @@ struct ioat_chan_common {
void __iomem *reg_base;
unsigned long last_completion;
spinlock_t cleanup_lock;
- dma_cookie_t completed_cookie;
unsigned long state;
#define IOAT_COMPLETION_PENDING 0
#define IOAT_COMPLETION_ACK 1
@@ -143,28 +142,6 @@ static inline struct ioat_dma_chan *to_ioat_chan(struct dma_chan *c)
return container_of(chan, struct ioat_dma_chan, base);
}
-/**
- * ioat_tx_status - poll the status of an ioat transaction
- * @c: channel handle
- * @cookie: transaction identifier
- * @txstate: if set, updated with the transaction state
- */
-static inline enum dma_status
-ioat_tx_status(struct dma_chan *c, dma_cookie_t cookie,
- struct dma_tx_state *txstate)
-{
- struct ioat_chan_common *chan = to_chan_common(c);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
-
- last_used = c->cookie;
- last_complete = chan->completed_cookie;
-
- dma_set_tx_state(txstate, last_complete, last_used, 0);
-
- return dma_async_is_complete(cookie, last_complete, last_used);
-}
-
/* wrapper around hardware descriptor format + additional software fields */
/**
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 5d65f8377971..e8e110ff3d96 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -41,6 +41,8 @@
#include "registers.h"
#include "hw.h"
+#include "../dmaengine.h"
+
int ioat_ring_alloc_order = 8;
module_param(ioat_ring_alloc_order, int, 0644);
MODULE_PARM_DESC(ioat_ring_alloc_order,
@@ -147,8 +149,7 @@ static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete)
dump_desc_dbg(ioat, desc);
if (tx->cookie) {
ioat_dma_unmap(chan, tx->flags, desc->len, desc->hw);
- chan->completed_cookie = tx->cookie;
- tx->cookie = 0;
+ dma_cookie_complete(tx);
if (tx->callback) {
tx->callback(tx->callback_param);
tx->callback = NULL;
@@ -398,13 +399,9 @@ static dma_cookie_t ioat2_tx_submit_unlock(struct dma_async_tx_descriptor *tx)
struct dma_chan *c = tx->chan;
struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
struct ioat_chan_common *chan = &ioat->base;
- dma_cookie_t cookie = c->cookie;
+ dma_cookie_t cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
- tx->cookie = cookie;
- c->cookie = cookie;
+ cookie = dma_cookie_assign(tx);
dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie);
if (!test_and_set_bit(IOAT_COMPLETION_PENDING, &chan->state))
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index f519c93a61e7..2c4476c0e405 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -61,6 +61,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/prefetch.h>
+#include "../dmaengine.h"
#include "registers.h"
#include "hw.h"
#include "dma.h"
@@ -277,9 +278,8 @@ static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete)
dump_desc_dbg(ioat, desc);
tx = &desc->txd;
if (tx->cookie) {
- chan->completed_cookie = tx->cookie;
+ dma_cookie_complete(tx);
ioat3_dma_unmap(ioat, desc, idx + i);
- tx->cookie = 0;
if (tx->callback) {
tx->callback(tx->callback_param);
tx->callback = NULL;
@@ -411,13 +411,15 @@ ioat3_tx_status(struct dma_chan *c, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
+ enum dma_status ret;
- if (ioat_tx_status(c, cookie, txstate) == DMA_SUCCESS)
- return DMA_SUCCESS;
+ ret = dma_cookie_status(c, cookie, txstate);
+ if (ret == DMA_SUCCESS)
+ return ret;
ioat3_cleanup(ioat);
- return ioat_tx_status(c, cookie, txstate);
+ return dma_cookie_status(c, cookie, txstate);
}
static struct dma_async_tx_descriptor *
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index faf88b7e1e71..da6c4c2c066a 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -36,6 +36,8 @@
#include <mach/adma.h>
+#include "dmaengine.h"
+
#define to_iop_adma_chan(chan) container_of(chan, struct iop_adma_chan, common)
#define to_iop_adma_device(dev) \
container_of(dev, struct iop_adma_device, common)
@@ -317,7 +319,7 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
}
if (cookie > 0) {
- iop_chan->completed_cookie = cookie;
+ iop_chan->common.completed_cookie = cookie;
pr_debug("\tcompleted cookie %d\n", cookie);
}
}
@@ -438,18 +440,6 @@ retry:
return NULL;
}
-static dma_cookie_t
-iop_desc_assign_cookie(struct iop_adma_chan *iop_chan,
- struct iop_adma_desc_slot *desc)
-{
- dma_cookie_t cookie = iop_chan->common.cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
- iop_chan->common.cookie = desc->async_tx.cookie = cookie;
- return cookie;
-}
-
static void iop_adma_check_threshold(struct iop_adma_chan *iop_chan)
{
dev_dbg(iop_chan->device->common.dev, "pending: %d\n",
@@ -477,7 +467,7 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx)
slots_per_op = grp_start->slots_per_op;
spin_lock_bh(&iop_chan->lock);
- cookie = iop_desc_assign_cookie(iop_chan, sw_desc);
+ cookie = dma_cookie_assign(tx);
old_chain_tail = list_entry(iop_chan->chain.prev,
struct iop_adma_desc_slot, chain_node);
@@ -904,24 +894,15 @@ static enum dma_status iop_adma_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- enum dma_status ret;
-
- last_used = chan->cookie;
- last_complete = iop_chan->completed_cookie;
- dma_set_tx_state(txstate, last_complete, last_used, 0);
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ int ret;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_SUCCESS)
return ret;
iop_adma_slot_cleanup(iop_chan);
- last_used = chan->cookie;
- last_complete = iop_chan->completed_cookie;
- dma_set_tx_state(txstate, last_complete, last_used, 0);
-
- return dma_async_is_complete(cookie, last_complete, last_used);
+ return dma_cookie_status(chan, cookie, txstate);
}
static irqreturn_t iop_adma_eot_handler(int irq, void *data)
@@ -1565,6 +1546,7 @@ static int __devinit iop_adma_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&iop_chan->chain);
INIT_LIST_HEAD(&iop_chan->all_slots);
iop_chan->common.device = dma_dev;
+ dma_cookie_init(&iop_chan->common);
list_add_tail(&iop_chan->common.device_node, &dma_dev->channels);
if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
@@ -1642,16 +1624,12 @@ static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan)
iop_desc_set_dest_addr(grp_start, iop_chan, 0);
iop_desc_set_memcpy_src_addr(grp_start, 0);
- cookie = iop_chan->common.cookie;
- cookie++;
- if (cookie <= 1)
- cookie = 2;
+ cookie = dma_cookie_assign(&sw_desc->async_tx);
/* initialize the completed cookie to be less than
* the most recently used cookie
*/
- iop_chan->completed_cookie = cookie - 1;
- iop_chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+ iop_chan->common.completed_cookie = cookie - 1;
/* channel should not be busy */
BUG_ON(iop_chan_is_busy(iop_chan));
@@ -1699,16 +1677,12 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan)
iop_desc_set_xor_src_addr(grp_start, 0, 0);
iop_desc_set_xor_src_addr(grp_start, 1, 0);
- cookie = iop_chan->common.cookie;
- cookie++;
- if (cookie <= 1)
- cookie = 2;
+ cookie = dma_cookie_assign(&sw_desc->async_tx);
/* initialize the completed cookie to be less than
* the most recently used cookie
*/
- iop_chan->completed_cookie = cookie - 1;
- iop_chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+ iop_chan->common.completed_cookie = cookie - 1;
/* channel should not be busy */
BUG_ON(iop_chan_is_busy(iop_chan));
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index 6212b16e8cf2..62e3f8ec2461 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -25,6 +25,7 @@
#include <mach/ipu.h>
+#include "../dmaengine.h"
#include "ipu_intern.h"
#define FS_VF_IN_VALID 0x00000002
@@ -866,14 +867,7 @@ static dma_cookie_t idmac_tx_submit(struct dma_async_tx_descriptor *tx)
dev_dbg(dev, "Submitting sg %p\n", &desc->sg[0]);
- cookie = ichan->dma_chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- /* from dmaengine.h: "last cookie value returned to client" */
- ichan->dma_chan.cookie = cookie;
- tx->cookie = cookie;
+ cookie = dma_cookie_assign(tx);
/* ipu->lock can be taken under ichan->lock, but not v.v. */
spin_lock_irqsave(&ichan->lock, flags);
@@ -1295,7 +1289,7 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
/* Flip the active buffer - even if update above failed */
ichan->active_buffer = !ichan->active_buffer;
if (done)
- ichan->completed = desc->txd.cookie;
+ dma_cookie_complete(&desc->txd);
callback = desc->txd.callback;
callback_param = desc->txd.callback_param;
@@ -1341,7 +1335,8 @@ static void ipu_gc_tasklet(unsigned long arg)
/* Allocate and initialise a transfer descriptor. */
static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan,
struct scatterlist *sgl, unsigned int sg_len,
- enum dma_transfer_direction direction, unsigned long tx_flags)
+ enum dma_transfer_direction direction, unsigned long tx_flags,
+ void *context)
{
struct idmac_channel *ichan = to_idmac_chan(chan);
struct idmac_tx_desc *desc = NULL;
@@ -1510,8 +1505,7 @@ static int idmac_alloc_chan_resources(struct dma_chan *chan)
BUG_ON(chan->client_count > 1);
WARN_ON(ichan->status != IPU_CHANNEL_FREE);
- chan->cookie = 1;
- ichan->completed = -ENXIO;
+ dma_cookie_init(chan);
ret = ipu_irq_map(chan->chan_id);
if (ret < 0)
@@ -1600,9 +1594,7 @@ static void idmac_free_chan_resources(struct dma_chan *chan)
static enum dma_status idmac_tx_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *txstate)
{
- struct idmac_channel *ichan = to_idmac_chan(chan);
-
- dma_set_tx_state(txstate, ichan->completed, chan->cookie, 0);
+ dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, 0);
if (cookie != chan->cookie)
return DMA_ERROR;
return DMA_SUCCESS;
@@ -1638,11 +1630,10 @@ static int __init ipu_idmac_init(struct ipu *ipu)
ichan->status = IPU_CHANNEL_FREE;
ichan->sec_chan_en = false;
- ichan->completed = -ENXIO;
snprintf(ichan->eof_name, sizeof(ichan->eof_name), "IDMAC EOF %d", i);
dma_chan->device = &idmac->dma;
- dma_chan->cookie = 1;
+ dma_cookie_init(dma_chan);
dma_chan->chan_id = i;
list_add_tail(&dma_chan->device_node, &dma->channels);
}
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 4d6d4cf66949..2ab0a3d0eed5 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -44,6 +44,8 @@
#include <linux/random.h>
+#include "dmaengine.h"
+
/* Number of DMA Transfer descriptors allocated per channel */
#define MPC_DMA_DESCRIPTORS 64
@@ -188,7 +190,6 @@ struct mpc_dma_chan {
struct list_head completed;
struct mpc_dma_tcd *tcd;
dma_addr_t tcd_paddr;
- dma_cookie_t completed_cookie;
/* Lock for this structure */
spinlock_t lock;
@@ -365,7 +366,7 @@ static void mpc_dma_process_completed(struct mpc_dma *mdma)
/* Free descriptors */
spin_lock_irqsave(&mchan->lock, flags);
list_splice_tail_init(&list, &mchan->free);
- mchan->completed_cookie = last_cookie;
+ mchan->chan.completed_cookie = last_cookie;
spin_unlock_irqrestore(&mchan->lock, flags);
}
}
@@ -438,13 +439,7 @@ static dma_cookie_t mpc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
mpc_dma_execute(mchan);
/* Update cookie */
- cookie = mchan->chan.cookie + 1;
- if (cookie <= 0)
- cookie = 1;
-
- mchan->chan.cookie = cookie;
- mdesc->desc.cookie = cookie;
-
+ cookie = dma_cookie_assign(txd);
spin_unlock_irqrestore(&mchan->lock, flags);
return cookie;
@@ -562,17 +557,14 @@ mpc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ enum dma_status ret;
unsigned long flags;
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
spin_lock_irqsave(&mchan->lock, flags);
- last_used = mchan->chan.cookie;
- last_complete = mchan->completed_cookie;
+ ret = dma_cookie_status(chan, cookie, txstate);
spin_unlock_irqrestore(&mchan->lock, flags);
- dma_set_tx_state(txstate, last_complete, last_used, 0);
- return dma_async_is_complete(cookie, last_complete, last_used);
+ return ret;
}
/* Prepare descriptor for memory to memory copy */
@@ -741,8 +733,7 @@ static int __devinit mpc_dma_probe(struct platform_device *op)
mchan = &mdma->channels[i];
mchan->chan.device = dma;
- mchan->chan.cookie = 1;
- mchan->completed_cookie = mchan->chan.cookie;
+ dma_cookie_init(&mchan->chan);
INIT_LIST_HEAD(&mchan->free);
INIT_LIST_HEAD(&mchan->prepared);
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index e779b434af45..fa5d55fea46c 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -26,6 +26,8 @@
#include <linux/platform_device.h>
#include <linux/memory.h>
#include <plat/mv_xor.h>
+
+#include "dmaengine.h"
#include "mv_xor.h"
static void mv_xor_issue_pending(struct dma_chan *chan);
@@ -435,7 +437,7 @@ static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan)
}
if (cookie > 0)
- mv_chan->completed_cookie = cookie;
+ mv_chan->common.completed_cookie = cookie;
}
static void
@@ -534,18 +536,6 @@ retry:
return NULL;
}
-static dma_cookie_t
-mv_desc_assign_cookie(struct mv_xor_chan *mv_chan,
- struct mv_xor_desc_slot *desc)
-{
- dma_cookie_t cookie = mv_chan->common.cookie;
-
- if (++cookie < 0)
- cookie = 1;
- mv_chan->common.cookie = desc->async_tx.cookie = cookie;
- return cookie;
-}
-
/************************ DMA engine API functions ****************************/
static dma_cookie_t
mv_xor_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -563,7 +553,7 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx)
grp_start = sw_desc->group_head;
spin_lock_bh(&mv_chan->lock);
- cookie = mv_desc_assign_cookie(mv_chan, sw_desc);
+ cookie = dma_cookie_assign(tx);
if (list_empty(&mv_chan->chain))
list_splice_init(&sw_desc->tx_list, &mv_chan->chain);
@@ -820,27 +810,16 @@ static enum dma_status mv_xor_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
enum dma_status ret;
- last_used = chan->cookie;
- last_complete = mv_chan->completed_cookie;
- mv_chan->is_complete_cookie = cookie;
- dma_set_tx_state(txstate, last_complete, last_used, 0);
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_SUCCESS) {
mv_xor_clean_completed_slots(mv_chan);
return ret;
}
mv_xor_slot_cleanup(mv_chan);
- last_used = chan->cookie;
- last_complete = mv_chan->completed_cookie;
-
- dma_set_tx_state(txstate, last_complete, last_used, 0);
- return dma_async_is_complete(cookie, last_complete, last_used);
+ return dma_cookie_status(chan, cookie, txstate);
}
static void mv_dump_xor_regs(struct mv_xor_chan *chan)
@@ -1214,6 +1193,7 @@ static int __devinit mv_xor_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mv_chan->completed_slots);
INIT_LIST_HEAD(&mv_chan->all_slots);
mv_chan->common.device = dma_dev;
+ dma_cookie_init(&mv_chan->common);
list_add_tail(&mv_chan->common.device_node, &dma_dev->channels);
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index 977b592e976b..654876b7ba1d 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -78,7 +78,6 @@ struct mv_xor_device {
/**
* struct mv_xor_chan - internal representation of a XOR channel
* @pending: allows batching of hardware operations
- * @completed_cookie: identifier for the most recently completed operation
* @lock: serializes enqueue/dequeue operations to the descriptors pool
* @mmr_base: memory mapped register base
* @idx: the index of the xor channel
@@ -93,7 +92,6 @@ struct mv_xor_device {
*/
struct mv_xor_chan {
int pending;
- dma_cookie_t completed_cookie;
spinlock_t lock; /* protects the descriptor slot pool */
void __iomem *mmr_base;
unsigned int idx;
@@ -109,7 +107,6 @@ struct mv_xor_chan {
#ifdef USE_TIMER
unsigned long cleanup_time;
u32 current_on_last_cleanup;
- dma_cookie_t is_complete_cookie;
#endif
};
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index b06cd4ca626f..65334c49b71e 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -28,6 +28,8 @@
#include <mach/dma.h>
#include <mach/common.h>
+#include "dmaengine.h"
+
/*
* NOTE: The term "PIO" throughout the mxs-dma implementation means
* PIO mode of mxs apbh-dma and apbx-dma. With this working mode,
@@ -111,7 +113,6 @@ struct mxs_dma_chan {
struct mxs_dma_ccw *ccw;
dma_addr_t ccw_phys;
int desc_count;
- dma_cookie_t last_completed;
enum dma_status status;
unsigned int flags;
#define MXS_DMA_SG_LOOP (1 << 0)
@@ -193,19 +194,6 @@ static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
mxs_chan->status = DMA_IN_PROGRESS;
}
-static dma_cookie_t mxs_dma_assign_cookie(struct mxs_dma_chan *mxs_chan)
-{
- dma_cookie_t cookie = mxs_chan->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- mxs_chan->chan.cookie = cookie;
- mxs_chan->desc.cookie = cookie;
-
- return cookie;
-}
-
static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
{
return container_of(chan, struct mxs_dma_chan, chan);
@@ -217,7 +205,7 @@ static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
mxs_dma_enable_chan(mxs_chan);
- return mxs_dma_assign_cookie(mxs_chan);
+ return dma_cookie_assign(tx);
}
static void mxs_dma_tasklet(unsigned long data)
@@ -274,7 +262,7 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
stat1 &= ~(1 << channel);
if (mxs_chan->status == DMA_SUCCESS)
- mxs_chan->last_completed = mxs_chan->desc.cookie;
+ dma_cookie_complete(&mxs_chan->desc);
/* schedule tasklet on this channel */
tasklet_schedule(&mxs_chan->tasklet);
@@ -352,7 +340,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long append)
+ unsigned long append, void *context)
{
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -447,7 +435,8 @@ err_out:
static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
- size_t period_len, enum dma_transfer_direction direction)
+ size_t period_len, enum dma_transfer_direction direction,
+ void *context)
{
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -538,7 +527,7 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
dma_cookie_t last_used;
last_used = chan->cookie;
- dma_set_tx_state(txstate, mxs_chan->last_completed, last_used, 0);
+ dma_set_tx_state(txstate, chan->completed_cookie, last_used, 0);
return mxs_chan->status;
}
@@ -630,6 +619,7 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
mxs_chan->mxs_dma = mxs_dma;
mxs_chan->chan.device = &mxs_dma->dma_device;
+ dma_cookie_init(&mxs_chan->chan);
tasklet_init(&mxs_chan->tasklet, mxs_dma_tasklet,
(unsigned long) mxs_chan);
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index 823f58179f9d..65c0495a6d40 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -25,6 +25,8 @@
#include <linux/module.h>
#include <linux/pch_dma.h>
+#include "dmaengine.h"
+
#define DRV_NAME "pch-dma"
#define DMA_CTL0_DISABLE 0x0
@@ -105,7 +107,6 @@ struct pch_dma_chan {
spinlock_t lock;
- dma_cookie_t completed_cookie;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
@@ -416,20 +417,6 @@ static void pdc_advance_work(struct pch_dma_chan *pd_chan)
}
}
-static dma_cookie_t pdc_assign_cookie(struct pch_dma_chan *pd_chan,
- struct pch_dma_desc *desc)
-{
- dma_cookie_t cookie = pd_chan->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- pd_chan->chan.cookie = cookie;
- desc->txd.cookie = cookie;
-
- return cookie;
-}
-
static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd)
{
struct pch_dma_desc *desc = to_pd_desc(txd);
@@ -437,7 +424,7 @@ static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd)
dma_cookie_t cookie;
spin_lock(&pd_chan->lock);
- cookie = pdc_assign_cookie(pd_chan, desc);
+ cookie = dma_cookie_assign(txd);
if (list_empty(&pd_chan->active_list)) {
list_add_tail(&desc->desc_node, &pd_chan->active_list);
@@ -544,7 +531,7 @@ static int pd_alloc_chan_resources(struct dma_chan *chan)
spin_lock_irq(&pd_chan->lock);
list_splice(&tmp_list, &pd_chan->free_list);
pd_chan->descs_allocated = i;
- pd_chan->completed_cookie = chan->cookie = 1;
+ dma_cookie_init(chan);
spin_unlock_irq(&pd_chan->lock);
pdc_enable_irq(chan, 1);
@@ -578,19 +565,12 @@ static enum dma_status pd_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct pch_dma_chan *pd_chan = to_pd_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_completed;
- int ret;
+ enum dma_status ret;
spin_lock_irq(&pd_chan->lock);
- last_completed = pd_chan->completed_cookie;
- last_used = chan->cookie;
+ ret = dma_cookie_status(chan, cookie, txstate);
spin_unlock_irq(&pd_chan->lock);
- ret = dma_async_is_complete(cookie, last_completed, last_used);
-
- dma_set_tx_state(txstate, last_completed, last_used, 0);
-
return ret;
}
@@ -607,7 +587,8 @@ static void pd_issue_pending(struct dma_chan *chan)
static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
struct scatterlist *sgl, unsigned int sg_len,
- enum dma_transfer_direction direction, unsigned long flags)
+ enum dma_transfer_direction direction, unsigned long flags,
+ void *context)
{
struct pch_dma_chan *pd_chan = to_pd_chan(chan);
struct pch_dma_slave *pd_slave = chan->private;
@@ -932,7 +913,7 @@ static int __devinit pch_dma_probe(struct pci_dev *pdev,
struct pch_dma_chan *pd_chan = &pd->channels[i];
pd_chan->chan.device = &pd->dma;
- pd_chan->chan.cookie = 1;
+ dma_cookie_init(&pd_chan->chan);
pd_chan->membase = &regs->desc[i];
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 16b66c827f19..282caf118be8 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -1,4 +1,6 @@
-/* linux/drivers/dma/pl330.c
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
@@ -9,10 +11,15 @@
* (at your option) any later version.
*/
+#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
@@ -21,8 +28,497 @@
#include <linux/scatterlist.h>
#include <linux/of.h>
+#include "dmaengine.h"
+#define PL330_MAX_CHAN 8
+#define PL330_MAX_IRQS 32
+#define PL330_MAX_PERI 32
+
+enum pl330_srccachectrl {
+ SCCTRL0, /* Noncacheable and nonbufferable */
+ SCCTRL1, /* Bufferable only */
+ SCCTRL2, /* Cacheable, but do not allocate */
+ SCCTRL3, /* Cacheable and bufferable, but do not allocate */
+ SINVALID1,
+ SINVALID2,
+ SCCTRL6, /* Cacheable write-through, allocate on reads only */
+ SCCTRL7, /* Cacheable write-back, allocate on reads only */
+};
+
+enum pl330_dstcachectrl {
+ DCCTRL0, /* Noncacheable and nonbufferable */
+ DCCTRL1, /* Bufferable only */
+ DCCTRL2, /* Cacheable, but do not allocate */
+ DCCTRL3, /* Cacheable and bufferable, but do not allocate */
+ DINVALID1, /* AWCACHE = 0x1000 */
+ DINVALID2,
+ DCCTRL6, /* Cacheable write-through, allocate on writes only */
+ DCCTRL7, /* Cacheable write-back, allocate on writes only */
+};
+
+enum pl330_byteswap {
+ SWAP_NO,
+ SWAP_2,
+ SWAP_4,
+ SWAP_8,
+ SWAP_16,
+};
+
+enum pl330_reqtype {
+ MEMTOMEM,
+ MEMTODEV,
+ DEVTOMEM,
+ DEVTODEV,
+};
+
+/* Register and Bit field Definitions */
+#define DS 0x0
+#define DS_ST_STOP 0x0
+#define DS_ST_EXEC 0x1
+#define DS_ST_CMISS 0x2
+#define DS_ST_UPDTPC 0x3
+#define DS_ST_WFE 0x4
+#define DS_ST_ATBRR 0x5
+#define DS_ST_QBUSY 0x6
+#define DS_ST_WFP 0x7
+#define DS_ST_KILL 0x8
+#define DS_ST_CMPLT 0x9
+#define DS_ST_FLTCMP 0xe
+#define DS_ST_FAULT 0xf
+
+#define DPC 0x4
+#define INTEN 0x20
+#define ES 0x24
+#define INTSTATUS 0x28
+#define INTCLR 0x2c
+#define FSM 0x30
+#define FSC 0x34
+#define FTM 0x38
+
+#define _FTC 0x40
+#define FTC(n) (_FTC + (n)*0x4)
+
+#define _CS 0x100
+#define CS(n) (_CS + (n)*0x8)
+#define CS_CNS (1 << 21)
+
+#define _CPC 0x104
+#define CPC(n) (_CPC + (n)*0x8)
+
+#define _SA 0x400
+#define SA(n) (_SA + (n)*0x20)
+
+#define _DA 0x404
+#define DA(n) (_DA + (n)*0x20)
+
+#define _CC 0x408
+#define CC(n) (_CC + (n)*0x20)
+
+#define CC_SRCINC (1 << 0)
+#define CC_DSTINC (1 << 14)
+#define CC_SRCPRI (1 << 8)
+#define CC_DSTPRI (1 << 22)
+#define CC_SRCNS (1 << 9)
+#define CC_DSTNS (1 << 23)
+#define CC_SRCIA (1 << 10)
+#define CC_DSTIA (1 << 24)
+#define CC_SRCBRSTLEN_SHFT 4
+#define CC_DSTBRSTLEN_SHFT 18
+#define CC_SRCBRSTSIZE_SHFT 1
+#define CC_DSTBRSTSIZE_SHFT 15
+#define CC_SRCCCTRL_SHFT 11
+#define CC_SRCCCTRL_MASK 0x7
+#define CC_DSTCCTRL_SHFT 25
+#define CC_DRCCCTRL_MASK 0x7
+#define CC_SWAP_SHFT 28
+
+#define _LC0 0x40c
+#define LC0(n) (_LC0 + (n)*0x20)
+
+#define _LC1 0x410
+#define LC1(n) (_LC1 + (n)*0x20)
+
+#define DBGSTATUS 0xd00
+#define DBG_BUSY (1 << 0)
+
+#define DBGCMD 0xd04
+#define DBGINST0 0xd08
+#define DBGINST1 0xd0c
+
+#define CR0 0xe00
+#define CR1 0xe04
+#define CR2 0xe08
+#define CR3 0xe0c
+#define CR4 0xe10
+#define CRD 0xe14
+
+#define PERIPH_ID 0xfe0
+#define PERIPH_REV_SHIFT 20
+#define PERIPH_REV_MASK 0xf
+#define PERIPH_REV_R0P0 0
+#define PERIPH_REV_R1P0 1
+#define PERIPH_REV_R1P1 2
+#define PCELL_ID 0xff0
+
+#define CR0_PERIPH_REQ_SET (1 << 0)
+#define CR0_BOOT_EN_SET (1 << 1)
+#define CR0_BOOT_MAN_NS (1 << 2)
+#define CR0_NUM_CHANS_SHIFT 4
+#define CR0_NUM_CHANS_MASK 0x7
+#define CR0_NUM_PERIPH_SHIFT 12
+#define CR0_NUM_PERIPH_MASK 0x1f
+#define CR0_NUM_EVENTS_SHIFT 17
+#define CR0_NUM_EVENTS_MASK 0x1f
+
+#define CR1_ICACHE_LEN_SHIFT 0
+#define CR1_ICACHE_LEN_MASK 0x7
+#define CR1_NUM_ICACHELINES_SHIFT 4
+#define CR1_NUM_ICACHELINES_MASK 0xf
+
+#define CRD_DATA_WIDTH_SHIFT 0
+#define CRD_DATA_WIDTH_MASK 0x7
+#define CRD_WR_CAP_SHIFT 4
+#define CRD_WR_CAP_MASK 0x7
+#define CRD_WR_Q_DEP_SHIFT 8
+#define CRD_WR_Q_DEP_MASK 0xf
+#define CRD_RD_CAP_SHIFT 12
+#define CRD_RD_CAP_MASK 0x7
+#define CRD_RD_Q_DEP_SHIFT 16
+#define CRD_RD_Q_DEP_MASK 0xf
+#define CRD_DATA_BUFF_SHIFT 20
+#define CRD_DATA_BUFF_MASK 0x3ff
+
+#define PART 0x330
+#define DESIGNER 0x41
+#define REVISION 0x0
+#define INTEG_CFG 0x0
+#define PERIPH_ID_VAL ((PART << 0) | (DESIGNER << 12))
+
+#define PCELL_ID_VAL 0xb105f00d
+
+#define PL330_STATE_STOPPED (1 << 0)
+#define PL330_STATE_EXECUTING (1 << 1)
+#define PL330_STATE_WFE (1 << 2)
+#define PL330_STATE_FAULTING (1 << 3)
+#define PL330_STATE_COMPLETING (1 << 4)
+#define PL330_STATE_WFP (1 << 5)
+#define PL330_STATE_KILLING (1 << 6)
+#define PL330_STATE_FAULT_COMPLETING (1 << 7)
+#define PL330_STATE_CACHEMISS (1 << 8)
+#define PL330_STATE_UPDTPC (1 << 9)
+#define PL330_STATE_ATBARRIER (1 << 10)
+#define PL330_STATE_QUEUEBUSY (1 << 11)
+#define PL330_STATE_INVALID (1 << 15)
+
+#define PL330_STABLE_STATES (PL330_STATE_STOPPED | PL330_STATE_EXECUTING \
+ | PL330_STATE_WFE | PL330_STATE_FAULTING)
+
+#define CMD_DMAADDH 0x54
+#define CMD_DMAEND 0x00
+#define CMD_DMAFLUSHP 0x35
+#define CMD_DMAGO 0xa0
+#define CMD_DMALD 0x04
+#define CMD_DMALDP 0x25
+#define CMD_DMALP 0x20
+#define CMD_DMALPEND 0x28
+#define CMD_DMAKILL 0x01
+#define CMD_DMAMOV 0xbc
+#define CMD_DMANOP 0x18
+#define CMD_DMARMB 0x12
+#define CMD_DMASEV 0x34
+#define CMD_DMAST 0x08
+#define CMD_DMASTP 0x29
+#define CMD_DMASTZ 0x0c
+#define CMD_DMAWFE 0x36
+#define CMD_DMAWFP 0x30
+#define CMD_DMAWMB 0x13
+
+#define SZ_DMAADDH 3
+#define SZ_DMAEND 1
+#define SZ_DMAFLUSHP 2
+#define SZ_DMALD 1
+#define SZ_DMALDP 2
+#define SZ_DMALP 2
+#define SZ_DMALPEND 2
+#define SZ_DMAKILL 1
+#define SZ_DMAMOV 6
+#define SZ_DMANOP 1
+#define SZ_DMARMB 1
+#define SZ_DMASEV 2
+#define SZ_DMAST 1
+#define SZ_DMASTP 2
+#define SZ_DMASTZ 1
+#define SZ_DMAWFE 2
+#define SZ_DMAWFP 2
+#define SZ_DMAWMB 1
+#define SZ_DMAGO 6
+
+#define BRST_LEN(ccr) ((((ccr) >> CC_SRCBRSTLEN_SHFT) & 0xf) + 1)
+#define BRST_SIZE(ccr) (1 << (((ccr) >> CC_SRCBRSTSIZE_SHFT) & 0x7))
+
+#define BYTE_TO_BURST(b, ccr) ((b) / BRST_SIZE(ccr) / BRST_LEN(ccr))
+#define BURST_TO_BYTE(c, ccr) ((c) * BRST_SIZE(ccr) * BRST_LEN(ccr))
+
+/*
+ * With 256 bytes, we can do more than 2.5MB and 5MB xfers per req
+ * at 1byte/burst for P<->M and M<->M respectively.
+ * For typical scenario, at 1word/burst, 10MB and 20MB xfers per req
+ * should be enough for P<->M and M<->M respectively.
+ */
+#define MCODE_BUFF_PER_REQ 256
+
+/* If the _pl330_req is available to the client */
+#define IS_FREE(req) (*((u8 *)((req)->mc_cpu)) == CMD_DMAEND)
+
+/* Use this _only_ to wait on transient states */
+#define UNTIL(t, s) while (!(_state(t) & (s))) cpu_relax();
+
+#ifdef PL330_DEBUG_MCGEN
+static unsigned cmd_line;
+#define PL330_DBGCMD_DUMP(off, x...) do { \
+ printk("%x:", cmd_line); \
+ printk(x); \
+ cmd_line += off; \
+ } while (0)
+#define PL330_DBGMC_START(addr) (cmd_line = addr)
+#else
+#define PL330_DBGCMD_DUMP(off, x...) do {} while (0)
+#define PL330_DBGMC_START(addr) do {} while (0)
+#endif
+
+/* The number of default descriptors */
+
#define NR_DEFAULT_DESC 16
+/* Populated by the PL330 core driver for DMA API driver's info */
+struct pl330_config {
+ u32 periph_id;
+ u32 pcell_id;
+#define DMAC_MODE_NS (1 << 0)
+ unsigned int mode;
+ unsigned int data_bus_width:10; /* In number of bits */
+ unsigned int data_buf_dep:10;
+ unsigned int num_chan:4;
+ unsigned int num_peri:6;
+ u32 peri_ns;
+ unsigned int num_events:6;
+ u32 irq_ns;
+};
+
+/* Handle to the DMAC provided to the PL330 core */
+struct pl330_info {
+ /* Owning device */
+ struct device *dev;
+ /* Size of MicroCode buffers for each channel. */
+ unsigned mcbufsz;
+ /* ioremap'ed address of PL330 registers. */
+ void __iomem *base;
+ /* Client can freely use it. */
+ void *client_data;
+ /* PL330 core data, Client must not touch it. */
+ void *pl330_data;
+ /* Populated by the PL330 core driver during pl330_add */
+ struct pl330_config pcfg;
+ /*
+ * If the DMAC has some reset mechanism, then the
+ * client may want to provide pointer to the method.
+ */
+ void (*dmac_reset)(struct pl330_info *pi);
+};
+
+/**
+ * Request Configuration.
+ * The PL330 core does not modify this and uses the last
+ * working configuration if the request doesn't provide any.
+ *
+ * The Client may want to provide this info only for the
+ * first request and a request with new settings.
+ */
+struct pl330_reqcfg {
+ /* Address Incrementing */
+ unsigned dst_inc:1;
+ unsigned src_inc:1;
+
+ /*
+ * For now, the SRC & DST protection levels
+ * and burst size/length are assumed same.
+ */
+ bool nonsecure;
+ bool privileged;
+ bool insnaccess;
+ unsigned brst_len:5;
+ unsigned brst_size:3; /* in power of 2 */
+
+ enum pl330_dstcachectrl dcctl;
+ enum pl330_srccachectrl scctl;
+ enum pl330_byteswap swap;
+ struct pl330_config *pcfg;
+};
+
+/*
+ * One cycle of DMAC operation.
+ * There may be more than one xfer in a request.
+ */
+struct pl330_xfer {
+ u32 src_addr;
+ u32 dst_addr;
+ /* Size to xfer */
+ u32 bytes;
+ /*
+ * Pointer to next xfer in the list.
+ * The last xfer in the req must point to NULL.
+ */
+ struct pl330_xfer *next;
+};
+
+/* The xfer callbacks are made with one of these arguments. */
+enum pl330_op_err {
+ /* The all xfers in the request were success. */
+ PL330_ERR_NONE,
+ /* If req aborted due to global error. */
+ PL330_ERR_ABORT,
+ /* If req failed due to problem with Channel. */
+ PL330_ERR_FAIL,
+};
+
+/* A request defining Scatter-Gather List ending with NULL xfer. */
+struct pl330_req {
+ enum pl330_reqtype rqtype;
+ /* Index of peripheral for the xfer. */
+ unsigned peri:5;
+ /* Unique token for this xfer, set by the client. */
+ void *token;
+ /* Callback to be called after xfer. */
+ void (*xfer_cb)(void *token, enum pl330_op_err err);
+ /* If NULL, req will be done at last set parameters. */
+ struct pl330_reqcfg *cfg;
+ /* Pointer to first xfer in the request. */
+ struct pl330_xfer *x;
+};
+
+/*
+ * To know the status of the channel and DMAC, the client
+ * provides a pointer to this structure. The PL330 core
+ * fills it with current information.
+ */
+struct pl330_chanstatus {
+ /*
+ * If the DMAC engine halted due to some error,
+ * the client should remove-add DMAC.
+ */
+ bool dmac_halted;
+ /*
+ * If channel is halted due to some error,
+ * the client should ABORT/FLUSH and START the channel.
+ */
+ bool faulting;
+ /* Location of last load */
+ u32 src_addr;
+ /* Location of last store */
+ u32 dst_addr;
+ /*
+ * Pointer to the currently active req, NULL if channel is
+ * inactive, even though the requests may be present.
+ */
+ struct pl330_req *top_req;
+ /* Pointer to req waiting second in the queue if any. */
+ struct pl330_req *wait_req;
+};
+
+enum pl330_chan_op {
+ /* Start the channel */
+ PL330_OP_START,
+ /* Abort the active xfer */
+ PL330_OP_ABORT,
+ /* Stop xfer and flush queue */
+ PL330_OP_FLUSH,
+};
+
+struct _xfer_spec {
+ u32 ccr;
+ struct pl330_req *r;
+ struct pl330_xfer *x;
+};
+
+enum dmamov_dst {
+ SAR = 0,
+ CCR,
+ DAR,
+};
+
+enum pl330_dst {
+ SRC = 0,
+ DST,
+};
+
+enum pl330_cond {
+ SINGLE,
+ BURST,
+ ALWAYS,
+};
+
+struct _pl330_req {
+ u32 mc_bus;
+ void *mc_cpu;
+ /* Number of bytes taken to setup MC for the req */
+ u32 mc_len;
+ struct pl330_req *r;
+ /* Hook to attach to DMAC's list of reqs with due callback */
+ struct list_head rqd;
+};
+
+/* ToBeDone for tasklet */
+struct _pl330_tbd {
+ bool reset_dmac;
+ bool reset_mngr;
+ u8 reset_chan;
+};
+
+/* A DMAC Thread */
+struct pl330_thread {
+ u8 id;
+ int ev;
+ /* If the channel is not yet acquired by any client */
+ bool free;
+ /* Parent DMAC */
+ struct pl330_dmac *dmac;
+ /* Only two at a time */
+ struct _pl330_req req[2];
+ /* Index of the last enqueued request */
+ unsigned lstenq;
+ /* Index of the last submitted request or -1 if the DMA is stopped */
+ int req_running;
+};
+
+enum pl330_dmac_state {
+ UNINIT,
+ INIT,
+ DYING,
+};
+
+/* A DMAC */
+struct pl330_dmac {
+ spinlock_t lock;
+ /* Holds list of reqs with due callbacks */
+ struct list_head req_done;
+ /* Pointer to platform specific stuff */
+ struct pl330_info *pinfo;
+ /* Maximum possible events/irqs */
+ int events[32];
+ /* BUS address of MicroCode buffer */
+ u32 mcode_bus;
+ /* CPU address of MicroCode buffer */
+ void *mcode_cpu;
+ /* List of all Channel threads */
+ struct pl330_thread *channels;
+ /* Pointer to the MANAGER thread */
+ struct pl330_thread *manager;
+ /* To handle bad news in interrupt */
+ struct tasklet_struct tasks;
+ struct _pl330_tbd dmac_tbd;
+ /* State of DMAC operation */
+ enum pl330_dmac_state state;
+};
+
enum desc_status {
/* In the DMAC pool */
FREE,
@@ -51,9 +547,6 @@ struct dma_pl330_chan {
/* DMA-Engine Channel */
struct dma_chan chan;
- /* Last completed cookie */
- dma_cookie_t completed;
-
/* List of to be xfered descriptors */
struct list_head work_list;
@@ -117,6 +610,1599 @@ struct dma_pl330_desc {
struct dma_pl330_chan *pchan;
};
+static inline void _callback(struct pl330_req *r, enum pl330_op_err err)
+{
+ if (r && r->xfer_cb)
+ r->xfer_cb(r->token, err);
+}
+
+static inline bool _queue_empty(struct pl330_thread *thrd)
+{
+ return (IS_FREE(&thrd->req[0]) && IS_FREE(&thrd->req[1]))
+ ? true : false;
+}
+
+static inline bool _queue_full(struct pl330_thread *thrd)
+{
+ return (IS_FREE(&thrd->req[0]) || IS_FREE(&thrd->req[1]))
+ ? false : true;
+}
+
+static inline bool is_manager(struct pl330_thread *thrd)
+{
+ struct pl330_dmac *pl330 = thrd->dmac;
+
+ /* MANAGER is indexed at the end */
+ if (thrd->id == pl330->pinfo->pcfg.num_chan)
+ return true;
+ else
+ return false;
+}
+
+/* If manager of the thread is in Non-Secure mode */
+static inline bool _manager_ns(struct pl330_thread *thrd)
+{
+ struct pl330_dmac *pl330 = thrd->dmac;
+
+ return (pl330->pinfo->pcfg.mode & DMAC_MODE_NS) ? true : false;
+}
+
+static inline u32 get_id(struct pl330_info *pi, u32 off)
+{
+ void __iomem *regs = pi->base;
+ u32 id = 0;
+
+ id |= (readb(regs + off + 0x0) << 0);
+ id |= (readb(regs + off + 0x4) << 8);
+ id |= (readb(regs + off + 0x8) << 16);
+ id |= (readb(regs + off + 0xc) << 24);
+
+ return id;
+}
+
+static inline u32 get_revision(u32 periph_id)
+{
+ return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK;
+}
+
+static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[],
+ enum pl330_dst da, u16 val)
+{
+ if (dry_run)
+ return SZ_DMAADDH;
+
+ buf[0] = CMD_DMAADDH;
+ buf[0] |= (da << 1);
+ *((u16 *)&buf[1]) = val;
+
+ PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n",
+ da == 1 ? "DA" : "SA", val);
+
+ return SZ_DMAADDH;
+}
+
+static inline u32 _emit_END(unsigned dry_run, u8 buf[])
+{
+ if (dry_run)
+ return SZ_DMAEND;
+
+ buf[0] = CMD_DMAEND;
+
+ PL330_DBGCMD_DUMP(SZ_DMAEND, "\tDMAEND\n");
+
+ return SZ_DMAEND;
+}
+
+static inline u32 _emit_FLUSHP(unsigned dry_run, u8 buf[], u8 peri)
+{
+ if (dry_run)
+ return SZ_DMAFLUSHP;
+
+ buf[0] = CMD_DMAFLUSHP;
+
+ peri &= 0x1f;
+ peri <<= 3;
+ buf[1] = peri;
+
+ PL330_DBGCMD_DUMP(SZ_DMAFLUSHP, "\tDMAFLUSHP %u\n", peri >> 3);
+
+ return SZ_DMAFLUSHP;
+}
+
+static inline u32 _emit_LD(unsigned dry_run, u8 buf[], enum pl330_cond cond)
+{
+ if (dry_run)
+ return SZ_DMALD;
+
+ buf[0] = CMD_DMALD;
+
+ if (cond == SINGLE)
+ buf[0] |= (0 << 1) | (1 << 0);
+ else if (cond == BURST)
+ buf[0] |= (1 << 1) | (1 << 0);
+
+ PL330_DBGCMD_DUMP(SZ_DMALD, "\tDMALD%c\n",
+ cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
+
+ return SZ_DMALD;
+}
+
+static inline u32 _emit_LDP(unsigned dry_run, u8 buf[],
+ enum pl330_cond cond, u8 peri)
+{
+ if (dry_run)
+ return SZ_DMALDP;
+
+ buf[0] = CMD_DMALDP;
+
+ if (cond == BURST)
+ buf[0] |= (1 << 1);
+
+ peri &= 0x1f;
+ peri <<= 3;
+ buf[1] = peri;
+
+ PL330_DBGCMD_DUMP(SZ_DMALDP, "\tDMALDP%c %u\n",
+ cond == SINGLE ? 'S' : 'B', peri >> 3);
+
+ return SZ_DMALDP;
+}
+
+static inline u32 _emit_LP(unsigned dry_run, u8 buf[],
+ unsigned loop, u8 cnt)
+{
+ if (dry_run)
+ return SZ_DMALP;
+
+ buf[0] = CMD_DMALP;
+
+ if (loop)
+ buf[0] |= (1 << 1);
+
+ cnt--; /* DMAC increments by 1 internally */
+ buf[1] = cnt;
+
+ PL330_DBGCMD_DUMP(SZ_DMALP, "\tDMALP_%c %u\n", loop ? '1' : '0', cnt);
+
+ return SZ_DMALP;
+}
+
+struct _arg_LPEND {
+ enum pl330_cond cond;
+ bool forever;
+ unsigned loop;
+ u8 bjump;
+};
+
+static inline u32 _emit_LPEND(unsigned dry_run, u8 buf[],
+ const struct _arg_LPEND *arg)
+{
+ enum pl330_cond cond = arg->cond;
+ bool forever = arg->forever;
+ unsigned loop = arg->loop;
+ u8 bjump = arg->bjump;
+
+ if (dry_run)
+ return SZ_DMALPEND;
+
+ buf[0] = CMD_DMALPEND;
+
+ if (loop)
+ buf[0] |= (1 << 2);
+
+ if (!forever)
+ buf[0] |= (1 << 4);
+
+ if (cond == SINGLE)
+ buf[0] |= (0 << 1) | (1 << 0);
+ else if (cond == BURST)
+ buf[0] |= (1 << 1) | (1 << 0);
+
+ buf[1] = bjump;
+
+ PL330_DBGCMD_DUMP(SZ_DMALPEND, "\tDMALP%s%c_%c bjmpto_%x\n",
+ forever ? "FE" : "END",
+ cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'),
+ loop ? '1' : '0',
+ bjump);
+
+ return SZ_DMALPEND;
+}
+
+static inline u32 _emit_KILL(unsigned dry_run, u8 buf[])
+{
+ if (dry_run)
+ return SZ_DMAKILL;
+
+ buf[0] = CMD_DMAKILL;
+
+ return SZ_DMAKILL;
+}
+
+static inline u32 _emit_MOV(unsigned dry_run, u8 buf[],
+ enum dmamov_dst dst, u32 val)
+{
+ if (dry_run)
+ return SZ_DMAMOV;
+
+ buf[0] = CMD_DMAMOV;
+ buf[1] = dst;
+ *((u32 *)&buf[2]) = val;
+
+ PL330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n",
+ dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"), val);
+
+ return SZ_DMAMOV;
+}
+
+static inline u32 _emit_NOP(unsigned dry_run, u8 buf[])
+{
+ if (dry_run)
+ return SZ_DMANOP;
+
+ buf[0] = CMD_DMANOP;
+
+ PL330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n");
+
+ return SZ_DMANOP;
+}
+
+static inline u32 _emit_RMB(unsigned dry_run, u8 buf[])
+{
+ if (dry_run)
+ return SZ_DMARMB;
+
+ buf[0] = CMD_DMARMB;
+
+ PL330_DBGCMD_DUMP(SZ_DMARMB, "\tDMARMB\n");
+
+ return SZ_DMARMB;
+}
+
+static inline u32 _emit_SEV(unsigned dry_run, u8 buf[], u8 ev)
+{
+ if (dry_run)
+ return SZ_DMASEV;
+
+ buf[0] = CMD_DMASEV;
+
+ ev &= 0x1f;
+ ev <<= 3;
+ buf[1] = ev;
+
+ PL330_DBGCMD_DUMP(SZ_DMASEV, "\tDMASEV %u\n", ev >> 3);
+
+ return SZ_DMASEV;
+}
+
+static inline u32 _emit_ST(unsigned dry_run, u8 buf[], enum pl330_cond cond)
+{
+ if (dry_run)
+ return SZ_DMAST;
+
+ buf[0] = CMD_DMAST;
+
+ if (cond == SINGLE)
+ buf[0] |= (0 << 1) | (1 << 0);
+ else if (cond == BURST)
+ buf[0] |= (1 << 1) | (1 << 0);
+
+ PL330_DBGCMD_DUMP(SZ_DMAST, "\tDMAST%c\n",
+ cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
+
+ return SZ_DMAST;
+}
+
+static inline u32 _emit_STP(unsigned dry_run, u8 buf[],
+ enum pl330_cond cond, u8 peri)
+{
+ if (dry_run)
+ return SZ_DMASTP;
+
+ buf[0] = CMD_DMASTP;
+
+ if (cond == BURST)
+ buf[0] |= (1 << 1);
+
+ peri &= 0x1f;
+ peri <<= 3;
+ buf[1] = peri;
+
+ PL330_DBGCMD_DUMP(SZ_DMASTP, "\tDMASTP%c %u\n",
+ cond == SINGLE ? 'S' : 'B', peri >> 3);
+
+ return SZ_DMASTP;
+}
+
+static inline u32 _emit_STZ(unsigned dry_run, u8 buf[])
+{
+ if (dry_run)
+ return SZ_DMASTZ;
+
+ buf[0] = CMD_DMASTZ;
+
+ PL330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n");
+
+ return SZ_DMASTZ;
+}
+
+static inline u32 _emit_WFE(unsigned dry_run, u8 buf[], u8 ev,
+ unsigned invalidate)
+{
+ if (dry_run)
+ return SZ_DMAWFE;
+
+ buf[0] = CMD_DMAWFE;
+
+ ev &= 0x1f;
+ ev <<= 3;
+ buf[1] = ev;
+
+ if (invalidate)
+ buf[1] |= (1 << 1);
+
+ PL330_DBGCMD_DUMP(SZ_DMAWFE, "\tDMAWFE %u%s\n",
+ ev >> 3, invalidate ? ", I" : "");
+
+ return SZ_DMAWFE;
+}
+
+static inline u32 _emit_WFP(unsigned dry_run, u8 buf[],
+ enum pl330_cond cond, u8 peri)
+{
+ if (dry_run)
+ return SZ_DMAWFP;
+
+ buf[0] = CMD_DMAWFP;
+
+ if (cond == SINGLE)
+ buf[0] |= (0 << 1) | (0 << 0);
+ else if (cond == BURST)
+ buf[0] |= (1 << 1) | (0 << 0);
+ else
+ buf[0] |= (0 << 1) | (1 << 0);
+
+ peri &= 0x1f;
+ peri <<= 3;
+ buf[1] = peri;
+
+ PL330_DBGCMD_DUMP(SZ_DMAWFP, "\tDMAWFP%c %u\n",
+ cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'P'), peri >> 3);
+
+ return SZ_DMAWFP;
+}
+
+static inline u32 _emit_WMB(unsigned dry_run, u8 buf[])
+{
+ if (dry_run)
+ return SZ_DMAWMB;
+
+ buf[0] = CMD_DMAWMB;
+
+ PL330_DBGCMD_DUMP(SZ_DMAWMB, "\tDMAWMB\n");
+
+ return SZ_DMAWMB;
+}
+
+struct _arg_GO {
+ u8 chan;
+ u32 addr;
+ unsigned ns;
+};
+
+static inline u32 _emit_GO(unsigned dry_run, u8 buf[],
+ const struct _arg_GO *arg)
+{
+ u8 chan = arg->chan;
+ u32 addr = arg->addr;
+ unsigned ns = arg->ns;
+
+ if (dry_run)
+ return SZ_DMAGO;
+
+ buf[0] = CMD_DMAGO;
+ buf[0] |= (ns << 1);
+
+ buf[1] = chan & 0x7;
+
+ *((u32 *)&buf[2]) = addr;
+
+ return SZ_DMAGO;
+}
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+/* Returns Time-Out */
+static bool _until_dmac_idle(struct pl330_thread *thrd)
+{
+ void __iomem *regs = thrd->dmac->pinfo->base;
+ unsigned long loops = msecs_to_loops(5);
+
+ do {
+ /* Until Manager is Idle */
+ if (!(readl(regs + DBGSTATUS) & DBG_BUSY))
+ break;
+
+ cpu_relax();
+ } while (--loops);
+
+ if (!loops)
+ return true;
+
+ return false;
+}
+
+static inline void _execute_DBGINSN(struct pl330_thread *thrd,
+ u8 insn[], bool as_manager)
+{
+ void __iomem *regs = thrd->dmac->pinfo->base;
+ u32 val;
+
+ val = (insn[0] << 16) | (insn[1] << 24);
+ if (!as_manager) {
+ val |= (1 << 0);
+ val |= (thrd->id << 8); /* Channel Number */
+ }
+ writel(val, regs + DBGINST0);
+
+ val = *((u32 *)&insn[2]);
+ writel(val, regs + DBGINST1);
+
+ /* If timed out due to halted state-machine */
+ if (_until_dmac_idle(thrd)) {
+ dev_err(thrd->dmac->pinfo->dev, "DMAC halted!\n");
+ return;
+ }
+
+ /* Get going */
+ writel(0, regs + DBGCMD);
+}
+
+/*
+ * Mark a _pl330_req as free.
+ * We do it by writing DMAEND as the first instruction
+ * because no valid request is going to have DMAEND as
+ * its first instruction to execute.
+ */
+static void mark_free(struct pl330_thread *thrd, int idx)
+{
+ struct _pl330_req *req = &thrd->req[idx];
+
+ _emit_END(0, req->mc_cpu);
+ req->mc_len = 0;
+
+ thrd->req_running = -1;
+}
+
+static inline u32 _state(struct pl330_thread *thrd)
+{
+ void __iomem *regs = thrd->dmac->pinfo->base;
+ u32 val;
+
+ if (is_manager(thrd))
+ val = readl(regs + DS) & 0xf;
+ else
+ val = readl(regs + CS(thrd->id)) & 0xf;
+
+ switch (val) {
+ case DS_ST_STOP:
+ return PL330_STATE_STOPPED;
+ case DS_ST_EXEC:
+ return PL330_STATE_EXECUTING;
+ case DS_ST_CMISS:
+ return PL330_STATE_CACHEMISS;
+ case DS_ST_UPDTPC:
+ return PL330_STATE_UPDTPC;
+ case DS_ST_WFE:
+ return PL330_STATE_WFE;
+ case DS_ST_FAULT:
+ return PL330_STATE_FAULTING;
+ case DS_ST_ATBRR:
+ if (is_manager(thrd))
+ return PL330_STATE_INVALID;
+ else
+ return PL330_STATE_ATBARRIER;
+ case DS_ST_QBUSY:
+ if (is_manager(thrd))
+ return PL330_STATE_INVALID;
+ else
+ return PL330_STATE_QUEUEBUSY;
+ case DS_ST_WFP:
+ if (is_manager(thrd))
+ return PL330_STATE_INVALID;
+ else
+ return PL330_STATE_WFP;
+ case DS_ST_KILL:
+ if (is_manager(thrd))
+ return PL330_STATE_INVALID;
+ else
+ return PL330_STATE_KILLING;
+ case DS_ST_CMPLT:
+ if (is_manager(thrd))
+ return PL330_STATE_INVALID;
+ else
+ return PL330_STATE_COMPLETING;
+ case DS_ST_FLTCMP:
+ if (is_manager(thrd))
+ return PL330_STATE_INVALID;
+ else
+ return PL330_STATE_FAULT_COMPLETING;
+ default:
+ return PL330_STATE_INVALID;
+ }
+}
+
+static void _stop(struct pl330_thread *thrd)
+{
+ void __iomem *regs = thrd->dmac->pinfo->base;
+ u8 insn[6] = {0, 0, 0, 0, 0, 0};
+
+ if (_state(thrd) == PL330_STATE_FAULT_COMPLETING)
+ UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
+
+ /* Return if nothing needs to be done */
+ if (_state(thrd) == PL330_STATE_COMPLETING
+ || _state(thrd) == PL330_STATE_KILLING
+ || _state(thrd) == PL330_STATE_STOPPED)
+ return;
+
+ _emit_KILL(0, insn);
+
+ /* Stop generating interrupts for SEV */
+ writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN);
+
+ _execute_DBGINSN(thrd, insn, is_manager(thrd));
+}
+
+/* Start doing req 'idx' of thread 'thrd' */
+static bool _trigger(struct pl330_thread *thrd)
+{
+ void __iomem *regs = thrd->dmac->pinfo->base;
+ struct _pl330_req *req;
+ struct pl330_req *r;
+ struct _arg_GO go;
+ unsigned ns;
+ u8 insn[6] = {0, 0, 0, 0, 0, 0};
+ int idx;
+
+ /* Return if already ACTIVE */
+ if (_state(thrd) != PL330_STATE_STOPPED)
+ return true;
+
+ idx = 1 - thrd->lstenq;
+ if (!IS_FREE(&thrd->req[idx]))
+ req = &thrd->req[idx];
+ else {
+ idx = thrd->lstenq;
+ if (!IS_FREE(&thrd->req[idx]))
+ req = &thrd->req[idx];
+ else
+ req = NULL;
+ }
+
+ /* Return if no request */
+ if (!req || !req->r)
+ return true;
+
+ r = req->r;
+
+ if (r->cfg)
+ ns = r->cfg->nonsecure ? 1 : 0;
+ else if (readl(regs + CS(thrd->id)) & CS_CNS)
+ ns = 1;
+ else
+ ns = 0;
+
+ /* See 'Abort Sources' point-4 at Page 2-25 */
+ if (_manager_ns(thrd) && !ns)
+ dev_info(thrd->dmac->pinfo->dev, "%s:%d Recipe for ABORT!\n",
+ __func__, __LINE__);
+
+ go.chan = thrd->id;
+ go.addr = req->mc_bus;
+ go.ns = ns;
+ _emit_GO(0, insn, &go);
+
+ /* Set to generate interrupts for SEV */
+ writel(readl(regs + INTEN) | (1 << thrd->ev), regs + INTEN);
+
+ /* Only manager can execute GO */
+ _execute_DBGINSN(thrd, insn, true);
+
+ thrd->req_running = idx;
+
+ return true;
+}
+
+static bool _start(struct pl330_thread *thrd)
+{
+ switch (_state(thrd)) {
+ case PL330_STATE_FAULT_COMPLETING:
+ UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
+
+ if (_state(thrd) == PL330_STATE_KILLING)
+ UNTIL(thrd, PL330_STATE_STOPPED)
+
+ case PL330_STATE_FAULTING:
+ _stop(thrd);
+
+ case PL330_STATE_KILLING:
+ case PL330_STATE_COMPLETING:
+ UNTIL(thrd, PL330_STATE_STOPPED)
+
+ case PL330_STATE_STOPPED:
+ return _trigger(thrd);
+
+ case PL330_STATE_WFP:
+ case PL330_STATE_QUEUEBUSY:
+ case PL330_STATE_ATBARRIER:
+ case PL330_STATE_UPDTPC:
+ case PL330_STATE_CACHEMISS:
+ case PL330_STATE_EXECUTING:
+ return true;
+
+ case PL330_STATE_WFE: /* For RESUME, nothing yet */
+ default:
+ return false;
+ }
+}
+
+static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs, int cyc)
+{
+ int off = 0;
+ struct pl330_config *pcfg = pxs->r->cfg->pcfg;
+
+ /* check lock-up free version */
+ if (get_revision(pcfg->periph_id) >= PERIPH_REV_R1P0) {
+ while (cyc--) {
+ off += _emit_LD(dry_run, &buf[off], ALWAYS);
+ off += _emit_ST(dry_run, &buf[off], ALWAYS);
+ }
+ } else {
+ while (cyc--) {
+ off += _emit_LD(dry_run, &buf[off], ALWAYS);
+ off += _emit_RMB(dry_run, &buf[off]);
+ off += _emit_ST(dry_run, &buf[off], ALWAYS);
+ off += _emit_WMB(dry_run, &buf[off]);
+ }
+ }
+
+ return off;
+}
+
+static inline int _ldst_devtomem(unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs, int cyc)
+{
+ int off = 0;
+
+ while (cyc--) {
+ off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+ off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+ off += _emit_ST(dry_run, &buf[off], ALWAYS);
+ off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
+ }
+
+ return off;
+}
+
+static inline int _ldst_memtodev(unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs, int cyc)
+{
+ int off = 0;
+
+ while (cyc--) {
+ off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+ off += _emit_LD(dry_run, &buf[off], ALWAYS);
+ off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->r->peri);
+ off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
+ }
+
+ return off;
+}
+
+static int _bursts(unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs, int cyc)
+{
+ int off = 0;
+
+ switch (pxs->r->rqtype) {
+ case MEMTODEV:
+ off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc);
+ break;
+ case DEVTOMEM:
+ off += _ldst_devtomem(dry_run, &buf[off], pxs, cyc);
+ break;
+ case MEMTOMEM:
+ off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc);
+ break;
+ default:
+ off += 0x40000000; /* Scare off the Client */
+ break;
+ }
+
+ return off;
+}
+
+/* Returns bytes consumed and updates bursts */
+static inline int _loop(unsigned dry_run, u8 buf[],
+ unsigned long *bursts, const struct _xfer_spec *pxs)
+{
+ int cyc, cycmax, szlp, szlpend, szbrst, off;
+ unsigned lcnt0, lcnt1, ljmp0, ljmp1;
+ struct _arg_LPEND lpend;
+
+ /* Max iterations possible in DMALP is 256 */
+ if (*bursts >= 256*256) {
+ lcnt1 = 256;
+ lcnt0 = 256;
+ cyc = *bursts / lcnt1 / lcnt0;
+ } else if (*bursts > 256) {
+ lcnt1 = 256;
+ lcnt0 = *bursts / lcnt1;
+ cyc = 1;
+ } else {
+ lcnt1 = *bursts;
+ lcnt0 = 0;
+ cyc = 1;
+ }
+
+ szlp = _emit_LP(1, buf, 0, 0);
+ szbrst = _bursts(1, buf, pxs, 1);
+
+ lpend.cond = ALWAYS;
+ lpend.forever = false;
+ lpend.loop = 0;
+ lpend.bjump = 0;
+ szlpend = _emit_LPEND(1, buf, &lpend);
+
+ if (lcnt0) {
+ szlp *= 2;
+ szlpend *= 2;
+ }
+
+ /*
+ * Max bursts that we can unroll due to limit on the
+ * size of backward jump that can be encoded in DMALPEND
+ * which is 8-bits and hence 255
+ */
+ cycmax = (255 - (szlp + szlpend)) / szbrst;
+
+ cyc = (cycmax < cyc) ? cycmax : cyc;
+
+ off = 0;
+
+ if (lcnt0) {
+ off += _emit_LP(dry_run, &buf[off], 0, lcnt0);
+ ljmp0 = off;
+ }
+
+ off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
+ ljmp1 = off;
+
+ off += _bursts(dry_run, &buf[off], pxs, cyc);
+
+ lpend.cond = ALWAYS;
+ lpend.forever = false;
+ lpend.loop = 1;
+ lpend.bjump = off - ljmp1;
+ off += _emit_LPEND(dry_run, &buf[off], &lpend);
+
+ if (lcnt0) {
+ lpend.cond = ALWAYS;
+ lpend.forever = false;
+ lpend.loop = 0;
+ lpend.bjump = off - ljmp0;
+ off += _emit_LPEND(dry_run, &buf[off], &lpend);
+ }
+
+ *bursts = lcnt1 * cyc;
+ if (lcnt0)
+ *bursts *= lcnt0;
+
+ return off;
+}
+
+static inline int _setup_loops(unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs)
+{
+ struct pl330_xfer *x = pxs->x;
+ u32 ccr = pxs->ccr;
+ unsigned long c, bursts = BYTE_TO_BURST(x->bytes, ccr);
+ int off = 0;
+
+ while (bursts) {
+ c = bursts;
+ off += _loop(dry_run, &buf[off], &c, pxs);
+ bursts -= c;
+ }
+
+ return off;
+}
+
+static inline int _setup_xfer(unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs)
+{
+ struct pl330_xfer *x = pxs->x;
+ int off = 0;
+
+ /* DMAMOV SAR, x->src_addr */
+ off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr);
+ /* DMAMOV DAR, x->dst_addr */
+ off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
+
+ /* Setup Loop(s) */
+ off += _setup_loops(dry_run, &buf[off], pxs);
+
+ return off;
+}
+
+/*
+ * A req is a sequence of one or more xfer units.
+ * Returns the number of bytes taken to setup the MC for the req.
+ */
+static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
+ unsigned index, struct _xfer_spec *pxs)
+{
+ struct _pl330_req *req = &thrd->req[index];
+ struct pl330_xfer *x;
+ u8 *buf = req->mc_cpu;
+ int off = 0;
+
+ PL330_DBGMC_START(req->mc_bus);
+
+ /* DMAMOV CCR, ccr */
+ off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
+
+ x = pxs->r->x;
+ do {
+ /* Error if xfer length is not aligned at burst size */
+ if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr)))
+ return -EINVAL;
+
+ pxs->x = x;
+ off += _setup_xfer(dry_run, &buf[off], pxs);
+
+ x = x->next;
+ } while (x);
+
+ /* DMASEV peripheral/event */
+ off += _emit_SEV(dry_run, &buf[off], thrd->ev);
+ /* DMAEND */
+ off += _emit_END(dry_run, &buf[off]);
+
+ return off;
+}
+
+static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc)
+{
+ u32 ccr = 0;
+
+ if (rqc->src_inc)
+ ccr |= CC_SRCINC;
+
+ if (rqc->dst_inc)
+ ccr |= CC_DSTINC;
+
+ /* We set same protection levels for Src and DST for now */
+ if (rqc->privileged)
+ ccr |= CC_SRCPRI | CC_DSTPRI;
+ if (rqc->nonsecure)
+ ccr |= CC_SRCNS | CC_DSTNS;
+ if (rqc->insnaccess)
+ ccr |= CC_SRCIA | CC_DSTIA;
+
+ ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT);
+ ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT);
+
+ ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT);
+ ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT);
+
+ ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT);
+ ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT);
+
+ ccr |= (rqc->swap << CC_SWAP_SHFT);
+
+ return ccr;
+}
+
+static inline bool _is_valid(u32 ccr)
+{
+ enum pl330_dstcachectrl dcctl;
+ enum pl330_srccachectrl scctl;
+
+ dcctl = (ccr >> CC_DSTCCTRL_SHFT) & CC_DRCCCTRL_MASK;
+ scctl = (ccr >> CC_SRCCCTRL_SHFT) & CC_SRCCCTRL_MASK;
+
+ if (dcctl == DINVALID1 || dcctl == DINVALID2
+ || scctl == SINVALID1 || scctl == SINVALID2)
+ return false;
+ else
+ return true;
+}
+
+/*
+ * Submit a list of xfers after which the client wants notification.
+ * Client is not notified after each xfer unit, just once after all
+ * xfer units are done or some error occurs.
+ */
+static int pl330_submit_req(void *ch_id, struct pl330_req *r)
+{
+ struct pl330_thread *thrd = ch_id;
+ struct pl330_dmac *pl330;
+ struct pl330_info *pi;
+ struct _xfer_spec xs;
+ unsigned long flags;
+ void __iomem *regs;
+ unsigned idx;
+ u32 ccr;
+ int ret = 0;
+
+ /* No Req or Unacquired Channel or DMAC */
+ if (!r || !thrd || thrd->free)
+ return -EINVAL;
+
+ pl330 = thrd->dmac;
+ pi = pl330->pinfo;
+ regs = pi->base;
+
+ if (pl330->state == DYING
+ || pl330->dmac_tbd.reset_chan & (1 << thrd->id)) {
+ dev_info(thrd->dmac->pinfo->dev, "%s:%d\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ /* If request for non-existing peripheral */
+ if (r->rqtype != MEMTOMEM && r->peri >= pi->pcfg.num_peri) {
+ dev_info(thrd->dmac->pinfo->dev,
+ "%s:%d Invalid peripheral(%u)!\n",
+ __func__, __LINE__, r->peri);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&pl330->lock, flags);
+
+ if (_queue_full(thrd)) {
+ ret = -EAGAIN;
+ goto xfer_exit;
+ }
+
+ /* Prefer Secure Channel */
+ if (!_manager_ns(thrd))
+ r->cfg->nonsecure = 0;
+ else
+ r->cfg->nonsecure = 1;
+
+ /* Use last settings, if not provided */
+ if (r->cfg)
+ ccr = _prepare_ccr(r->cfg);
+ else
+ ccr = readl(regs + CC(thrd->id));
+
+ /* If this req doesn't have valid xfer settings */
+ if (!_is_valid(ccr)) {
+ ret = -EINVAL;
+ dev_info(thrd->dmac->pinfo->dev, "%s:%d Invalid CCR(%x)!\n",
+ __func__, __LINE__, ccr);
+ goto xfer_exit;
+ }
+
+ idx = IS_FREE(&thrd->req[0]) ? 0 : 1;
+
+ xs.ccr = ccr;
+ xs.r = r;
+
+ /* First dry run to check if req is acceptable */
+ ret = _setup_req(1, thrd, idx, &xs);
+ if (ret < 0)
+ goto xfer_exit;
+
+ if (ret > pi->mcbufsz / 2) {
+ dev_info(thrd->dmac->pinfo->dev,
+ "%s:%d Trying increasing mcbufsz\n",
+ __func__, __LINE__);
+ ret = -ENOMEM;
+ goto xfer_exit;
+ }
+
+ /* Hook the request */
+ thrd->lstenq = idx;
+ thrd->req[idx].mc_len = _setup_req(0, thrd, idx, &xs);
+ thrd->req[idx].r = r;
+
+ ret = 0;
+
+xfer_exit:
+ spin_unlock_irqrestore(&pl330->lock, flags);
+
+ return ret;
+}
+
+static void pl330_dotask(unsigned long data)
+{
+ struct pl330_dmac *pl330 = (struct pl330_dmac *) data;
+ struct pl330_info *pi = pl330->pinfo;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&pl330->lock, flags);
+
+ /* The DMAC itself gone nuts */
+ if (pl330->dmac_tbd.reset_dmac) {
+ pl330->state = DYING;
+ /* Reset the manager too */
+ pl330->dmac_tbd.reset_mngr = true;
+ /* Clear the reset flag */
+ pl330->dmac_tbd.reset_dmac = false;
+ }
+
+ if (pl330->dmac_tbd.reset_mngr) {
+ _stop(pl330->manager);
+ /* Reset all channels */
+ pl330->dmac_tbd.reset_chan = (1 << pi->pcfg.num_chan) - 1;
+ /* Clear the reset flag */
+ pl330->dmac_tbd.reset_mngr = false;
+ }
+
+ for (i = 0; i < pi->pcfg.num_chan; i++) {
+
+ if (pl330->dmac_tbd.reset_chan & (1 << i)) {
+ struct pl330_thread *thrd = &pl330->channels[i];
+ void __iomem *regs = pi->base;
+ enum pl330_op_err err;
+
+ _stop(thrd);
+
+ if (readl(regs + FSC) & (1 << thrd->id))
+ err = PL330_ERR_FAIL;
+ else
+ err = PL330_ERR_ABORT;
+
+ spin_unlock_irqrestore(&pl330->lock, flags);
+
+ _callback(thrd->req[1 - thrd->lstenq].r, err);
+ _callback(thrd->req[thrd->lstenq].r, err);
+
+ spin_lock_irqsave(&pl330->lock, flags);
+
+ thrd->req[0].r = NULL;
+ thrd->req[1].r = NULL;
+ mark_free(thrd, 0);
+ mark_free(thrd, 1);
+
+ /* Clear the reset flag */
+ pl330->dmac_tbd.reset_chan &= ~(1 << i);
+ }
+ }
+
+ spin_unlock_irqrestore(&pl330->lock, flags);
+
+ return;
+}
+
+/* Returns 1 if state was updated, 0 otherwise */
+static int pl330_update(const struct pl330_info *pi)
+{
+ struct _pl330_req *rqdone;
+ struct pl330_dmac *pl330;
+ unsigned long flags;
+ void __iomem *regs;
+ u32 val;
+ int id, ev, ret = 0;
+
+ if (!pi || !pi->pl330_data)
+ return 0;
+
+ regs = pi->base;
+ pl330 = pi->pl330_data;
+
+ spin_lock_irqsave(&pl330->lock, flags);
+
+ val = readl(regs + FSM) & 0x1;
+ if (val)
+ pl330->dmac_tbd.reset_mngr = true;
+ else
+ pl330->dmac_tbd.reset_mngr = false;
+
+ val = readl(regs + FSC) & ((1 << pi->pcfg.num_chan) - 1);
+ pl330->dmac_tbd.reset_chan |= val;
+ if (val) {
+ int i = 0;
+ while (i < pi->pcfg.num_chan) {
+ if (val & (1 << i)) {
+ dev_info(pi->dev,
+ "Reset Channel-%d\t CS-%x FTC-%x\n",
+ i, readl(regs + CS(i)),
+ readl(regs + FTC(i)));
+ _stop(&pl330->channels[i]);
+ }
+ i++;
+ }
+ }
+
+ /* Check which event happened i.e, thread notified */
+ val = readl(regs + ES);
+ if (pi->pcfg.num_events < 32
+ && val & ~((1 << pi->pcfg.num_events) - 1)) {
+ pl330->dmac_tbd.reset_dmac = true;
+ dev_err(pi->dev, "%s:%d Unexpected!\n", __func__, __LINE__);
+ ret = 1;
+ goto updt_exit;
+ }
+
+ for (ev = 0; ev < pi->pcfg.num_events; ev++) {
+ if (val & (1 << ev)) { /* Event occurred */
+ struct pl330_thread *thrd;
+ u32 inten = readl(regs + INTEN);
+ int active;
+
+ /* Clear the event */
+ if (inten & (1 << ev))
+ writel(1 << ev, regs + INTCLR);
+
+ ret = 1;
+
+ id = pl330->events[ev];
+
+ thrd = &pl330->channels[id];
+
+ active = thrd->req_running;
+ if (active == -1) /* Aborted */
+ continue;
+
+ rqdone = &thrd->req[active];
+ mark_free(thrd, active);
+
+ /* Get going again ASAP */
+ _start(thrd);
+
+ /* For now, just make a list of callbacks to be done */
+ list_add_tail(&rqdone->rqd, &pl330->req_done);
+ }
+ }
+
+ /* Now that we are in no hurry, do the callbacks */
+ while (!list_empty(&pl330->req_done)) {
+ struct pl330_req *r;
+
+ rqdone = container_of(pl330->req_done.next,
+ struct _pl330_req, rqd);
+
+ list_del_init(&rqdone->rqd);
+
+ /* Detach the req */
+ r = rqdone->r;
+ rqdone->r = NULL;
+
+ spin_unlock_irqrestore(&pl330->lock, flags);
+ _callback(r, PL330_ERR_NONE);
+ spin_lock_irqsave(&pl330->lock, flags);
+ }
+
+updt_exit:
+ spin_unlock_irqrestore(&pl330->lock, flags);
+
+ if (pl330->dmac_tbd.reset_dmac
+ || pl330->dmac_tbd.reset_mngr
+ || pl330->dmac_tbd.reset_chan) {
+ ret = 1;
+ tasklet_schedule(&pl330->tasks);
+ }
+
+ return ret;
+}
+
+static int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
+{
+ struct pl330_thread *thrd = ch_id;
+ struct pl330_dmac *pl330;
+ unsigned long flags;
+ int ret = 0, active;
+
+ if (!thrd || thrd->free || thrd->dmac->state == DYING)
+ return -EINVAL;
+
+ pl330 = thrd->dmac;
+ active = thrd->req_running;
+
+ spin_lock_irqsave(&pl330->lock, flags);
+
+ switch (op) {
+ case PL330_OP_FLUSH:
+ /* Make sure the channel is stopped */
+ _stop(thrd);
+
+ thrd->req[0].r = NULL;
+ thrd->req[1].r = NULL;
+ mark_free(thrd, 0);
+ mark_free(thrd, 1);
+ break;
+
+ case PL330_OP_ABORT:
+ /* Make sure the channel is stopped */
+ _stop(thrd);
+
+ /* ABORT is only for the active req */
+ if (active == -1)
+ break;
+
+ thrd->req[active].r = NULL;
+ mark_free(thrd, active);
+
+ /* Start the next */
+ case PL330_OP_START:
+ if ((active == -1) && !_start(thrd))
+ ret = -EIO;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&pl330->lock, flags);
+ return ret;
+}
+
+/* Reserve an event */
+static inline int _alloc_event(struct pl330_thread *thrd)
+{
+ struct pl330_dmac *pl330 = thrd->dmac;
+ struct pl330_info *pi = pl330->pinfo;
+ int ev;
+
+ for (ev = 0; ev < pi->pcfg.num_events; ev++)
+ if (pl330->events[ev] == -1) {
+ pl330->events[ev] = thrd->id;
+ return ev;
+ }
+
+ return -1;
+}
+
+static bool _chan_ns(const struct pl330_info *pi, int i)
+{
+ return pi->pcfg.irq_ns & (1 << i);
+}
+
+/* Upon success, returns IdentityToken for the
+ * allocated channel, NULL otherwise.
+ */
+static void *pl330_request_channel(const struct pl330_info *pi)
+{
+ struct pl330_thread *thrd = NULL;
+ struct pl330_dmac *pl330;
+ unsigned long flags;
+ int chans, i;
+
+ if (!pi || !pi->pl330_data)
+ return NULL;
+
+ pl330 = pi->pl330_data;
+
+ if (pl330->state == DYING)
+ return NULL;
+
+ chans = pi->pcfg.num_chan;
+
+ spin_lock_irqsave(&pl330->lock, flags);
+
+ for (i = 0; i < chans; i++) {
+ thrd = &pl330->channels[i];
+ if ((thrd->free) && (!_manager_ns(thrd) ||
+ _chan_ns(pi, i))) {
+ thrd->ev = _alloc_event(thrd);
+ if (thrd->ev >= 0) {
+ thrd->free = false;
+ thrd->lstenq = 1;
+ thrd->req[0].r = NULL;
+ mark_free(thrd, 0);
+ thrd->req[1].r = NULL;
+ mark_free(thrd, 1);
+ break;
+ }
+ }
+ thrd = NULL;
+ }
+
+ spin_unlock_irqrestore(&pl330->lock, flags);
+
+ return thrd;
+}
+
+/* Release an event */
+static inline void _free_event(struct pl330_thread *thrd, int ev)
+{
+ struct pl330_dmac *pl330 = thrd->dmac;
+ struct pl330_info *pi = pl330->pinfo;
+
+ /* If the event is valid and was held by the thread */
+ if (ev >= 0 && ev < pi->pcfg.num_events
+ && pl330->events[ev] == thrd->id)
+ pl330->events[ev] = -1;
+}
+
+static void pl330_release_channel(void *ch_id)
+{
+ struct pl330_thread *thrd = ch_id;
+ struct pl330_dmac *pl330;
+ unsigned long flags;
+
+ if (!thrd || thrd->free)
+ return;
+
+ _stop(thrd);
+
+ _callback(thrd->req[1 - thrd->lstenq].r, PL330_ERR_ABORT);
+ _callback(thrd->req[thrd->lstenq].r, PL330_ERR_ABORT);
+
+ pl330 = thrd->dmac;
+
+ spin_lock_irqsave(&pl330->lock, flags);
+ _free_event(thrd, thrd->ev);
+ thrd->free = true;
+ spin_unlock_irqrestore(&pl330->lock, flags);
+}
+
+/* Initialize the structure for PL330 configuration, that can be used
+ * by the client driver the make best use of the DMAC
+ */
+static void read_dmac_config(struct pl330_info *pi)
+{
+ void __iomem *regs = pi->base;
+ u32 val;
+
+ val = readl(regs + CRD) >> CRD_DATA_WIDTH_SHIFT;
+ val &= CRD_DATA_WIDTH_MASK;
+ pi->pcfg.data_bus_width = 8 * (1 << val);
+
+ val = readl(regs + CRD) >> CRD_DATA_BUFF_SHIFT;
+ val &= CRD_DATA_BUFF_MASK;
+ pi->pcfg.data_buf_dep = val + 1;
+
+ val = readl(regs + CR0) >> CR0_NUM_CHANS_SHIFT;
+ val &= CR0_NUM_CHANS_MASK;
+ val += 1;
+ pi->pcfg.num_chan = val;
+
+ val = readl(regs + CR0);
+ if (val & CR0_PERIPH_REQ_SET) {
+ val = (val >> CR0_NUM_PERIPH_SHIFT) & CR0_NUM_PERIPH_MASK;
+ val += 1;
+ pi->pcfg.num_peri = val;
+ pi->pcfg.peri_ns = readl(regs + CR4);
+ } else {
+ pi->pcfg.num_peri = 0;
+ }
+
+ val = readl(regs + CR0);
+ if (val & CR0_BOOT_MAN_NS)
+ pi->pcfg.mode |= DMAC_MODE_NS;
+ else
+ pi->pcfg.mode &= ~DMAC_MODE_NS;
+
+ val = readl(regs + CR0) >> CR0_NUM_EVENTS_SHIFT;
+ val &= CR0_NUM_EVENTS_MASK;
+ val += 1;
+ pi->pcfg.num_events = val;
+
+ pi->pcfg.irq_ns = readl(regs + CR3);
+
+ pi->pcfg.periph_id = get_id(pi, PERIPH_ID);
+ pi->pcfg.pcell_id = get_id(pi, PCELL_ID);
+}
+
+static inline void _reset_thread(struct pl330_thread *thrd)
+{
+ struct pl330_dmac *pl330 = thrd->dmac;
+ struct pl330_info *pi = pl330->pinfo;
+
+ thrd->req[0].mc_cpu = pl330->mcode_cpu
+ + (thrd->id * pi->mcbufsz);
+ thrd->req[0].mc_bus = pl330->mcode_bus
+ + (thrd->id * pi->mcbufsz);
+ thrd->req[0].r = NULL;
+ mark_free(thrd, 0);
+
+ thrd->req[1].mc_cpu = thrd->req[0].mc_cpu
+ + pi->mcbufsz / 2;
+ thrd->req[1].mc_bus = thrd->req[0].mc_bus
+ + pi->mcbufsz / 2;
+ thrd->req[1].r = NULL;
+ mark_free(thrd, 1);
+}
+
+static int dmac_alloc_threads(struct pl330_dmac *pl330)
+{
+ struct pl330_info *pi = pl330->pinfo;
+ int chans = pi->pcfg.num_chan;
+ struct pl330_thread *thrd;
+ int i;
+
+ /* Allocate 1 Manager and 'chans' Channel threads */
+ pl330->channels = kzalloc((1 + chans) * sizeof(*thrd),
+ GFP_KERNEL);
+ if (!pl330->channels)
+ return -ENOMEM;
+
+ /* Init Channel threads */
+ for (i = 0; i < chans; i++) {
+ thrd = &pl330->channels[i];
+ thrd->id = i;
+ thrd->dmac = pl330;
+ _reset_thread(thrd);
+ thrd->free = true;
+ }
+
+ /* MANAGER is indexed at the end */
+ thrd = &pl330->channels[chans];
+ thrd->id = chans;
+ thrd->dmac = pl330;
+ thrd->free = false;
+ pl330->manager = thrd;
+
+ return 0;
+}
+
+static int dmac_alloc_resources(struct pl330_dmac *pl330)
+{
+ struct pl330_info *pi = pl330->pinfo;
+ int chans = pi->pcfg.num_chan;
+ int ret;
+
+ /*
+ * Alloc MicroCode buffer for 'chans' Channel threads.
+ * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN)
+ */
+ pl330->mcode_cpu = dma_alloc_coherent(pi->dev,
+ chans * pi->mcbufsz,
+ &pl330->mcode_bus, GFP_KERNEL);
+ if (!pl330->mcode_cpu) {
+ dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ ret = dmac_alloc_threads(pl330);
+ if (ret) {
+ dev_err(pi->dev, "%s:%d Can't to create channels for DMAC!\n",
+ __func__, __LINE__);
+ dma_free_coherent(pi->dev,
+ chans * pi->mcbufsz,
+ pl330->mcode_cpu, pl330->mcode_bus);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pl330_add(struct pl330_info *pi)
+{
+ struct pl330_dmac *pl330;
+ void __iomem *regs;
+ int i, ret;
+
+ if (!pi || !pi->dev)
+ return -EINVAL;
+
+ /* If already added */
+ if (pi->pl330_data)
+ return -EINVAL;
+
+ /*
+ * If the SoC can perform reset on the DMAC, then do it
+ * before reading its configuration.
+ */
+ if (pi->dmac_reset)
+ pi->dmac_reset(pi);
+
+ regs = pi->base;
+
+ /* Check if we can handle this DMAC */
+ if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL
+ || get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
+ dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
+ get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
+ return -EINVAL;
+ }
+
+ /* Read the configuration of the DMAC */
+ read_dmac_config(pi);
+
+ if (pi->pcfg.num_events == 0) {
+ dev_err(pi->dev, "%s:%d Can't work without events!\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ pl330 = kzalloc(sizeof(*pl330), GFP_KERNEL);
+ if (!pl330) {
+ dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ /* Assign the info structure and private data */
+ pl330->pinfo = pi;
+ pi->pl330_data = pl330;
+
+ spin_lock_init(&pl330->lock);
+
+ INIT_LIST_HEAD(&pl330->req_done);
+
+ /* Use default MC buffer size if not provided */
+ if (!pi->mcbufsz)
+ pi->mcbufsz = MCODE_BUFF_PER_REQ * 2;
+
+ /* Mark all events as free */
+ for (i = 0; i < pi->pcfg.num_events; i++)
+ pl330->events[i] = -1;
+
+ /* Allocate resources needed by the DMAC */
+ ret = dmac_alloc_resources(pl330);
+ if (ret) {
+ dev_err(pi->dev, "Unable to create channels for DMAC\n");
+ kfree(pl330);
+ return ret;
+ }
+
+ tasklet_init(&pl330->tasks, pl330_dotask, (unsigned long) pl330);
+
+ pl330->state = INIT;
+
+ return 0;
+}
+
+static int dmac_free_threads(struct pl330_dmac *pl330)
+{
+ struct pl330_info *pi = pl330->pinfo;
+ int chans = pi->pcfg.num_chan;
+ struct pl330_thread *thrd;
+ int i;
+
+ /* Release Channel threads */
+ for (i = 0; i < chans; i++) {
+ thrd = &pl330->channels[i];
+ pl330_release_channel((void *)thrd);
+ }
+
+ /* Free memory */
+ kfree(pl330->channels);
+
+ return 0;
+}
+
+static void dmac_free_resources(struct pl330_dmac *pl330)
+{
+ struct pl330_info *pi = pl330->pinfo;
+ int chans = pi->pcfg.num_chan;
+
+ dmac_free_threads(pl330);
+
+ dma_free_coherent(pi->dev, chans * pi->mcbufsz,
+ pl330->mcode_cpu, pl330->mcode_bus);
+}
+
+static void pl330_del(struct pl330_info *pi)
+{
+ struct pl330_dmac *pl330;
+
+ if (!pi || !pi->pl330_data)
+ return;
+
+ pl330 = pi->pl330_data;
+
+ pl330->state = UNINIT;
+
+ tasklet_kill(&pl330->tasks);
+
+ /* Free DMAC resources */
+ dmac_free_resources(pl330);
+
+ kfree(pl330);
+ pi->pl330_data = NULL;
+}
+
/* forward declaration */
static struct amba_driver pl330_driver;
@@ -234,7 +2320,7 @@ static void pl330_tasklet(unsigned long data)
/* Pick up ripe tomatoes */
list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
if (desc->status == DONE) {
- pch->completed = desc->txd.cookie;
+ dma_cookie_complete(&desc->txd);
list_move_tail(&desc->node, &list);
}
@@ -305,7 +2391,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
spin_lock_irqsave(&pch->lock, flags);
- pch->completed = chan->cookie = 1;
+ dma_cookie_init(chan);
pch->cyclic = false;
pch->pl330_chid = pl330_request_channel(&pdmac->pif);
@@ -340,7 +2426,6 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
/* Mark all desc done */
list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
desc->status = DONE;
- pch->completed = desc->txd.cookie;
list_move_tail(&desc->node, &list);
}
@@ -396,18 +2481,7 @@ static enum dma_status
pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
- struct dma_pl330_chan *pch = to_pchan(chan);
- dma_cookie_t last_done, last_used;
- int ret;
-
- last_done = pch->completed;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_done, last_used);
-
- dma_set_tx_state(txstate, last_done, last_used, 0);
-
- return ret;
+ return dma_cookie_status(chan, cookie, txstate);
}
static void pl330_issue_pending(struct dma_chan *chan)
@@ -430,26 +2504,16 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
spin_lock_irqsave(&pch->lock, flags);
/* Assign cookies to all nodes */
- cookie = tx->chan->cookie;
-
while (!list_empty(&last->node)) {
desc = list_entry(last->node.next, struct dma_pl330_desc, node);
- if (++cookie < 0)
- cookie = 1;
- desc->txd.cookie = cookie;
+ dma_cookie_assign(&desc->txd);
list_move_tail(&desc->node, &pch->work_list);
}
- if (++cookie < 0)
- cookie = 1;
- last->txd.cookie = cookie;
-
+ cookie = dma_cookie_assign(&last->txd);
list_add_tail(&last->node, &pch->work_list);
-
- tx->chan->cookie = cookie;
-
spin_unlock_irqrestore(&pch->lock, flags);
return cookie;
@@ -553,6 +2617,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
async_tx_ack(&desc->txd);
desc->req.peri = peri_id ? pch->chan.chan_id : 0;
+ desc->rqcfg.pcfg = &pch->dmac->pif.pcfg;
dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
@@ -621,7 +2686,8 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
- size_t period_len, enum dma_transfer_direction direction)
+ size_t period_len, enum dma_transfer_direction direction,
+ void *context)
{
struct dma_pl330_desc *desc;
struct dma_pl330_chan *pch = to_pchan(chan);
@@ -711,7 +2777,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
static struct dma_async_tx_descriptor *
pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flg)
+ unsigned long flg, void *context)
{
struct dma_pl330_desc *first, *desc = NULL;
struct dma_pl330_chan *pch = to_pchan(chan);
@@ -829,7 +2895,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
if (IS_ERR(pdmac->clk)) {
dev_err(&adev->dev, "Cannot get operation clock.\n");
ret = -EINVAL;
- goto probe_err1;
+ goto probe_err2;
}
amba_set_drvdata(adev, pdmac);
@@ -843,11 +2909,11 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
ret = request_irq(irq, pl330_irq_handler, 0,
dev_name(&adev->dev), pi);
if (ret)
- goto probe_err2;
+ goto probe_err3;
ret = pl330_add(pi);
if (ret)
- goto probe_err3;
+ goto probe_err4;
INIT_LIST_HEAD(&pdmac->desc_pool);
spin_lock_init(&pdmac->pool_lock);
@@ -904,7 +2970,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
ret = dma_async_device_register(pd);
if (ret) {
dev_err(&adev->dev, "unable to register DMAC\n");
- goto probe_err4;
+ goto probe_err5;
}
dev_info(&adev->dev,
@@ -917,10 +2983,15 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
-probe_err4:
+probe_err5:
pl330_del(pi);
-probe_err3:
+probe_err4:
free_irq(irq, pi);
+probe_err3:
+#ifndef CONFIG_PM_RUNTIME
+ clk_disable(pdmac->clk);
+#endif
+ clk_put(pdmac->clk);
probe_err2:
iounmap(pi->base);
probe_err1:
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index fc457a7e8832..ced98826684a 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -46,6 +46,7 @@
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
#include "adma.h"
+#include "../dmaengine.h"
enum ppc_adma_init_code {
PPC_ADMA_INIT_OK = 0,
@@ -1930,7 +1931,7 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
if (end_of_chain && slot_cnt) {
/* Should wait for ZeroSum completion */
if (cookie > 0)
- chan->completed_cookie = cookie;
+ chan->common.completed_cookie = cookie;
return;
}
@@ -1960,7 +1961,7 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
BUG_ON(!seen_current);
if (cookie > 0) {
- chan->completed_cookie = cookie;
+ chan->common.completed_cookie = cookie;
pr_debug("\tcompleted cookie %d\n", cookie);
}
@@ -2150,22 +2151,6 @@ static int ppc440spe_adma_alloc_chan_resources(struct dma_chan *chan)
}
/**
- * ppc440spe_desc_assign_cookie - assign a cookie
- */
-static dma_cookie_t ppc440spe_desc_assign_cookie(
- struct ppc440spe_adma_chan *chan,
- struct ppc440spe_adma_desc_slot *desc)
-{
- dma_cookie_t cookie = chan->common.cookie;
-
- cookie++;
- if (cookie < 0)
- cookie = 1;
- chan->common.cookie = desc->async_tx.cookie = cookie;
- return cookie;
-}
-
-/**
* ppc440spe_rxor_set_region_data -
*/
static void ppc440spe_rxor_set_region(struct ppc440spe_adma_desc_slot *desc,
@@ -2235,8 +2220,7 @@ static dma_cookie_t ppc440spe_adma_tx_submit(struct dma_async_tx_descriptor *tx)
slots_per_op = group_start->slots_per_op;
spin_lock_bh(&chan->lock);
-
- cookie = ppc440spe_desc_assign_cookie(chan, sw_desc);
+ cookie = dma_cookie_assign(tx);
if (unlikely(list_empty(&chan->chain))) {
/* first peer */
@@ -3944,28 +3928,16 @@ static enum dma_status ppc440spe_adma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *txstate)
{
struct ppc440spe_adma_chan *ppc440spe_chan;
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
enum dma_status ret;
ppc440spe_chan = to_ppc440spe_adma_chan(chan);
- last_used = chan->cookie;
- last_complete = ppc440spe_chan->completed_cookie;
-
- dma_set_tx_state(txstate, last_complete, last_used, 0);
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_SUCCESS)
return ret;
ppc440spe_adma_slot_cleanup(ppc440spe_chan);
- last_used = chan->cookie;
- last_complete = ppc440spe_chan->completed_cookie;
-
- dma_set_tx_state(txstate, last_complete, last_used, 0);
-
- return dma_async_is_complete(cookie, last_complete, last_used);
+ return dma_cookie_status(chan, cookie, txstate);
}
/**
@@ -4050,16 +4022,12 @@ static void ppc440spe_chan_start_null_xor(struct ppc440spe_adma_chan *chan)
async_tx_ack(&sw_desc->async_tx);
ppc440spe_desc_init_null_xor(group_start);
- cookie = chan->common.cookie;
- cookie++;
- if (cookie <= 1)
- cookie = 2;
+ cookie = dma_cookie_assign(&sw_desc->async_tx);
/* initialize the completed cookie to be less than
* the most recently used cookie
*/
- chan->completed_cookie = cookie - 1;
- chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+ chan->common.completed_cookie = cookie - 1;
/* channel should not be busy */
BUG_ON(ppc440spe_chan_is_busy(chan));
@@ -4529,6 +4497,7 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev)
INIT_LIST_HEAD(&chan->all_slots);
chan->device = adev;
chan->common.device = &adev->common;
+ dma_cookie_init(&chan->common);
list_add_tail(&chan->common.device_node, &adev->common.channels);
tasklet_init(&chan->irq_tasklet, ppc440spe_adma_tasklet,
(unsigned long)chan);
diff --git a/drivers/dma/ppc4xx/adma.h b/drivers/dma/ppc4xx/adma.h
index 8ada5a812e3b..26b7a5ed9ac7 100644
--- a/drivers/dma/ppc4xx/adma.h
+++ b/drivers/dma/ppc4xx/adma.h
@@ -81,7 +81,6 @@ struct ppc440spe_adma_device {
* @common: common dmaengine channel object members
* @all_slots: complete domain of slots usable by the channel
* @pending: allows batching of hardware operations
- * @completed_cookie: identifier for the most recently completed operation
* @slots_allocated: records the actual size of the descriptor slot pool
* @hw_chain_inited: h/w descriptor chain initialization flag
* @irq_tasklet: bottom half where ppc440spe_adma_slot_cleanup runs
@@ -99,7 +98,6 @@ struct ppc440spe_adma_chan {
struct list_head all_slots;
struct ppc440spe_adma_desc_slot *last_used;
int pending;
- dma_cookie_t completed_cookie;
int slots_allocated;
int hw_chain_inited;
struct tasklet_struct irq_tasklet;
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index 812fd76e9c18..19d7a8d3975d 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -30,6 +30,8 @@
#include <linux/kdebug.h>
#include <linux/spinlock.h>
#include <linux/rculist.h>
+
+#include "dmaengine.h"
#include "shdma.h"
/* DMA descriptor control */
@@ -296,13 +298,7 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
else
power_up = false;
- cookie = sh_chan->common.cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
-
- sh_chan->common.cookie = cookie;
- tx->cookie = cookie;
+ cookie = dma_cookie_assign(tx);
/* Mark all chunks of this descriptor as submitted, move to the queue */
list_for_each_entry_safe(chunk, c, desc->node.prev, node) {
@@ -673,7 +669,8 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
- enum dma_transfer_direction direction, unsigned long flags)
+ enum dma_transfer_direction direction, unsigned long flags,
+ void *context)
{
struct sh_dmae_slave *param;
struct sh_dmae_chan *sh_chan;
@@ -764,12 +761,12 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
cookie = tx->cookie;
if (desc->mark == DESC_COMPLETED && desc->chunks == 1) {
- if (sh_chan->completed_cookie != desc->cookie - 1)
+ if (sh_chan->common.completed_cookie != desc->cookie - 1)
dev_dbg(sh_chan->dev,
"Completing cookie %d, expected %d\n",
desc->cookie,
- sh_chan->completed_cookie + 1);
- sh_chan->completed_cookie = desc->cookie;
+ sh_chan->common.completed_cookie + 1);
+ sh_chan->common.completed_cookie = desc->cookie;
}
/* Call callback on the last chunk */
@@ -823,7 +820,7 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
* Terminating and the loop completed normally: forgive
* uncompleted cookies
*/
- sh_chan->completed_cookie = sh_chan->common.cookie;
+ sh_chan->common.completed_cookie = sh_chan->common.cookie;
spin_unlock_irqrestore(&sh_chan->desc_lock, flags);
@@ -883,23 +880,14 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
enum dma_status status;
unsigned long flags;
sh_dmae_chan_ld_cleanup(sh_chan, false);
- /* First read completed cookie to avoid a skew */
- last_complete = sh_chan->completed_cookie;
- rmb();
- last_used = chan->cookie;
- BUG_ON(last_complete < 0);
- dma_set_tx_state(txstate, last_complete, last_used, 0);
-
spin_lock_irqsave(&sh_chan->desc_lock, flags);
- status = dma_async_is_complete(cookie, last_complete, last_used);
+ status = dma_cookie_status(chan, cookie, txstate);
/*
* If we don't find cookie on the queue, it has been aborted and we have
@@ -1102,6 +1090,7 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
/* reference struct dma_device */
new_sh_chan->common.device = &shdev->common;
+ dma_cookie_init(&new_sh_chan->common);
new_sh_chan->dev = shdev->common.dev;
new_sh_chan->id = id;
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 2b55a276dc5b..0b1d2c105f02 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -30,7 +30,6 @@ enum dmae_pm_state {
};
struct sh_dmae_chan {
- dma_cookie_t completed_cookie; /* The maximum cookie completed */
spinlock_t desc_lock; /* Descriptor operation lock */
struct list_head ld_queue; /* Link descriptors queue */
struct list_head ld_free; /* Link descriptors free */
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 2333810d1688..434ad31174f2 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -18,6 +18,8 @@
#include <linux/of_platform.h>
#include <linux/sirfsoc_dma.h>
+#include "dmaengine.h"
+
#define SIRFSOC_DMA_DESCRIPTORS 16
#define SIRFSOC_DMA_CHANNELS 16
@@ -59,7 +61,6 @@ struct sirfsoc_dma_chan {
struct list_head queued;
struct list_head active;
struct list_head completed;
- dma_cookie_t completed_cookie;
unsigned long happened_cyclic;
unsigned long completed_cyclic;
@@ -208,7 +209,7 @@ static void sirfsoc_dma_process_completed(struct sirfsoc_dma *sdma)
/* Free descriptors */
spin_lock_irqsave(&schan->lock, flags);
list_splice_tail_init(&list, &schan->free);
- schan->completed_cookie = last_cookie;
+ schan->chan.completed_cookie = last_cookie;
spin_unlock_irqrestore(&schan->lock, flags);
} else {
/* for cyclic channel, desc is always in active list */
@@ -258,13 +259,7 @@ static dma_cookie_t sirfsoc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
/* Move descriptor to queue */
list_move_tail(&sdesc->node, &schan->queued);
- /* Update cookie */
- cookie = schan->chan.cookie + 1;
- if (cookie <= 0)
- cookie = 1;
-
- schan->chan.cookie = cookie;
- sdesc->desc.cookie = cookie;
+ cookie = dma_cookie_assign(txd);
spin_unlock_irqrestore(&schan->lock, flags);
@@ -414,16 +409,13 @@ sirfsoc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
{
struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
unsigned long flags;
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
+ enum dma_status ret;
spin_lock_irqsave(&schan->lock, flags);
- last_used = schan->chan.cookie;
- last_complete = schan->completed_cookie;
+ ret = dma_cookie_status(chan, cookie, txstate);
spin_unlock_irqrestore(&schan->lock, flags);
- dma_set_tx_state(txstate, last_complete, last_used, 0);
- return dma_async_is_complete(cookie, last_complete, last_used);
+ return ret;
}
static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved(
@@ -497,7 +489,7 @@ err_dir:
static struct dma_async_tx_descriptor *
sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,
size_t buf_len, size_t period_len,
- enum dma_transfer_direction direction)
+ enum dma_transfer_direction direction, void *context)
{
struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
struct sirfsoc_dma_desc *sdesc = NULL;
@@ -635,8 +627,7 @@ static int __devinit sirfsoc_dma_probe(struct platform_device *op)
schan = &sdma->channels[i];
schan->chan.device = dma;
- schan->chan.cookie = 1;
- schan->completed_cookie = schan->chan.cookie;
+ dma_cookie_init(&schan->chan);
INIT_LIST_HEAD(&schan->free);
INIT_LIST_HEAD(&schan->prepared);
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index cc5ecbc067a3..bdd41d4bfa8d 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -21,6 +21,7 @@
#include <plat/ste_dma40.h>
+#include "dmaengine.h"
#include "ste_dma40_ll.h"
#define D40_NAME "dma40"
@@ -220,8 +221,6 @@ struct d40_base;
*
* @lock: A spinlock to protect this struct.
* @log_num: The logical number, if any of this channel.
- * @completed: Starts with 1, after first interrupt it is set to dma engine's
- * current cookie.
* @pending_tx: The number of pending transfers. Used between interrupt handler
* and tasklet.
* @busy: Set to true when transfer is ongoing on this channel.
@@ -250,8 +249,6 @@ struct d40_base;
struct d40_chan {
spinlock_t lock;
int log_num;
- /* ID of the most recent completed transfer */
- int completed;
int pending_tx;
bool busy;
struct d40_phy_res *phy_chan;
@@ -1223,21 +1220,14 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
chan);
struct d40_desc *d40d = container_of(tx, struct d40_desc, txd);
unsigned long flags;
+ dma_cookie_t cookie;
spin_lock_irqsave(&d40c->lock, flags);
-
- d40c->chan.cookie++;
-
- if (d40c->chan.cookie < 0)
- d40c->chan.cookie = 1;
-
- d40d->txd.cookie = d40c->chan.cookie;
-
+ cookie = dma_cookie_assign(tx);
d40_desc_queue(d40c, d40d);
-
spin_unlock_irqrestore(&d40c->lock, flags);
- return tx->cookie;
+ return cookie;
}
static int d40_start(struct d40_chan *d40c)
@@ -1357,7 +1347,7 @@ static void dma_tasklet(unsigned long data)
goto err;
if (!d40d->cyclic)
- d40c->completed = d40d->txd.cookie;
+ dma_cookie_complete(&d40d->txd);
/*
* If terminating a channel pending_tx is set to zero.
@@ -2182,7 +2172,7 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
bool is_free_phy;
spin_lock_irqsave(&d40c->lock, flags);
- d40c->completed = chan->cookie = 1;
+ dma_cookie_init(chan);
/* If no dma configuration is set use default configuration (memcpy) */
if (!d40c->configured) {
@@ -2299,7 +2289,8 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
struct scatterlist *sgl,
unsigned int sg_len,
enum dma_transfer_direction direction,
- unsigned long dma_flags)
+ unsigned long dma_flags,
+ void *context)
{
if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV)
return NULL;
@@ -2310,7 +2301,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
static struct dma_async_tx_descriptor *
dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
size_t buf_len, size_t period_len,
- enum dma_transfer_direction direction)
+ enum dma_transfer_direction direction, void *context)
{
unsigned int periods = buf_len / period_len;
struct dma_async_tx_descriptor *txd;
@@ -2342,25 +2333,19 @@ static enum dma_status d40_tx_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- int ret;
+ enum dma_status ret;
if (d40c->phy_chan == NULL) {
chan_err(d40c, "Cannot read status of unallocated channel\n");
return -EINVAL;
}
- last_complete = d40c->completed;
- last_used = chan->cookie;
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret != DMA_SUCCESS)
+ dma_set_residue(txstate, stedma40_residue(chan));
if (d40_is_paused(d40c))
ret = DMA_PAUSED;
- else
- ret = dma_async_is_complete(cookie, last_complete, last_used);
-
- dma_set_tx_state(txstate, last_complete, last_used,
- stedma40_residue(chan));
return ret;
}
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index a6f9c1684a0f..4e0dff59901d 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -31,6 +31,8 @@
#include <linux/timb_dma.h>
+#include "dmaengine.h"
+
#define DRIVER_NAME "timb-dma"
/* Global DMA registers */
@@ -84,7 +86,6 @@ struct timb_dma_chan {
especially the lists and descriptors,
from races between the tasklet and calls
from above */
- dma_cookie_t last_completed_cookie;
bool ongoing;
struct list_head active_list;
struct list_head queue;
@@ -284,7 +285,7 @@ static void __td_finish(struct timb_dma_chan *td_chan)
else
iowrite32(0, td_chan->membase + TIMBDMA_OFFS_TX_DLAR);
*/
- td_chan->last_completed_cookie = txd->cookie;
+ dma_cookie_complete(txd);
td_chan->ongoing = false;
callback = txd->callback;
@@ -349,12 +350,7 @@ static dma_cookie_t td_tx_submit(struct dma_async_tx_descriptor *txd)
dma_cookie_t cookie;
spin_lock_bh(&td_chan->lock);
-
- cookie = txd->chan->cookie;
- if (++cookie < 0)
- cookie = 1;
- txd->chan->cookie = cookie;
- txd->cookie = cookie;
+ cookie = dma_cookie_assign(txd);
if (list_empty(&td_chan->active_list)) {
dev_dbg(chan2dev(txd->chan), "%s: started %u\n", __func__,
@@ -481,8 +477,7 @@ static int td_alloc_chan_resources(struct dma_chan *chan)
}
spin_lock_bh(&td_chan->lock);
- td_chan->last_completed_cookie = 1;
- chan->cookie = 1;
+ dma_cookie_init(chan);
spin_unlock_bh(&td_chan->lock);
return 0;
@@ -515,24 +510,13 @@ static void td_free_chan_resources(struct dma_chan *chan)
static enum dma_status td_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
- struct timb_dma_chan *td_chan =
- container_of(chan, struct timb_dma_chan, chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- int ret;
+ enum dma_status ret;
dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
- last_complete = td_chan->last_completed_cookie;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
-
- dma_set_tx_state(txstate, last_complete, last_used, 0);
+ ret = dma_cookie_status(chan, cookie, txstate);
- dev_dbg(chan2dev(chan),
- "%s: exit, ret: %d, last_complete: %d, last_used: %d\n",
- __func__, ret, last_complete, last_used);
+ dev_dbg(chan2dev(chan), "%s: exit, ret: %d\n", __func__, ret);
return ret;
}
@@ -558,7 +542,8 @@ static void td_issue_pending(struct dma_chan *chan)
static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
struct scatterlist *sgl, unsigned int sg_len,
- enum dma_transfer_direction direction, unsigned long flags)
+ enum dma_transfer_direction direction, unsigned long flags,
+ void *context)
{
struct timb_dma_chan *td_chan =
container_of(chan, struct timb_dma_chan, chan);
@@ -766,7 +751,7 @@ static int __devinit td_probe(struct platform_device *pdev)
}
td_chan->chan.device = &td->dma;
- td_chan->chan.cookie = 1;
+ dma_cookie_init(&td_chan->chan);
spin_lock_init(&td_chan->lock);
INIT_LIST_HEAD(&td_chan->active_list);
INIT_LIST_HEAD(&td_chan->queue);
diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c
index 6122c364cf11..913f55c76c99 100644
--- a/drivers/dma/txx9dmac.c
+++ b/drivers/dma/txx9dmac.c
@@ -15,6 +15,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
+
+#include "dmaengine.h"
#include "txx9dmac.h"
static struct txx9dmac_chan *to_txx9dmac_chan(struct dma_chan *chan)
@@ -279,21 +281,6 @@ static void txx9dmac_desc_put(struct txx9dmac_chan *dc,
}
}
-/* Called with dc->lock held and bh disabled */
-static dma_cookie_t
-txx9dmac_assign_cookie(struct txx9dmac_chan *dc, struct txx9dmac_desc *desc)
-{
- dma_cookie_t cookie = dc->chan.cookie;
-
- if (++cookie < 0)
- cookie = 1;
-
- dc->chan.cookie = cookie;
- desc->txd.cookie = cookie;
-
- return cookie;
-}
-
/*----------------------------------------------------------------------*/
static void txx9dmac_dump_regs(struct txx9dmac_chan *dc)
@@ -424,7 +411,7 @@ txx9dmac_descriptor_complete(struct txx9dmac_chan *dc,
dev_vdbg(chan2dev(&dc->chan), "descriptor %u %p complete\n",
txd->cookie, desc);
- dc->completed = txd->cookie;
+ dma_cookie_complete(txd);
callback = txd->callback;
param = txd->callback_param;
@@ -738,7 +725,7 @@ static dma_cookie_t txx9dmac_tx_submit(struct dma_async_tx_descriptor *tx)
dma_cookie_t cookie;
spin_lock_bh(&dc->lock);
- cookie = txx9dmac_assign_cookie(dc, desc);
+ cookie = dma_cookie_assign(tx);
dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u %p\n",
desc->txd.cookie, desc);
@@ -846,7 +833,7 @@ txx9dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
static struct dma_async_tx_descriptor *
txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags)
+ unsigned long flags, void *context)
{
struct txx9dmac_chan *dc = to_txx9dmac_chan(chan);
struct txx9dmac_dev *ddev = dc->ddev;
@@ -972,27 +959,17 @@ txx9dmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct txx9dmac_chan *dc = to_txx9dmac_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- int ret;
+ enum dma_status ret;
- last_complete = dc->completed;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
if (ret != DMA_SUCCESS) {
spin_lock_bh(&dc->lock);
txx9dmac_scan_descriptors(dc);
spin_unlock_bh(&dc->lock);
- last_complete = dc->completed;
- last_used = chan->cookie;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
+ ret = dma_cookie_status(chan, cookie, txstate);
}
- dma_set_tx_state(txstate, last_complete, last_used, 0);
-
return ret;
}
@@ -1057,7 +1034,7 @@ static int txx9dmac_alloc_chan_resources(struct dma_chan *chan)
return -EIO;
}
- dc->completed = chan->cookie = 1;
+ dma_cookie_init(chan);
dc->ccr = TXX9_DMA_CCR_IMMCHN | TXX9_DMA_CCR_INTENE | CCR_LE;
txx9dmac_chan_set_SMPCHN(dc);
@@ -1186,7 +1163,7 @@ static int __init txx9dmac_chan_probe(struct platform_device *pdev)
dc->ddev->chan[ch] = dc;
dc->chan.device = &dc->dma;
list_add_tail(&dc->chan.device_node, &dc->chan.device->channels);
- dc->chan.cookie = dc->completed = 1;
+ dma_cookie_init(&dc->chan);
if (is_dmac64(dc))
dc->ch_regs = &__txx9dmac_regs(dc->ddev)->CHAN[ch];
diff --git a/drivers/dma/txx9dmac.h b/drivers/dma/txx9dmac.h
index 365d42366b9f..f5a760598882 100644
--- a/drivers/dma/txx9dmac.h
+++ b/drivers/dma/txx9dmac.h
@@ -172,7 +172,6 @@ struct txx9dmac_chan {
spinlock_t lock;
/* these other elements are all protected by lock */
- dma_cookie_t completed;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 5948a2194f50..fdffa1beca17 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -215,7 +215,7 @@ config EDAC_I7300
config EDAC_SBRIDGE
tristate "Intel Sandy-Bridge Integrated MC"
depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
- depends on EXPERIMENTAL
+ depends on PCI_MMCONFIG && EXPERIMENTAL
help
Support for error detection and correction the Intel
Sandy Bridge Integrated Memory Controller.
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index da09cd74bc5b..feef7733fae7 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -39,7 +39,7 @@ static LIST_HEAD(mc_devices);
#ifdef CONFIG_EDAC_DEBUG
-static void edac_mc_dump_channel(struct channel_info *chan)
+static void edac_mc_dump_channel(struct rank_info *chan)
{
debugf4("\tchannel = %p\n", chan);
debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
@@ -156,7 +156,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
{
struct mem_ctl_info *mci;
struct csrow_info *csi, *csrow;
- struct channel_info *chi, *chp, *chan;
+ struct rank_info *chi, *chp, *chan;
void *pvt;
unsigned size;
int row, chn;
@@ -181,7 +181,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
* rather than an imaginary chunk of memory located at address 0.
*/
csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
- chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi));
+ chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
/* setup index and various internal pointers */
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index 2e23547b2f24..d500749464ea 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -49,7 +49,7 @@
#define I5100_FERR_NF_MEM_M6ERR_MASK (1 << 6)
#define I5100_FERR_NF_MEM_M5ERR_MASK (1 << 5)
#define I5100_FERR_NF_MEM_M4ERR_MASK (1 << 4)
-#define I5100_FERR_NF_MEM_M1ERR_MASK 1
+#define I5100_FERR_NF_MEM_M1ERR_MASK (1 << 1)
#define I5100_FERR_NF_MEM_ANY_MASK \
(I5100_FERR_NF_MEM_M16ERR_MASK | \
I5100_FERR_NF_MEM_M15ERR_MASK | \
@@ -535,23 +535,20 @@ static void i5100_read_log(struct mem_ctl_info *mci, int chan,
static void i5100_check_error(struct mem_ctl_info *mci)
{
struct i5100_priv *priv = mci->pvt_info;
- u32 dw;
-
+ u32 dw, dw2;
pci_read_config_dword(priv->mc, I5100_FERR_NF_MEM, &dw);
if (i5100_ferr_nf_mem_any(dw)) {
- u32 dw2;
pci_read_config_dword(priv->mc, I5100_NERR_NF_MEM, &dw2);
- if (dw2)
- pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM,
- dw2);
- pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
i5100_read_log(mci, i5100_ferr_nf_mem_chan_indx(dw),
i5100_ferr_nf_mem_any(dw),
i5100_nerr_nf_mem_any(dw2));
+
+ pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM, dw2);
}
+ pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
}
/* The i5100 chipset will scrub the entire memory once, then
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index 67ec9626a330..1869a1018fb5 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -735,7 +735,7 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
/* Attempt to 'get' the MCH register we want */
pdev = NULL;
- while (!pvt->branchmap_werrors || !pvt->fsb_error_regs) {
+ while (1) {
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
if (!pdev) {
@@ -743,23 +743,42 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
i5400_printk(KERN_ERR,
"'system address,Process Bus' "
"device not found:"
- "vendor 0x%x device 0x%x ERR funcs "
+ "vendor 0x%x device 0x%x ERR func 1 "
"(broken BIOS?)\n",
PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_ERR);
- goto error;
+ return -ENODEV;
}
- /* Store device 16 funcs 1 and 2 */
- switch (PCI_FUNC(pdev->devfn)) {
- case 1:
- pvt->branchmap_werrors = pdev;
- break;
- case 2:
- pvt->fsb_error_regs = pdev;
+ /* Store device 16 func 1 */
+ if (PCI_FUNC(pdev->devfn) == 1)
break;
+ }
+ pvt->branchmap_werrors = pdev;
+
+ pdev = NULL;
+ while (1) {
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
+ if (!pdev) {
+ /* End of list, leave */
+ i5400_printk(KERN_ERR,
+ "'system address,Process Bus' "
+ "device not found:"
+ "vendor 0x%x device 0x%x ERR func 2 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_5400_ERR);
+
+ pci_dev_put(pvt->branchmap_werrors);
+ return -ENODEV;
}
+
+ /* Store device 16 func 2 */
+ if (PCI_FUNC(pdev->devfn) == 2)
+ break;
}
+ pvt->fsb_error_regs = pdev;
debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n",
pci_name(pvt->system_address),
@@ -778,7 +797,10 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
"MC: 'BRANCH 0' device not found:"
"vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_FBD0);
- goto error;
+
+ pci_dev_put(pvt->fsb_error_regs);
+ pci_dev_put(pvt->branchmap_werrors);
+ return -ENODEV;
}
/* If this device claims to have more than 2 channels then
@@ -796,14 +818,14 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
"(broken BIOS?)\n",
PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_FBD1);
- goto error;
+
+ pci_dev_put(pvt->branch_0);
+ pci_dev_put(pvt->fsb_error_regs);
+ pci_dev_put(pvt->branchmap_werrors);
+ return -ENODEV;
}
return 0;
-
-error:
- i5400_put_devices(mci);
- return -ENODEV;
}
/*
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index fc757069c6af..d427c69bb8b1 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -184,7 +184,7 @@ struct ppc4xx_ecc_status {
/* Function Prototypes */
-static int ppc4xx_edac_probe(struct platform_device *device)
+static int ppc4xx_edac_probe(struct platform_device *device);
static int ppc4xx_edac_remove(struct platform_device *device);
/* Global Variables */
@@ -1068,7 +1068,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
mci->mod_name = PPC4XX_EDAC_MODULE_NAME;
mci->mod_ver = PPC4XX_EDAC_MODULE_REVISION;
- mci->ctl_name = match->compatible,
+ mci->ctl_name = ppc4xx_edac_match->compatible,
mci->dev_name = np->full_name;
/* Initialize callbacks */
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 3a605f777712..a203536d90dd 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -20,6 +20,7 @@
#include <linux/mmzone.h>
#include <linux/smp.h>
#include <linux/bitmap.h>
+#include <linux/math64.h>
#include <asm/processor.h>
#include <asm/mce.h>
@@ -670,6 +671,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
u32 reg;
u64 limit, prv = 0;
u64 tmp_mb;
+ u32 mb, kb;
u32 rir_way;
/*
@@ -682,8 +684,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
pvt->tolm = GET_TOLM(reg);
tmp_mb = (1 + pvt->tolm) >> 20;
- debugf0("TOLM: %Lu.%03Lu GB (0x%016Lx)\n",
- tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tolm);
+ mb = div_u64_rem(tmp_mb, 1000, &kb);
+ debugf0("TOLM: %u.%03u GB (0x%016Lx)\n",
+ mb, kb, (u64)pvt->tolm);
/* Address range is already 45:25 */
pci_read_config_dword(pvt->pci_sad1, TOHM,
@@ -691,8 +694,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
pvt->tohm = GET_TOHM(reg);
tmp_mb = (1 + pvt->tohm) >> 20;
- debugf0("TOHM: %Lu.%03Lu GB (0x%016Lx)",
- tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tohm);
+ mb = div_u64_rem(tmp_mb, 1000, &kb);
+ debugf0("TOHM: %u.%03u GB (0x%016Lx)",
+ mb, kb, (u64)pvt->tohm);
/*
* Step 2) Get SAD range and SAD Interleave list
@@ -714,10 +718,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
break;
tmp_mb = (limit + 1) >> 20;
- debugf0("SAD#%d %s up to %Lu.%03Lu GB (0x%016Lx) %s reg=0x%08x\n",
+ mb = div_u64_rem(tmp_mb, 1000, &kb);
+ debugf0("SAD#%d %s up to %u.%03u GB (0x%016Lx) %s reg=0x%08x\n",
n_sads,
get_dram_attr(reg),
- tmp_mb / 1000, tmp_mb % 1000,
+ mb, kb,
((u64)tmp_mb) << 20L,
INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]",
reg);
@@ -747,8 +752,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
break;
tmp_mb = (limit + 1) >> 20;
- debugf0("TAD#%d: up to %Lu.%03Lu GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
- n_tads, tmp_mb / 1000, tmp_mb % 1000,
+ mb = div_u64_rem(tmp_mb, 1000, &kb);
+ debugf0("TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
+ n_tads, mb, kb,
((u64)tmp_mb) << 20L,
(u32)TAD_SOCK(reg),
(u32)TAD_CH(reg),
@@ -757,7 +763,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
(u32)TAD_TGT2(reg),
(u32)TAD_TGT3(reg),
reg);
- prv = tmp_mb;
+ prv = limit;
}
/*
@@ -771,9 +777,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
tad_ch_nilv_offset[j],
&reg);
tmp_mb = TAD_OFFSET(reg) >> 20;
- debugf0("TAD CH#%d, offset #%d: %Lu.%03Lu GB (0x%016Lx), reg=0x%08x\n",
+ mb = div_u64_rem(tmp_mb, 1000, &kb);
+ debugf0("TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
i, j,
- tmp_mb / 1000, tmp_mb % 1000,
+ mb, kb,
((u64)tmp_mb) << 20L,
reg);
}
@@ -795,9 +802,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
tmp_mb = RIR_LIMIT(reg) >> 20;
rir_way = 1 << RIR_WAY(reg);
- debugf0("CH#%d RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d, reg=0x%08x\n",
+ mb = div_u64_rem(tmp_mb, 1000, &kb);
+ debugf0("CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
i, j,
- tmp_mb / 1000, tmp_mb % 1000,
+ mb, kb,
((u64)tmp_mb) << 20L,
rir_way,
reg);
@@ -808,9 +816,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
&reg);
tmp_mb = RIR_OFFSET(reg) << 6;
- debugf0("CH#%d RIR#%d INTL#%d, offset %Lu.%03Lu GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
+ mb = div_u64_rem(tmp_mb, 1000, &kb);
+ debugf0("CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
i, j, k,
- tmp_mb / 1000, tmp_mb % 1000,
+ mb, kb,
((u64)tmp_mb) << 20L,
(u32)RIR_RNK_TGT(reg),
reg);
@@ -848,6 +857,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
u8 ch_way,sck_way;
u32 tad_offset;
u32 rir_way;
+ u32 mb, kb;
u64 ch_addr, offset, limit, prv = 0;
@@ -858,7 +868,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
* range (e. g. VGA addresses). It is unlikely, however, that the
* memory controller would generate an error on that range.
*/
- if ((addr > (u64) pvt->tolm) && (addr < (1L << 32))) {
+ if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) {
sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr);
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL;
@@ -913,7 +923,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
addr,
limit,
sad_way + 7,
- INTERLEAVE_MODE(reg) ? "" : "XOR[18:16]");
+ interleave_mode ? "" : "XOR[18:16]");
if (interleave_mode)
idx = ((addr >> 6) ^ (addr >> 16)) & 7;
else
@@ -1053,7 +1063,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
ch_addr = addr & 0x7f;
/* Remove socket wayness and remove 6 bits */
addr >>= 6;
- addr /= sck_xch;
+ addr = div_u64(addr, sck_xch);
#if 0
/* Divide by channel way */
addr = addr / ch_way;
@@ -1073,10 +1083,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
continue;
limit = RIR_LIMIT(reg);
-
- debugf0("RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d\n",
+ mb = div_u64_rem(limit >> 20, 1000, &kb);
+ debugf0("RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
n_rir,
- (limit >> 20) / 1000, (limit >> 20) % 1000,
+ mb, kb,
limit,
1 << RIR_WAY(reg));
if (ch_addr <= limit)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 22c6df5f136d..2e6b24547e2a 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -44,7 +44,6 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <asm/system.h>
#include "core.h"
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index afa7c83bd114..68109e9bb04e 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -40,7 +40,6 @@
#include <linux/atomic.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include "core.h"
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c
index 255646ffc352..0de83508f321 100644
--- a/drivers/firewire/core-topology.c
+++ b/drivers/firewire/core-topology.c
@@ -31,7 +31,6 @@
#include <linux/atomic.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include "core.h"
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 187b3f2e797e..2b5460075a9f 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -46,7 +46,6 @@
#include <asm/byteorder.h>
#include <asm/page.h>
-#include <asm/system.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h>
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 000a29ffedae..b7e65d7eab64 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -52,7 +52,6 @@
#include <linux/workqueue.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 0409cf35adda..edadbdad31d0 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -236,6 +236,12 @@ config GPIO_MAX732X_IRQ
Say yes here to enable the max732x to be used as an interrupt
controller. It requires the driver to be built in the kernel.
+config GPIO_MC9S08DZ60
+ bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions"
+ depends on I2C && MACH_MX35_3DS
+ help
+ Select this to enable the MC9S08DZ60 GPIO driver
+
config GPIO_PCA953X
tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"
depends on I2C
@@ -422,6 +428,14 @@ config GPIO_ML_IOH
Hub) which is for IVI(In-Vehicle Infotainment) use.
This driver can access the IOH's GPIO device.
+config GPIO_SODAVILLE
+ bool "Intel Sodaville GPIO support"
+ depends on X86 && PCI && OF && BROKEN
+ select GPIO_GENERIC
+ select GENERIC_IRQ_CHIP
+ help
+ Say Y here to support Intel Sodaville GPIO.
+
config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
depends on MFD_TIMBERDALE && HAS_IOMEM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9a8fb54ae462..007f54bd0081 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
+obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
+obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index df0d59570a84..3d000169285d 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -313,10 +313,16 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
return -ENODEV;
}
-static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger)
+static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
{
- struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
- u32 mask = (u32) irq_data_get_irq_handler_data(d);
+ struct davinci_gpio_controller *d;
+ struct davinci_gpio_regs __iomem *g;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ u32 mask;
+
+ d = (struct davinci_gpio_controller *)data->handler_data;
+ g = (struct davinci_gpio_regs __iomem *)d->regs;
+ mask = __gpio_mask(data->irq - soc_info->gpio_irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
@@ -380,7 +386,7 @@ static int __init davinci_gpio_irq_setup(void)
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
*/
if (soc_info->gpio_unbanked) {
- static struct irq_chip gpio_irqchip_unbanked;
+ static struct irq_chip_type gpio_unbanked;
/* pass "bank 0" GPIO IRQs to AINTC */
chips[0].chip.to_irq = gpio_to_irq_unbanked;
@@ -388,9 +394,10 @@ static int __init davinci_gpio_irq_setup(void)
/* AINTC handles mask/unmask; GPIO handles triggering */
irq = bank_irq;
- gpio_irqchip_unbanked = *irq_get_chip(irq);
- gpio_irqchip_unbanked.name = "GPIO-AINTC";
- gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked;
+ gpio_unbanked = *container_of(irq_get_chip(irq),
+ struct irq_chip_type, chip);
+ gpio_unbanked.chip.name = "GPIO-AINTC";
+ gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */
g = gpio2regs(0);
@@ -399,9 +406,8 @@ static int __init davinci_gpio_irq_setup(void)
/* set the direct IRQs up to use that irqchip */
for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
- irq_set_chip(irq, &gpio_irqchip_unbanked);
- irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
- irq_set_chip_data(irq, (__force void *)g);
+ irq_set_chip(irq, &gpio_unbanked.chip);
+ irq_set_handler_data(irq, &chips[gpio / 32]);
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
}
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 4ca5642e9776..776b772523e5 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -12,8 +12,6 @@
* published by the Free Software Foundation.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -65,11 +63,6 @@ static void ep93xx_gpio_update_int_params(unsigned port)
EP93XX_GPIO_REG(int_en_register_offset[port]));
}
-static inline void ep93xx_gpio_int_mask(unsigned line)
-{
- gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
-}
-
static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
{
int line = irq_to_gpio(irq);
@@ -212,7 +205,6 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
handler = handle_edge_irq;
break;
default:
- pr_err("failed to set irq type %d for gpio %d\n", type, gpio);
return -EINVAL;
}
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index ddfacc5ce56d..61c2d08d37b6 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -59,12 +59,14 @@
#define GPO3_PIN_TO_BIT(x) (1 << (x))
#define GPIO012_PIN_IN_SEL(x, y) (((x) >> (y)) & 1)
#define GPIO3_PIN_IN_SHIFT(x) ((x) == 5 ? 24 : 10 + (x))
-#define GPIO3_PIN_IN_SEL(x, y) ((x) >> GPIO3_PIN_IN_SHIFT(y))
+#define GPIO3_PIN_IN_SEL(x, y) (((x) >> GPIO3_PIN_IN_SHIFT(y)) & 1)
#define GPIO3_PIN5_IN_SEL(x) (((x) >> 24) & 1)
#define GPI3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1)
+#define GPO3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1)
struct gpio_regs {
void __iomem *inp_state;
+ void __iomem *outp_state;
void __iomem *outp_set;
void __iomem *outp_clr;
void __iomem *dir_set;
@@ -145,6 +147,7 @@ static struct gpio_regs gpio_grp_regs_p2 = {
static struct gpio_regs gpio_grp_regs_p3 = {
.inp_state = LPC32XX_GPIO_P3_INP_STATE,
+ .outp_state = LPC32XX_GPIO_P3_OUTP_STATE,
.outp_set = LPC32XX_GPIO_P3_OUTP_SET,
.outp_clr = LPC32XX_GPIO_P3_OUTP_CLR,
.dir_set = LPC32XX_GPIO_P2_DIR_SET,
@@ -240,6 +243,12 @@ static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
}
+static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group,
+ unsigned pin)
+{
+ return GPO3_PIN_IN_SEL(__raw_readl(group->gpio_grp->outp_state), pin);
+}
+
/*
* GENERIC_GPIO primitives.
*/
@@ -340,6 +349,13 @@ static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
__set_gpo_level_p3(group, pin, value);
}
+static int lpc32xx_gpo_get_value(struct gpio_chip *chip, unsigned pin)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ return __get_gpo_state_p3(group, pin);
+}
+
static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
{
if (pin < chip->ngpio)
@@ -427,6 +443,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
.label = "gpo_p3",
.direction_output = lpc32xx_gpio_dir_out_always,
.set = lpc32xx_gpo_set_value,
+ .get = lpc32xx_gpo_get_value,
.request = lpc32xx_gpio_request,
.base = LPC32XX_GPO_P3_GRP,
.ngpio = LPC32XX_GPO_P3_MAX,
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
new file mode 100644
index 000000000000..2738cc44d636
--- /dev/null
+++ b/drivers/gpio/gpio-mc9s08dz60.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Wu Guoxing <b39297@freescale.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#define GPIO_GROUP_NUM 2
+#define GPIO_NUM_PER_GROUP 8
+#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP)
+
+struct mc9s08dz60 {
+ struct i2c_client *client;
+ struct gpio_chip chip;
+};
+
+static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc)
+{
+ return container_of(gc, struct mc9s08dz60, chip);
+}
+
+
+static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
+{
+ *reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
+ *bit = offset % GPIO_NUM_PER_GROUP;
+}
+
+static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ u8 reg, bit;
+ s32 value;
+ struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+ mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+ value = i2c_smbus_read_byte_data(mc9s->client, reg);
+
+ return (value >= 0) ? (value >> bit) & 0x1 : 0;
+}
+
+static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val)
+{
+ u8 reg, bit;
+ s32 value;
+
+ mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+ value = i2c_smbus_read_byte_data(mc9s->client, reg);
+ if (value >= 0) {
+ if (val)
+ value |= 1 << bit;
+ else
+ value &= ~(1 << bit);
+
+ return i2c_smbus_write_byte_data(mc9s->client, reg, value);
+ } else
+ return value;
+
+}
+
+
+static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+ struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+ mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_direction_output(struct gpio_chip *gc,
+ unsigned offset, int val)
+{
+ struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+ return mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct mc9s08dz60 *mc9s;
+
+ mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL);
+ if (!mc9s)
+ return -ENOMEM;
+
+ mc9s->chip.label = client->name;
+ mc9s->chip.base = -1;
+ mc9s->chip.dev = &client->dev;
+ mc9s->chip.owner = THIS_MODULE;
+ mc9s->chip.ngpio = GPIO_NUM;
+ mc9s->chip.can_sleep = 1;
+ mc9s->chip.get = mc9s08dz60_get_value;
+ mc9s->chip.set = mc9s08dz60_set_value;
+ mc9s->chip.direction_output = mc9s08dz60_direction_output;
+ mc9s->client = client;
+ i2c_set_clientdata(client, mc9s);
+
+ ret = gpiochip_add(&mc9s->chip);
+ if (ret)
+ goto error;
+
+ return 0;
+
+ error:
+ kfree(mc9s);
+ return ret;
+}
+
+static int mc9s08dz60_remove(struct i2c_client *client)
+{
+ struct mc9s08dz60 *mc9s;
+ int ret;
+
+ mc9s = i2c_get_clientdata(client);
+
+ ret = gpiochip_remove(&mc9s->chip);
+ if (!ret)
+ kfree(mc9s);
+
+ return ret;
+
+}
+
+static const struct i2c_device_id mc9s08dz60_id[] = {
+ {"mc9s08dz60", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id);
+
+static struct i2c_driver mc9s08dz60_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mc9s08dz60",
+ },
+ .probe = mc9s08dz60_probe,
+ .remove = mc9s08dz60_remove,
+ .id_table = mc9s08dz60_id,
+};
+
+module_i2c_driver(mc9s08dz60_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc. "
+ "Wu Guoxing <b39297@freescale.com>");
+MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index f49bd6f47a50..1adc2ec1e383 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -19,9 +19,12 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/slab.h>
+#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/irqdomain.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -50,10 +53,10 @@ struct gpio_regs {
struct gpio_bank {
struct list_head node;
- unsigned long pbase;
void __iomem *base;
u16 irq;
- u16 virtual_irq_start;
+ int irq_base;
+ struct irq_domain *domain;
u32 suspend_wakeup;
u32 saved_wakeup;
u32 non_wakeup_gpios;
@@ -77,7 +80,6 @@ struct gpio_bank {
int stride;
u32 width;
int context_loss_count;
- u16 id;
int power_mode;
bool workaround_enabled;
@@ -91,6 +93,11 @@ struct gpio_bank {
#define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
#define GPIO_MOD_CTRL_BIT BIT(0)
+static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
+{
+ return gpio_irq - bank->irq_base + bank->chip.base;
+}
+
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
{
void __iomem *reg = bank->base;
@@ -113,10 +120,13 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable)
void __iomem *reg = bank->base;
u32 l = GPIO_BIT(bank, gpio);
- if (enable)
+ if (enable) {
reg += bank->regs->set_dataout;
- else
+ bank->context.dataout |= l;
+ } else {
reg += bank->regs->clr_dataout;
+ bank->context.dataout &= ~l;
+ }
__raw_writel(l, reg);
}
@@ -137,25 +147,25 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
bank->context.dataout = l;
}
-static int _get_gpio_datain(struct gpio_bank *bank, int gpio)
+static int _get_gpio_datain(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->datain;
- return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0;
+ return (__raw_readl(reg) & (1 << offset)) != 0;
}
-static int _get_gpio_dataout(struct gpio_bank *bank, int gpio)
+static int _get_gpio_dataout(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->dataout;
- return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0;
+ return (__raw_readl(reg) & (1 << offset)) != 0;
}
static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
{
int l = __raw_readl(base + reg);
- if (set)
+ if (set)
l |= mask;
else
l &= ~mask;
@@ -238,7 +248,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
}
static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
- int trigger)
+ unsigned trigger)
{
void __iomem *base = bank->base;
u32 gpio_bit = 1 << gpio;
@@ -320,7 +330,8 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
#endif
-static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
+static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
+ unsigned trigger)
{
void __iomem *reg = bank->base;
void __iomem *base = bank->base;
@@ -367,7 +378,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
static int gpio_irq_type(struct irq_data *d, unsigned type)
{
- struct gpio_bank *bank;
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
unsigned gpio;
int retval;
unsigned long flags;
@@ -375,13 +386,11 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE)
gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
else
- gpio = d->irq - IH_GPIO_BASE;
+ gpio = irq_to_gpio(bank, d->irq);
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
- bank = irq_data_get_irq_chip_data(d);
-
if (!bank->regs->leveldetect0 &&
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL;
@@ -442,6 +451,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
if (bank->regs->set_irqenable) {
reg += bank->regs->set_irqenable;
l = gpio_mask;
+ bank->context.irqenable1 |= gpio_mask;
} else {
reg += bank->regs->irqenable;
l = __raw_readl(reg);
@@ -449,10 +459,10 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
l &= ~gpio_mask;
else
l |= gpio_mask;
+ bank->context.irqenable1 = l;
}
__raw_writel(l, reg);
- bank->context.irqenable1 = l;
}
static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
@@ -463,6 +473,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
if (bank->regs->clr_irqenable) {
reg += bank->regs->clr_irqenable;
l = gpio_mask;
+ bank->context.irqenable1 &= ~gpio_mask;
} else {
reg += bank->regs->irqenable;
l = __raw_readl(reg);
@@ -470,15 +481,18 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
l |= gpio_mask;
else
l &= ~gpio_mask;
+ bank->context.irqenable1 = l;
}
__raw_writel(l, reg);
- bank->context.irqenable1 = l;
}
static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
{
- _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ if (enable)
+ _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ else
+ _disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
}
/*
@@ -495,7 +509,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
unsigned long flags;
if (bank->non_wakeup_gpios & gpio_bit) {
- dev_err(bank->dev,
+ dev_err(bank->dev,
"Unable to modify wakeup on non-wakeup GPIO%d\n", gpio);
return -EINVAL;
}
@@ -506,6 +520,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
else
bank->suspend_wakeup &= ~gpio_bit;
+ __raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -522,14 +537,10 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
- unsigned int gpio = d->irq - IH_GPIO_BASE;
- struct gpio_bank *bank;
- int retval;
-
- bank = irq_data_get_irq_chip_data(d);
- retval = _set_gpio_wakeup(bank, gpio, enable);
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irq_to_gpio(bank, d->irq);
- return retval;
+ return _set_gpio_wakeup(bank, gpio, enable);
}
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -671,13 +682,15 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
if (!isr)
break;
- gpio_irq = bank->virtual_irq_start;
+ gpio_irq = bank->irq_base;
for (; isr != 0; isr >>= 1, gpio_irq++) {
- gpio_index = GPIO_INDEX(bank, irq_to_gpio(gpio_irq));
+ int gpio = irq_to_gpio(bank, gpio_irq);
if (!(isr & 1))
continue;
+ gpio_index = GPIO_INDEX(bank, gpio);
+
/*
* Some chips can't respond to both rising and falling
* at the same time. If this irq was requested with
@@ -703,8 +716,8 @@ exit:
static void gpio_irq_shutdown(struct irq_data *d)
{
- unsigned int gpio = d->irq - IH_GPIO_BASE;
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irq_to_gpio(bank, d->irq);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
@@ -714,16 +727,16 @@ static void gpio_irq_shutdown(struct irq_data *d)
static void gpio_ack_irq(struct irq_data *d)
{
- unsigned int gpio = d->irq - IH_GPIO_BASE;
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irq_to_gpio(bank, d->irq);
_clear_gpio_irqstatus(bank, gpio);
}
static void gpio_mask_irq(struct irq_data *d)
{
- unsigned int gpio = d->irq - IH_GPIO_BASE;
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irq_to_gpio(bank, d->irq);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
@@ -734,8 +747,8 @@ static void gpio_mask_irq(struct irq_data *d)
static void gpio_unmask_irq(struct irq_data *d)
{
- unsigned int gpio = d->irq - IH_GPIO_BASE;
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = irq_to_gpio(bank, d->irq);
unsigned int irq_mask = GPIO_BIT(bank, gpio);
u32 trigger = irqd_get_trigger_type(d);
unsigned long flags;
@@ -852,19 +865,15 @@ static int gpio_is_input(struct gpio_bank *bank, int mask)
static int gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
- void __iomem *reg;
- int gpio;
u32 mask;
- gpio = chip->base + offset;
bank = container_of(chip, struct gpio_bank, chip);
- reg = bank->base;
- mask = GPIO_BIT(bank, gpio);
+ mask = (1 << offset);
if (gpio_is_input(bank, mask))
- return _get_gpio_datain(bank, gpio);
+ return _get_gpio_datain(bank, offset);
else
- return _get_gpio_dataout(bank, gpio);
+ return _get_gpio_dataout(bank, offset);
}
static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
@@ -917,7 +926,7 @@ static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
struct gpio_bank *bank;
bank = container_of(chip, struct gpio_bank, chip);
- return bank->virtual_irq_start + offset;
+ return bank->irq_base + offset;
}
/*---------------------------------------------------------------------*/
@@ -970,7 +979,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
_gpio_rmw(base, bank->regs->ctrl, 0, 1);
}
-static __init void
+static __devinit void
omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
unsigned int num)
{
@@ -1030,8 +1039,7 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
gpiochip_add(&bank->chip);
- for (j = bank->virtual_irq_start;
- j < bank->virtual_irq_start + bank->width; j++) {
+ for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) {
irq_set_lockdep_class(j, &gpio_lock_class);
irq_set_chip_data(j, bank);
if (bank->is_mpuio) {
@@ -1046,39 +1054,38 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
irq_set_handler_data(bank->irq, bank);
}
+static const struct of_device_id omap_gpio_match[];
+
static int __devinit omap_gpio_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ const struct of_device_id *match;
struct omap_gpio_platform_data *pdata;
struct resource *res;
struct gpio_bank *bank;
int ret = 0;
- if (!pdev->dev.platform_data) {
- ret = -EINVAL;
- goto err_exit;
- }
+ match = of_match_device(of_match_ptr(omap_gpio_match), dev);
+
+ pdata = match ? match->data : dev->platform_data;
+ if (!pdata)
+ return -EINVAL;
- bank = kzalloc(sizeof(struct gpio_bank), GFP_KERNEL);
+ bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
if (!bank) {
- dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n");
- ret = -ENOMEM;
- goto err_exit;
+ dev_err(dev, "Memory alloc failed\n");
+ return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (unlikely(!res)) {
- dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n",
- pdev->id);
- ret = -ENODEV;
- goto err_free;
+ dev_err(dev, "Invalid IRQ resource\n");
+ return -ENODEV;
}
bank->irq = res->start;
- bank->id = pdev->id;
-
- pdata = pdev->dev.platform_data;
- bank->virtual_irq_start = pdata->virtual_irq_start;
- bank->dev = &pdev->dev;
+ bank->dev = dev;
bank->dbck_flag = pdata->dbck_flag;
bank->stride = pdata->bank_stride;
bank->width = pdata->bank_width;
@@ -1087,6 +1094,18 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
bank->loses_context = pdata->loses_context;
bank->get_context_loss_count = pdata->get_context_loss_count;
bank->regs = pdata->regs;
+#ifdef CONFIG_OF_GPIO
+ bank->chip.of_node = of_node_get(node);
+#endif
+
+ bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
+ if (bank->irq_base < 0) {
+ dev_err(dev, "Couldn't allocate IRQ numbers\n");
+ return -ENODEV;
+ }
+
+ bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base,
+ 0, &irq_domain_simple_ops, NULL);
if (bank->regs->set_dataout && bank->regs->clr_dataout)
bank->set_dataout = _set_gpio_dataout_reg;
@@ -1098,18 +1117,20 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
/* Static mapping, never released */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!res)) {
- dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n",
- pdev->id);
- ret = -ENODEV;
- goto err_free;
+ dev_err(dev, "Invalid mem resource\n");
+ return -ENODEV;
}
- bank->base = ioremap(res->start, resource_size(res));
+ if (!devm_request_mem_region(dev, res->start, resource_size(res),
+ pdev->name)) {
+ dev_err(dev, "Region already claimed\n");
+ return -EBUSY;
+ }
+
+ bank->base = devm_ioremap(dev, res->start, resource_size(res));
if (!bank->base) {
- dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n",
- pdev->id);
- ret = -ENOMEM;
- goto err_free;
+ dev_err(dev, "Could not ioremap\n");
+ return -ENOMEM;
}
platform_set_drvdata(pdev, bank);
@@ -1130,11 +1151,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
list_add_tail(&bank->node, &omap_gpio_list);
return ret;
-
-err_free:
- kfree(bank);
-err_exit:
- return ret;
}
#ifdef CONFIG_ARCH_OMAP2PLUS
@@ -1196,8 +1212,30 @@ static int omap_gpio_runtime_suspend(struct device *dev)
struct gpio_bank *bank = platform_get_drvdata(pdev);
u32 l1 = 0, l2 = 0;
unsigned long flags;
+ u32 wake_low, wake_hi;
spin_lock_irqsave(&bank->lock, flags);
+
+ /*
+ * Only edges can generate a wakeup event to the PRCM.
+ *
+ * Therefore, ensure any wake-up capable GPIOs have
+ * edge-detection enabled before going idle to ensure a wakeup
+ * to the PRCM is generated on a GPIO transition. (c.f. 34xx
+ * NDA TRM 25.5.3.1)
+ *
+ * The normal values will be restored upon ->runtime_resume()
+ * by writing back the values saved in bank->context.
+ */
+ wake_low = bank->context.leveldetect0 & bank->context.wake_en;
+ if (wake_low)
+ __raw_writel(wake_low | bank->context.fallingdetect,
+ bank->base + bank->regs->fallingdetect);
+ wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
+ if (wake_hi)
+ __raw_writel(wake_hi | bank->context.risingdetect,
+ bank->base + bank->regs->risingdetect);
+
if (bank->power_mode != OFF_MODE) {
bank->power_mode = 0;
goto update_gpio_context_count;
@@ -1207,9 +1245,6 @@ static int omap_gpio_runtime_suspend(struct device *dev)
* non-wakeup GPIOs. Otherwise spurious IRQs will be
* generated. See OMAP2420 Errata item 1.101.
*/
- if (!(bank->enabled_non_wakeup_gpios))
- goto update_gpio_context_count;
-
bank->saved_datain = __raw_readl(bank->base +
bank->regs->datain);
l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
@@ -1246,7 +1281,19 @@ static int omap_gpio_runtime_resume(struct device *dev)
spin_lock_irqsave(&bank->lock, flags);
_gpio_dbck_enable(bank);
- if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) {
+
+ /*
+ * In ->runtime_suspend(), level-triggered, wakeup-enabled
+ * GPIOs were set to edge trigger also in order to be able to
+ * generate a PRCM wakeup. Here we restore the
+ * pre-runtime_suspend() values for edge triggering.
+ */
+ __raw_writel(bank->context.fallingdetect,
+ bank->base + bank->regs->fallingdetect);
+ __raw_writel(bank->context.risingdetect,
+ bank->base + bank->regs->risingdetect);
+
+ if (!bank->workaround_enabled) {
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
@@ -1397,11 +1444,95 @@ static const struct dev_pm_ops gpio_pm_ops = {
NULL)
};
+#if defined(CONFIG_OF)
+static struct omap_gpio_reg_offs omap2_gpio_regs = {
+ .revision = OMAP24XX_GPIO_REVISION,
+ .direction = OMAP24XX_GPIO_OE,
+ .datain = OMAP24XX_GPIO_DATAIN,
+ .dataout = OMAP24XX_GPIO_DATAOUT,
+ .set_dataout = OMAP24XX_GPIO_SETDATAOUT,
+ .clr_dataout = OMAP24XX_GPIO_CLEARDATAOUT,
+ .irqstatus = OMAP24XX_GPIO_IRQSTATUS1,
+ .irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2,
+ .irqenable = OMAP24XX_GPIO_IRQENABLE1,
+ .irqenable2 = OMAP24XX_GPIO_IRQENABLE2,
+ .set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1,
+ .clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1,
+ .debounce = OMAP24XX_GPIO_DEBOUNCE_VAL,
+ .debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN,
+ .ctrl = OMAP24XX_GPIO_CTRL,
+ .wkup_en = OMAP24XX_GPIO_WAKE_EN,
+ .leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0,
+ .leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1,
+ .risingdetect = OMAP24XX_GPIO_RISINGDETECT,
+ .fallingdetect = OMAP24XX_GPIO_FALLINGDETECT,
+};
+
+static struct omap_gpio_reg_offs omap4_gpio_regs = {
+ .revision = OMAP4_GPIO_REVISION,
+ .direction = OMAP4_GPIO_OE,
+ .datain = OMAP4_GPIO_DATAIN,
+ .dataout = OMAP4_GPIO_DATAOUT,
+ .set_dataout = OMAP4_GPIO_SETDATAOUT,
+ .clr_dataout = OMAP4_GPIO_CLEARDATAOUT,
+ .irqstatus = OMAP4_GPIO_IRQSTATUS0,
+ .irqstatus2 = OMAP4_GPIO_IRQSTATUS1,
+ .irqenable = OMAP4_GPIO_IRQSTATUSSET0,
+ .irqenable2 = OMAP4_GPIO_IRQSTATUSSET1,
+ .set_irqenable = OMAP4_GPIO_IRQSTATUSSET0,
+ .clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0,
+ .debounce = OMAP4_GPIO_DEBOUNCINGTIME,
+ .debounce_en = OMAP4_GPIO_DEBOUNCENABLE,
+ .ctrl = OMAP4_GPIO_CTRL,
+ .wkup_en = OMAP4_GPIO_IRQWAKEN0,
+ .leveldetect0 = OMAP4_GPIO_LEVELDETECT0,
+ .leveldetect1 = OMAP4_GPIO_LEVELDETECT1,
+ .risingdetect = OMAP4_GPIO_RISINGDETECT,
+ .fallingdetect = OMAP4_GPIO_FALLINGDETECT,
+};
+
+static struct omap_gpio_platform_data omap2_pdata = {
+ .regs = &omap2_gpio_regs,
+ .bank_width = 32,
+ .dbck_flag = false,
+};
+
+static struct omap_gpio_platform_data omap3_pdata = {
+ .regs = &omap2_gpio_regs,
+ .bank_width = 32,
+ .dbck_flag = true,
+};
+
+static struct omap_gpio_platform_data omap4_pdata = {
+ .regs = &omap4_gpio_regs,
+ .bank_width = 32,
+ .dbck_flag = true,
+};
+
+static const struct of_device_id omap_gpio_match[] = {
+ {
+ .compatible = "ti,omap4-gpio",
+ .data = &omap4_pdata,
+ },
+ {
+ .compatible = "ti,omap3-gpio",
+ .data = &omap3_pdata,
+ },
+ {
+ .compatible = "ti,omap2-gpio",
+ .data = &omap2_pdata,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, omap_gpio_match);
+#endif
+
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
.driver = {
.name = "omap_gpio",
.pm = &gpio_pm_ops,
+ .of_match_table = of_match_ptr(omap_gpio_match),
},
};
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 77c9cc70fa77..b4b5da4fd2cc 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -352,7 +352,12 @@ static int pl061_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
+static const struct dev_pm_ops pl061_dev_pm_ops = {
+ .suspend = pl061_suspend,
+ .resume = pl061_resume,
+ .freeze = pl061_suspend,
+ .restore = pl061_resume,
+};
#endif
static struct amba_id pl061_ids[] = {
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index b2d3ee1d183a..5689ce62fd81 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -22,6 +22,8 @@
#include <linux/syscore_ops.h>
#include <linux/slab.h>
+#include <mach/irqs.h>
+
/*
* We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
* one set of registers. The register offsets are organized below:
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index 0a79a1167a25..46277877b7ec 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -169,7 +169,7 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip,
return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
}
-static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip,
+static int exynos_gpio_setpull(struct samsung_gpio_chip *chip,
unsigned int off, samsung_gpio_pull_t pull)
{
if (pull == S3C_GPIO_PULL_UP)
@@ -178,7 +178,7 @@ static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip,
return samsung_gpio_setpull_updown(chip, off, pull);
}
-static samsung_gpio_pull_t exynos4_gpio_getpull(struct samsung_gpio_chip *chip,
+static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip,
unsigned int off)
{
samsung_gpio_pull_t pull;
@@ -452,9 +452,9 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = {
};
#endif
-static struct samsung_gpio_cfg exynos4_gpio_cfg = {
- .set_pull = exynos4_gpio_setpull,
- .get_pull = exynos4_gpio_getpull,
+static struct samsung_gpio_cfg exynos_gpio_cfg = {
+ .set_pull = exynos_gpio_setpull,
+ .get_pull = exynos_gpio_getpull,
.set_config = samsung_gpio_setcfg_4bit,
.get_config = samsung_gpio_getcfg_4bit,
};
@@ -502,13 +502,13 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = {
.get_config = samsung_gpio_getcfg_2bit,
},
[8] = {
- .set_pull = exynos4_gpio_setpull,
- .get_pull = exynos4_gpio_getpull,
+ .set_pull = exynos_gpio_setpull,
+ .get_pull = exynos_gpio_getpull,
},
[9] = {
.cfg_eint = 0x3,
- .set_pull = exynos4_gpio_setpull,
- .get_pull = exynos4_gpio_getpull,
+ .set_pull = exynos_gpio_setpull,
+ .get_pull = exynos_gpio_getpull,
}
};
@@ -2113,10 +2113,10 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = {
};
/*
- * Followings are the gpio banks in EXYNOS4210
+ * Followings are the gpio banks in EXYNOS SoCs
*
* The 'config' member when left to NULL, is initialized to the default
- * structure samsung_gpio_cfgs[3] in the init function below.
+ * structure exynos_gpio_cfg in the init function below.
*
* The 'base' member is also initialized in the init function below.
* Note: The initialization of 'base' member of samsung_gpio_chip structure
@@ -2331,7 +2331,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
.label = "GPY6",
},
}, {
- .base = (S5P_VA_GPIO2 + 0xC00),
.config = &samsung_gpio_cfgs[9],
.irq_base = IRQ_EINT(0),
.chip = {
@@ -2341,7 +2340,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
.to_irq = samsung_gpiolib_to_irq,
},
}, {
- .base = (S5P_VA_GPIO2 + 0xC20),
.config = &samsung_gpio_cfgs[9],
.irq_base = IRQ_EINT(8),
.chip = {
@@ -2351,7 +2349,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
.to_irq = samsung_gpiolib_to_irq,
},
}, {
- .base = (S5P_VA_GPIO2 + 0xC40),
.config = &samsung_gpio_cfgs[9],
.irq_base = IRQ_EINT(16),
.chip = {
@@ -2361,7 +2358,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
.to_irq = samsung_gpiolib_to_irq,
},
}, {
- .base = (S5P_VA_GPIO2 + 0xC60),
.config = &samsung_gpio_cfgs[9],
.irq_base = IRQ_EINT(24),
.chip = {
@@ -2386,8 +2382,280 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = {
#endif
};
-#if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF)
-static int exynos4_gpio_xlate(struct gpio_chip *gc,
+static struct samsung_gpio_chip exynos5_gpios_1[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+ {
+ .chip = {
+ .base = EXYNOS5_GPA0(0),
+ .ngpio = EXYNOS5_GPIO_A0_NR,
+ .label = "GPA0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPA1(0),
+ .ngpio = EXYNOS5_GPIO_A1_NR,
+ .label = "GPA1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPA2(0),
+ .ngpio = EXYNOS5_GPIO_A2_NR,
+ .label = "GPA2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPB0(0),
+ .ngpio = EXYNOS5_GPIO_B0_NR,
+ .label = "GPB0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPB1(0),
+ .ngpio = EXYNOS5_GPIO_B1_NR,
+ .label = "GPB1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPB2(0),
+ .ngpio = EXYNOS5_GPIO_B2_NR,
+ .label = "GPB2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPB3(0),
+ .ngpio = EXYNOS5_GPIO_B3_NR,
+ .label = "GPB3",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPC0(0),
+ .ngpio = EXYNOS5_GPIO_C0_NR,
+ .label = "GPC0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPC1(0),
+ .ngpio = EXYNOS5_GPIO_C1_NR,
+ .label = "GPC1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPC2(0),
+ .ngpio = EXYNOS5_GPIO_C2_NR,
+ .label = "GPC2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPC3(0),
+ .ngpio = EXYNOS5_GPIO_C3_NR,
+ .label = "GPC3",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPD0(0),
+ .ngpio = EXYNOS5_GPIO_D0_NR,
+ .label = "GPD0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPD1(0),
+ .ngpio = EXYNOS5_GPIO_D1_NR,
+ .label = "GPD1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPY0(0),
+ .ngpio = EXYNOS5_GPIO_Y0_NR,
+ .label = "GPY0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPY1(0),
+ .ngpio = EXYNOS5_GPIO_Y1_NR,
+ .label = "GPY1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPY2(0),
+ .ngpio = EXYNOS5_GPIO_Y2_NR,
+ .label = "GPY2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPY3(0),
+ .ngpio = EXYNOS5_GPIO_Y3_NR,
+ .label = "GPY3",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPY4(0),
+ .ngpio = EXYNOS5_GPIO_Y4_NR,
+ .label = "GPY4",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPY5(0),
+ .ngpio = EXYNOS5_GPIO_Y5_NR,
+ .label = "GPY5",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPY6(0),
+ .ngpio = EXYNOS5_GPIO_Y6_NR,
+ .label = "GPY6",
+ },
+ }, {
+ .config = &samsung_gpio_cfgs[9],
+ .irq_base = IRQ_EINT(0),
+ .chip = {
+ .base = EXYNOS5_GPX0(0),
+ .ngpio = EXYNOS5_GPIO_X0_NR,
+ .label = "GPX0",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ }, {
+ .config = &samsung_gpio_cfgs[9],
+ .irq_base = IRQ_EINT(8),
+ .chip = {
+ .base = EXYNOS5_GPX1(0),
+ .ngpio = EXYNOS5_GPIO_X1_NR,
+ .label = "GPX1",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ }, {
+ .config = &samsung_gpio_cfgs[9],
+ .irq_base = IRQ_EINT(16),
+ .chip = {
+ .base = EXYNOS5_GPX2(0),
+ .ngpio = EXYNOS5_GPIO_X2_NR,
+ .label = "GPX2",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ }, {
+ .config = &samsung_gpio_cfgs[9],
+ .irq_base = IRQ_EINT(24),
+ .chip = {
+ .base = EXYNOS5_GPX3(0),
+ .ngpio = EXYNOS5_GPIO_X3_NR,
+ .label = "GPX3",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ },
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_2[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+ {
+ .chip = {
+ .base = EXYNOS5_GPE0(0),
+ .ngpio = EXYNOS5_GPIO_E0_NR,
+ .label = "GPE0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPE1(0),
+ .ngpio = EXYNOS5_GPIO_E1_NR,
+ .label = "GPE1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPF0(0),
+ .ngpio = EXYNOS5_GPIO_F0_NR,
+ .label = "GPF0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPF1(0),
+ .ngpio = EXYNOS5_GPIO_F1_NR,
+ .label = "GPF1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPG0(0),
+ .ngpio = EXYNOS5_GPIO_G0_NR,
+ .label = "GPG0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPG1(0),
+ .ngpio = EXYNOS5_GPIO_G1_NR,
+ .label = "GPG1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPG2(0),
+ .ngpio = EXYNOS5_GPIO_G2_NR,
+ .label = "GPG2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPH0(0),
+ .ngpio = EXYNOS5_GPIO_H0_NR,
+ .label = "GPH0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPH1(0),
+ .ngpio = EXYNOS5_GPIO_H1_NR,
+ .label = "GPH1",
+
+ },
+ },
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_3[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+ {
+ .chip = {
+ .base = EXYNOS5_GPV0(0),
+ .ngpio = EXYNOS5_GPIO_V0_NR,
+ .label = "GPV0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPV1(0),
+ .ngpio = EXYNOS5_GPIO_V1_NR,
+ .label = "GPV1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPV2(0),
+ .ngpio = EXYNOS5_GPIO_V2_NR,
+ .label = "GPV2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPV3(0),
+ .ngpio = EXYNOS5_GPIO_V3_NR,
+ .label = "GPV3",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS5_GPV4(0),
+ .ngpio = EXYNOS5_GPIO_V4_NR,
+ .label = "GPV4",
+ },
+ },
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_4[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+ {
+ .chip = {
+ .base = EXYNOS5_GPZ(0),
+ .ngpio = EXYNOS5_GPIO_Z_NR,
+ .label = "GPZ",
+ },
+ },
+#endif
+};
+
+
+#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF)
+static int exynos_gpio_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags)
{
unsigned int pin;
@@ -2413,13 +2681,13 @@ static int exynos4_gpio_xlate(struct gpio_chip *gc,
return gpiospec->args[0];
}
-static const struct of_device_id exynos4_gpio_dt_match[] __initdata = {
+static const struct of_device_id exynos_gpio_dt_match[] __initdata = {
{ .compatible = "samsung,exynos4-gpio", },
{}
};
-static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
+static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+ u64 base, u64 offset)
{
struct gpio_chip *gc = &chip->chip;
u64 address;
@@ -2429,28 +2697,29 @@ static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
gc->of_node = of_find_matching_node_by_address(NULL,
- exynos4_gpio_dt_match, address);
+ exynos_gpio_dt_match, address);
if (!gc->of_node) {
pr_info("gpio: device tree node not found for gpio controller"
" with base address %08llx\n", address);
return;
}
gc->of_gpio_n_cells = 4;
- gc->of_xlate = exynos4_gpio_xlate;
+ gc->of_xlate = exynos_gpio_xlate;
}
-#elif defined(CONFIG_ARCH_EXYNOS4)
-static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
+#elif defined(CONFIG_ARCH_EXYNOS)
+static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+ u64 base, u64 offset)
{
return;
}
-#endif /* defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) */
+#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */
/* TODO: cleanup soc_is_* */
static __init int samsung_gpiolib_init(void)
{
struct samsung_gpio_chip *chip;
int i, nr_chips;
+ void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
int group = 0;
samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs));
@@ -2516,66 +2785,200 @@ static __init int samsung_gpiolib_init(void)
s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
#endif
} else if (soc_is_exynos4210()) {
- group = 0;
+#ifdef CONFIG_CPU_EXYNOS4210
+ void __iomem *gpx_base;
/* gpio part1 */
+ gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
+ if (gpio_base1 == NULL) {
+ pr_err("unable to ioremap for gpio_base1\n");
+ goto err_ioremap1;
+ }
+
chip = exynos4_gpios_1;
nr_chips = ARRAY_SIZE(exynos4_gpios_1);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
- chip->config = &exynos4_gpio_cfg;
+ chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
-#ifdef CONFIG_CPU_EXYNOS4210
- exynos4_gpiolib_attach_ofnode(chip,
+ exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO1, i * 0x20);
-#endif
}
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1);
+ samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
+ nr_chips, gpio_base1);
/* gpio part2 */
+ gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
+ if (gpio_base2 == NULL) {
+ pr_err("unable to ioremap for gpio_base2\n");
+ goto err_ioremap2;
+ }
+
+ /* need to set base address for gpx */
+ chip = &exynos4_gpios_2[16];
+ gpx_base = gpio_base2 + 0xC00;
+ for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+ chip->base = gpx_base;
+
chip = exynos4_gpios_2;
nr_chips = ARRAY_SIZE(exynos4_gpios_2);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
- chip->config = &exynos4_gpio_cfg;
+ chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
-#ifdef CONFIG_CPU_EXYNOS4210
- exynos4_gpiolib_attach_ofnode(chip,
+ exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO2, i * 0x20);
-#endif
}
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2);
+ samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
+ nr_chips, gpio_base2);
/* gpio part3 */
+ gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
+ if (gpio_base3 == NULL) {
+ pr_err("unable to ioremap for gpio_base3\n");
+ goto err_ioremap3;
+ }
+
chip = exynos4_gpios_3;
nr_chips = ARRAY_SIZE(exynos4_gpios_3);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
- chip->config = &exynos4_gpio_cfg;
+ chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
-#ifdef CONFIG_CPU_EXYNOS4210
- exynos4_gpiolib_attach_ofnode(chip,
+ exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO3, i * 0x20);
-#endif
}
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3);
+ samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
+ nr_chips, gpio_base3);
#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
#endif
+
+#endif /* CONFIG_CPU_EXYNOS4210 */
+ } else if (soc_is_exynos5250()) {
+#ifdef CONFIG_SOC_EXYNOS5250
+ void __iomem *gpx_base;
+
+ /* gpio part1 */
+ gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
+ if (gpio_base1 == NULL) {
+ pr_err("unable to ioremap for gpio_base1\n");
+ goto err_ioremap1;
+ }
+
+ /* need to set base address for gpx */
+ chip = &exynos5_gpios_1[20];
+ gpx_base = gpio_base1 + 0xC00;
+ for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+ chip->base = gpx_base;
+
+ chip = exynos5_gpios_1;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_1);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO1, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
+ nr_chips, gpio_base1);
+
+ /* gpio part2 */
+ gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
+ if (gpio_base2 == NULL) {
+ pr_err("unable to ioremap for gpio_base2\n");
+ goto err_ioremap2;
+ }
+
+ chip = exynos5_gpios_2;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_2);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO2, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
+ nr_chips, gpio_base2);
+
+ /* gpio part3 */
+ gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
+ if (gpio_base3 == NULL) {
+ pr_err("unable to ioremap for gpio_base3\n");
+ goto err_ioremap3;
+ }
+
+ /* need to set base address for gpv */
+ exynos5_gpios_3[0].base = gpio_base3;
+ exynos5_gpios_3[1].base = gpio_base3 + 0x20;
+ exynos5_gpios_3[2].base = gpio_base3 + 0x60;
+ exynos5_gpios_3[3].base = gpio_base3 + 0x80;
+ exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
+
+ chip = exynos5_gpios_3;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_3);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO3, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
+ nr_chips, gpio_base3);
+
+ /* gpio part4 */
+ gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
+ if (gpio_base4 == NULL) {
+ pr_err("unable to ioremap for gpio_base4\n");
+ goto err_ioremap4;
+ }
+
+ chip = exynos5_gpios_4;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_4);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO4, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
+ nr_chips, gpio_base4);
+#endif /* CONFIG_SOC_EXYNOS5250 */
} else {
WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
return -ENODEV;
}
return 0;
+
+err_ioremap4:
+ iounmap(gpio_base3);
+err_ioremap3:
+ iounmap(gpio_base2);
+err_ioremap2:
+ iounmap(gpio_base1);
+err_ioremap1:
+ return -ENOMEM;
}
core_initcall(samsung_gpiolib_init);
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
new file mode 100644
index 000000000000..9ba15d31d242
--- /dev/null
+++ b/drivers/gpio/gpio-sodaville.c
@@ -0,0 +1,302 @@
+/*
+ * GPIO interface for Intel Sodaville SoCs.
+ *
+ * Copyright (c) 2010, 2011 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/basic_mmio_gpio.h>
+
+#define DRV_NAME "sdv_gpio"
+#define SDV_NUM_PUB_GPIOS 12
+#define PCI_DEVICE_ID_SDV_GPIO 0x2e67
+#define GPIO_BAR 0
+
+#define GPOUTR 0x00
+#define GPOER 0x04
+#define GPINR 0x08
+
+#define GPSTR 0x0c
+#define GPIT1R0 0x10
+#define GPIO_INT 0x14
+#define GPIT1R1 0x18
+
+#define GPMUXCTL 0x1c
+
+struct sdv_gpio_chip_data {
+ int irq_base;
+ void __iomem *gpio_pub_base;
+ struct irq_domain id;
+ struct irq_chip_generic *gc;
+ struct bgpio_chip bgpio;
+};
+
+static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct sdv_gpio_chip_data *sd = gc->private;
+ void __iomem *type_reg;
+ u32 irq_offs = d->irq - sd->irq_base;
+ u32 reg;
+
+ if (irq_offs < 8)
+ type_reg = sd->gpio_pub_base + GPIT1R0;
+ else
+ type_reg = sd->gpio_pub_base + GPIT1R1;
+
+ reg = readl(type_reg);
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ reg &= ~BIT(4 * (irq_offs % 8));
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ reg |= BIT(4 * (irq_offs % 8));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ writel(reg, type_reg);
+ return 0;
+}
+
+static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data)
+{
+ struct sdv_gpio_chip_data *sd = data;
+ u32 irq_stat = readl(sd->gpio_pub_base + GPSTR);
+
+ irq_stat &= readl(sd->gpio_pub_base + GPIO_INT);
+ if (!irq_stat)
+ return IRQ_NONE;
+
+ while (irq_stat) {
+ u32 irq_bit = __fls(irq_stat);
+
+ irq_stat &= ~BIT(irq_bit);
+ generic_handle_irq(sd->irq_base + irq_bit);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int sdv_xlate(struct irq_domain *h, struct device_node *node,
+ const u32 *intspec, u32 intsize, irq_hw_number_t *out_hwirq,
+ u32 *out_type)
+{
+ u32 line, type;
+
+ if (node != h->of_node)
+ return -EINVAL;
+
+ if (intsize < 2)
+ return -EINVAL;
+
+ line = *intspec;
+ *out_hwirq = line;
+
+ intspec++;
+ type = *intspec;
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_LOW:
+ case IRQ_TYPE_LEVEL_HIGH:
+ *out_type = type;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct irq_domain_ops irq_domain_sdv_ops = {
+ .dt_translate = sdv_xlate,
+};
+
+static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
+ struct pci_dev *pdev)
+{
+ struct irq_chip_type *ct;
+ int ret;
+
+ sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1);
+ if (sd->irq_base < 0)
+ return sd->irq_base;
+
+ /* mask + ACK all interrupt sources */
+ writel(0, sd->gpio_pub_base + GPIO_INT);
+ writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR);
+
+ ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED,
+ "sdv_gpio", sd);
+ if (ret)
+ goto out_free_desc;
+
+ sd->id.irq_base = sd->irq_base;
+ sd->id.of_node = of_node_get(pdev->dev.of_node);
+ sd->id.ops = &irq_domain_sdv_ops;
+
+ /*
+ * This gpio irq controller latches level irqs. Testing shows that if
+ * we unmask & ACK the IRQ before the source of the interrupt is gone
+ * then the interrupt is active again.
+ */
+ sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base,
+ sd->gpio_pub_base, handle_fasteoi_irq);
+ if (!sd->gc) {
+ ret = -ENOMEM;
+ goto out_free_irq;
+ }
+
+ sd->gc->private = sd;
+ ct = sd->gc->chip_types;
+ ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+ ct->regs.eoi = GPSTR;
+ ct->regs.mask = GPIO_INT;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+ ct->chip.irq_eoi = irq_gc_eoi;
+ ct->chip.irq_set_type = sdv_gpio_pub_set_type;
+
+ irq_setup_generic_chip(sd->gc, IRQ_MSK(SDV_NUM_PUB_GPIOS),
+ IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST,
+ IRQ_LEVEL | IRQ_NOPROBE);
+
+ irq_domain_add(&sd->id);
+ return 0;
+out_free_irq:
+ free_irq(pdev->irq, sd);
+out_free_desc:
+ irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+ return ret;
+}
+
+static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+{
+ struct sdv_gpio_chip_data *sd;
+ unsigned long addr;
+ const void *prop;
+ int len;
+ int ret;
+ u32 mux_val;
+
+ sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "can't enable device.\n");
+ goto done;
+ }
+
+ ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+ goto disable_pci;
+ }
+
+ addr = pci_resource_start(pdev, GPIO_BAR);
+ if (!addr)
+ goto release_reg;
+ sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR));
+
+ prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len);
+ if (prop && len == 4) {
+ mux_val = of_read_number(prop, 1);
+ writel(mux_val, sd->gpio_pub_base + GPMUXCTL);
+ }
+
+ ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
+ sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
+ NULL, sd->gpio_pub_base + GPOER, NULL, false);
+ if (ret)
+ goto unmap;
+ sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
+
+ ret = gpiochip_add(&sd->bgpio.gc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "gpiochip_add() failed.\n");
+ goto unmap;
+ }
+
+ ret = sdv_register_irqsupport(sd, pdev);
+ if (ret)
+ goto unmap;
+
+ pci_set_drvdata(pdev, sd);
+ dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n");
+ return 0;
+
+unmap:
+ iounmap(sd->gpio_pub_base);
+release_reg:
+ pci_release_region(pdev, GPIO_BAR);
+disable_pci:
+ pci_disable_device(pdev);
+done:
+ kfree(sd);
+ return ret;
+}
+
+static void sdv_gpio_remove(struct pci_dev *pdev)
+{
+ struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev);
+
+ irq_domain_del(&sd->id);
+ free_irq(pdev->irq, sd);
+ irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+
+ if (gpiochip_remove(&sd->bgpio.gc))
+ dev_err(&pdev->dev, "gpiochip_remove() failed.\n");
+
+ pci_release_region(pdev, GPIO_BAR);
+ iounmap(sd->gpio_pub_base);
+ pci_disable_device(pdev);
+ kfree(sd);
+}
+
+static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) },
+ { 0, },
+};
+
+static struct pci_driver sdv_gpio_driver = {
+ .name = DRV_NAME,
+ .id_table = sdv_gpio_pci_ids,
+ .probe = sdv_gpio_probe,
+ .remove = sdv_gpio_remove,
+};
+
+static int __init sdv_gpio_init(void)
+{
+ return pci_register_driver(&sdv_gpio_driver);
+}
+module_init(sdv_gpio_init);
+
+static void __exit sdv_gpio_exit(void)
+{
+ pci_unregister_driver(&sdv_gpio_driver);
+}
+module_exit(sdv_gpio_exit);
+
+MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>");
+MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 87a68a896abf..dce34727bbf8 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -54,7 +54,7 @@ static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
if (ret < 0)
return ret;
- return ret & mask;
+ return !!(ret & mask);
}
static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
@@ -307,13 +307,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
struct stmpe_gpio_platform_data *pdata;
struct stmpe_gpio *stmpe_gpio;
int ret;
- int irq;
+ int irq = 0;
pdata = stmpe->pdata->gpio;
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
if (!stmpe_gpio)
@@ -330,21 +328,28 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->chip.dev = &pdev->dev;
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
- stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+ if (irq >= 0)
+ stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+ else
+ dev_info(&pdev->dev,
+ "device configured in no-irq mode; "
+ "irqs are not available\n");
ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
if (ret)
goto out_free;
- ret = stmpe_gpio_irq_init(stmpe_gpio);
- if (ret)
- goto out_disable;
+ if (irq >= 0) {
+ ret = stmpe_gpio_irq_init(stmpe_gpio);
+ if (ret)
+ goto out_disable;
- ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
- "stmpe-gpio", stmpe_gpio);
- if (ret) {
- dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
- goto out_removeirq;
+ ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
+ IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+ goto out_removeirq;
+ }
}
ret = gpiochip_add(&stmpe_gpio->chip);
@@ -361,9 +366,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
return 0;
out_freeirq:
- free_irq(irq, stmpe_gpio);
+ if (irq >= 0)
+ free_irq(irq, stmpe_gpio);
out_removeirq:
- stmpe_gpio_irq_remove(stmpe_gpio);
+ if (irq >= 0)
+ stmpe_gpio_irq_remove(stmpe_gpio);
out_disable:
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
out_free:
@@ -391,8 +398,10 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
- free_irq(irq, stmpe_gpio);
- stmpe_gpio_irq_remove(stmpe_gpio);
+ if (irq >= 0) {
+ free_irq(irq, stmpe_gpio);
+ stmpe_gpio_irq_remove(stmpe_gpio);
+ }
platform_set_drvdata(pdev, NULL);
kfree(stmpe_gpio);
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 6f17671260e1..32de6707e3c4 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -109,11 +109,13 @@ void tegra_gpio_enable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
}
+EXPORT_SYMBOL_GPL(tegra_gpio_enable);
void tegra_gpio_disable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
}
+EXPORT_SYMBOL_GPL(tegra_gpio_disable);
static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
@@ -459,7 +461,7 @@ static int __init tegra_gpio_init(void)
}
postcore_initcall(tegra_gpio_init);
-void __init tegra_gpio_config(struct tegra_gpio_table *table, int num)
+void tegra_gpio_config(struct tegra_gpio_table *table, int num)
{
int i;
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 91f45b965d1e..7eef648a3351 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -69,6 +69,7 @@ static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
{
int ret;
+ struct tps65910_board *board_data;
if (!gpio_base)
return;
@@ -80,10 +81,10 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
switch(tps65910_chip_id(tps65910)) {
case TPS65910:
- tps65910->gpio.ngpio = 6;
+ tps65910->gpio.ngpio = TPS65910_NUM_GPIO;
break;
case TPS65911:
- tps65910->gpio.ngpio = 9;
+ tps65910->gpio.ngpio = TPS65911_NUM_GPIO;
break;
default:
return;
@@ -95,6 +96,21 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
tps65910->gpio.set = tps65910_gpio_set;
tps65910->gpio.get = tps65910_gpio_get;
+ /* Configure sleep control for gpios */
+ board_data = dev_get_platdata(tps65910->dev);
+ if (board_data) {
+ int i;
+ for (i = 0; i < tps65910->gpio.ngpio; ++i) {
+ if (board_data->en_gpio_sleep[i]) {
+ ret = tps65910_set_bits(tps65910,
+ TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
+ if (ret < 0)
+ dev_warn(tps65910->dev,
+ "GPIO Sleep setting failed\n");
+ }
+ }
+ }
+
ret = gpiochip_add(&tps65910->gpio);
if (ret)
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index b8b4f228757c..94256fe7bf36 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -32,6 +32,8 @@
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
#include <linux/i2c/twl.h>
@@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
* and vMMC2 power supplies based on card presence.
*/
pdata = chip->dev->platform_data;
- value |= pdata->mmc_cd & 0x03;
+ if (pdata)
+ value |= pdata->mmc_cd & 0x03;
status = gpio_twl4030_write(REG_GPIO_CTRL, value);
}
@@ -395,59 +398,70 @@ static int gpio_twl4030_remove(struct platform_device *pdev);
static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
{
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
- int ret;
+ struct device_node *node = pdev->dev.of_node;
+ int ret, irq_base;
/* maybe setup IRQs */
- if (pdata->irq_base) {
- if (is_module()) {
- dev_err(&pdev->dev,
- "can't dispatch IRQs from modules\n");
- goto no_irqs;
- }
- ret = twl4030_sih_setup(TWL4030_MODULE_GPIO);
- if (ret < 0)
- return ret;
- WARN_ON(ret != pdata->irq_base);
- twl4030_gpio_irq_base = ret;
+ if (is_module()) {
+ dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
+ goto no_irqs;
+ }
+
+ irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0);
+ if (irq_base < 0) {
+ dev_err(&pdev->dev, "Failed to alloc irq_descs\n");
+ return irq_base;
}
+ irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0,
+ &irq_domain_simple_ops, NULL);
+
+ ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base);
+ if (ret < 0)
+ return ret;
+
+ twl4030_gpio_irq_base = irq_base;
+
no_irqs:
- /*
- * NOTE: boards may waste power if they don't set pullups
- * and pulldowns correctly ... default for non-ULPI pins is
- * pulldown, and some other pins may have external pullups
- * or pulldowns. Careful!
- */
- ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
- if (ret)
- dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
- pdata->pullups, pdata->pulldowns,
- ret);
-
- ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
- if (ret)
- dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
- pdata->debounce, pdata->mmc_cd,
- ret);
-
- twl_gpiochip.base = pdata->gpio_base;
+ twl_gpiochip.base = -1;
twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
twl_gpiochip.dev = &pdev->dev;
- /* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
- * is (still) clear if use_leds is set.
- */
- if (pdata->use_leds)
- twl_gpiochip.ngpio += 2;
+ if (pdata) {
+ twl_gpiochip.base = pdata->gpio_base;
+
+ /*
+ * NOTE: boards may waste power if they don't set pullups
+ * and pulldowns correctly ... default for non-ULPI pins is
+ * pulldown, and some other pins may have external pullups
+ * or pulldowns. Careful!
+ */
+ ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+ if (ret)
+ dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+ pdata->pullups, pdata->pulldowns,
+ ret);
+
+ ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
+ if (ret)
+ dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
+ pdata->debounce, pdata->mmc_cd,
+ ret);
+
+ /*
+ * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
+ * is (still) clear if use_leds is set.
+ */
+ if (pdata->use_leds)
+ twl_gpiochip.ngpio += 2;
+ }
ret = gpiochip_add(&twl_gpiochip);
if (ret < 0) {
- dev_err(&pdev->dev,
- "could not register gpiochip, %d\n",
- ret);
+ dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
twl_gpiochip.ngpio = 0;
gpio_twl4030_remove(pdev);
- } else if (pdata->setup) {
+ } else if (pdata && pdata->setup) {
int status;
status = pdata->setup(&pdev->dev,
@@ -465,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
int status;
- if (pdata->teardown) {
+ if (pdata && pdata->teardown) {
status = pdata->teardown(&pdev->dev,
pdata->gpio_base, TWL4030_GPIO_MAX);
if (status) {
@@ -486,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
return -EIO;
}
+static const struct of_device_id twl_gpio_match[] = {
+ { .compatible = "ti,twl4030-gpio", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, twl_gpio_match);
+
/* Note: this hardware lives inside an I2C-based multi-function device. */
MODULE_ALIAS("platform:twl4030_gpio");
static struct platform_driver gpio_twl4030_driver = {
- .driver.name = "twl4030_gpio",
- .driver.owner = THIS_MODULE,
+ .driver = {
+ .name = "twl4030_gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(twl_gpio_match),
+ },
.probe = gpio_twl4030_probe,
.remove = gpio_twl4030_remove,
};
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 17fdf4b6af93..5a75510d66bb 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -58,6 +58,8 @@ struct gpio_desc {
#define FLAG_TRIG_FALL 5 /* trigger on falling edge */
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
+#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
+#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
#define ID_SHIFT 16 /* add new flags before this one */
@@ -873,6 +875,7 @@ void gpio_unexport(unsigned gpio)
{
struct gpio_desc *desc;
int status = 0;
+ struct device *dev = NULL;
if (!gpio_is_valid(gpio)) {
status = -EINVAL;
@@ -884,19 +887,20 @@ void gpio_unexport(unsigned gpio)
desc = &gpio_desc[gpio];
if (test_bit(FLAG_EXPORT, &desc->flags)) {
- struct device *dev = NULL;
dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev) {
gpio_setup_irq(desc, dev, 0);
clear_bit(FLAG_EXPORT, &desc->flags);
- put_device(dev);
- device_unregister(dev);
} else
status = -ENODEV;
}
mutex_unlock(&sysfs_lock);
+ if (dev) {
+ device_unregister(dev);
+ put_device(dev);
+ }
done:
if (status)
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
@@ -1150,8 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
* non-zero, this function will return to the caller and not iterate over any
* more gpio_chips.
*/
-struct gpio_chip *gpiochip_find(void *data,
- int (*match)(struct gpio_chip *chip, void *data))
+struct gpio_chip *gpiochip_find(const void *data,
+ int (*match)(struct gpio_chip *chip,
+ const void *data))
{
struct gpio_chip *chip = NULL;
unsigned long flags;
@@ -1261,6 +1266,8 @@ void gpio_free(unsigned gpio)
module_put(desc->chip->owner);
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
+ clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
+ clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
} else
WARN_ON(extra_checks);
@@ -1282,6 +1289,12 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (err)
return err;
+ if (flags & GPIOF_OPEN_DRAIN)
+ set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags);
+
+ if (flags & GPIOF_OPEN_SOURCE)
+ set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);
+
if (flags & GPIOF_DIR_IN)
err = gpio_direction_input(gpio);
else
@@ -1431,6 +1444,14 @@ int gpio_direction_output(unsigned gpio, int value)
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
+ /* Open drain pin should not be driven to 1 */
+ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags))
+ return gpio_direction_input(gpio);
+
+ /* Open source pin should not be driven to 0 */
+ if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags))
+ return gpio_direction_input(gpio);
+
spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio))
@@ -1560,6 +1581,7 @@ int __gpio_get_value(unsigned gpio)
int value;
chip = gpio_to_chip(gpio);
+ /* Should be using gpio_get_value_cansleep() */
WARN_ON(chip->can_sleep);
value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
trace_gpio_value(gpio, 1, value);
@@ -1567,6 +1589,57 @@ int __gpio_get_value(unsigned gpio)
}
EXPORT_SYMBOL_GPL(__gpio_get_value);
+/*
+ * _gpio_set_open_drain_value() - Set the open drain gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_drain_value(unsigned gpio,
+ struct gpio_chip *chip, int value)
+{
+ int err = 0;
+ if (value) {
+ err = chip->direction_input(chip, gpio - chip->base);
+ if (!err)
+ clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ } else {
+ err = chip->direction_output(chip, gpio - chip->base, 0);
+ if (!err)
+ set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ }
+ trace_gpio_direction(gpio, value, err);
+ if (err < 0)
+ pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
+ __func__, gpio, err);
+}
+
+/*
+ * _gpio_set_open_source() - Set the open source gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_source_value(unsigned gpio,
+ struct gpio_chip *chip, int value)
+{
+ int err = 0;
+ if (value) {
+ err = chip->direction_output(chip, gpio - chip->base, 1);
+ if (!err)
+ set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ } else {
+ err = chip->direction_input(chip, gpio - chip->base);
+ if (!err)
+ clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ }
+ trace_gpio_direction(gpio, !value, err);
+ if (err < 0)
+ pr_err("%s: Error in set_value for open source gpio%d err %d\n",
+ __func__, gpio, err);
+}
+
+
/**
* __gpio_set_value() - assign a gpio's value
* @gpio: gpio whose value will be assigned
@@ -1581,9 +1654,15 @@ void __gpio_set_value(unsigned gpio, int value)
struct gpio_chip *chip;
chip = gpio_to_chip(gpio);
+ /* Should be using gpio_set_value_cansleep() */
WARN_ON(chip->can_sleep);
trace_gpio_value(gpio, 0, value);
- chip->set(chip, gpio - chip->base, value);
+ if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags))
+ _gpio_set_open_drain_value(gpio, chip, value);
+ else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags))
+ _gpio_set_open_source_value(gpio, chip, value);
+ else
+ chip->set(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL_GPL(__gpio_set_value);
@@ -1650,7 +1729,12 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio);
trace_gpio_value(gpio, 0, value);
- chip->set(chip, gpio - chip->base, value);
+ if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags))
+ _gpio_set_open_drain_value(gpio, chip, value);
+ else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags))
+ _gpio_set_open_source_value(gpio, chip, value);
+ else
+ chip->set(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
index 4c2cb4a8ad98..5675d93b4205 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -244,7 +244,6 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
uint64_t value)
{
struct drm_encoder *encoder = connector->encoder;
- struct backlight_device *psb_bd;
if (!strcmp(property->name, "scaling mode") && encoder) {
struct psb_intel_crtc *psb_crtc =
@@ -301,11 +300,15 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
value))
goto set_prop_error;
else {
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+ struct backlight_device *psb_bd;
+
psb_bd = mdfld_get_backlight_device();
if (psb_bd) {
psb_bd->props.brightness = value;
mdfld_set_brightness(psb_bd);
}
+#endif
}
}
set_prop_done:
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 0694e170a338..1a7559b59997 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -467,6 +467,10 @@ static int i915_drm_freeze(struct drm_device *dev)
/* Modeset on resume, not lid events */
dev_priv->modeset_on_lid = 0;
+ console_lock();
+ intel_fbdev_set_suspend(dev, 1);
+ console_unlock();
+
return 0;
}
@@ -539,6 +543,9 @@ static int i915_drm_thaw(struct drm_device *dev)
dev_priv->modeset_on_lid = 0;
+ console_lock();
+ intel_fbdev_set_suspend(dev, 0);
+ console_unlock();
return error;
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9cec6c3937fa..5a14149b3794 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -382,7 +382,7 @@ extern int intel_framebuffer_init(struct drm_device *dev,
struct drm_i915_gem_object *obj);
extern int intel_fbdev_init(struct drm_device *dev);
extern void intel_fbdev_fini(struct drm_device *dev);
-
+extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 2d8766978388..19ecd78b8a2c 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -254,6 +254,16 @@ void intel_fbdev_fini(struct drm_device *dev)
kfree(dev_priv->fbdev);
dev_priv->fbdev = NULL;
}
+
+void intel_fbdev_set_suspend(struct drm_device *dev, int state)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ if (!dev_priv->fbdev)
+ return;
+
+ fb_set_suspend(dev_priv->fbdev->helper.fbdev, state);
+}
+
MODULE_LICENSE("GPL and additional rights");
void intel_fb_output_poll_changed(struct drm_device *dev)
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 8f510fd956b0..fa860358add1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -654,10 +654,13 @@ nouveau_connector_detect_depth(struct drm_connector *connector)
if (nv_connector->edid && connector->display_info.bpc)
return;
- /* if not, we're out of options unless we're LVDS, default to 6bpc */
- connector->display_info.bpc = 6;
- if (nv_encoder->dcb->type != OUTPUT_LVDS)
+ /* if not, we're out of options unless we're LVDS, default to 8bpc */
+ if (nv_encoder->dcb->type != OUTPUT_LVDS) {
+ connector->display_info.bpc = 8;
return;
+ }
+
+ connector->display_info.bpc = 6;
/* LVDS: panel straps */
if (bios->fp_no_ddc) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 8f4f914d9eab..e2be95af2e52 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -315,8 +315,8 @@ nouveau_i2c_init(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
struct nouveau_i2c_chan *port;
+ u8 version = 0x00, entries, recordlen;
u8 *i2c, *entry, legacy[2][4] = {};
- u8 version, entries, recordlen;
int ret, i;
INIT_LIST_HEAD(&dev_priv->i2c_ports);
@@ -346,12 +346,12 @@ nouveau_i2c_init(struct drm_device *dev)
if (i2c[7]) legacy[1][1] = i2c[7];
}
- if (i2c && version >= 0x30) {
+ if (version >= 0x30) {
entry = i2c[1] + i2c;
entries = i2c[2];
recordlen = i2c[3];
} else
- if (i2c) {
+ if (version) {
entry = i2c;
entries = 16;
recordlen = 4;
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index a3ae91fa8141..a4886b36d0fa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -852,7 +852,7 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_pm;
- if (!dev_priv->noaccel) {
+ if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
ret = nouveau_card_channel_init(dev);
if (ret)
goto out_fence;
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 083b3eada001..b5ff1f7b6f7e 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -588,8 +588,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
if (encoder->crtc == crtc) {
radeon_encoder = to_radeon_encoder(encoder);
connector = radeon_get_connector_for_encoder(encoder);
- if (connector && connector->display_info.bpc)
- bpc = connector->display_info.bpc;
+ /* if (connector && connector->display_info.bpc)
+ bpc = connector->display_info.bpc; */
encoder_mode = atombios_get_encoder_mode(encoder);
is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
@@ -965,7 +965,9 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
struct radeon_connector_atom_dig *dig_connector =
radeon_connector->con_priv;
int dp_clock;
- bpc = connector->display_info.bpc;
+
+ /* if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc; */
switch (encoder_mode) {
case ATOM_ENCODER_MODE_DP_MST:
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 6c62be226804..c57d85664e77 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -405,10 +405,13 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
/* get bpc from the EDID */
static int convert_bpc_to_bpp(int bpc)
{
+#if 0
if (bpc == 0)
return 24;
else
return bpc * 3;
+#endif
+ return 24;
}
/* get the max pix clock supported by the link rate and lane num */
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 468b874336f9..e607c4d7dd98 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -541,7 +541,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
dp_clock = dig_connector->dp_clock;
dp_lane_count = dig_connector->dp_lane_count;
hpd_id = radeon_connector->hpd.hpd;
- bpc = connector->display_info.bpc;
+ /* bpc = connector->display_info.bpc; */
}
/* no dig encoder assigned */
@@ -1159,7 +1159,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
dp_lane_count = dig_connector->dp_lane_count;
connector_object_id =
(radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
- bpc = connector->display_info.bpc;
+ /* bpc = connector->display_info.bpc; */
}
memset(&args, 0, sizeof(args));
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index a58b37a2e65a..70089d32b80f 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -80,6 +80,9 @@ struct evergreen_cs_track {
bool cb_dirty;
bool db_dirty;
bool streamout_dirty;
+ u32 htile_offset;
+ u32 htile_surface;
+ struct radeon_bo *htile_bo;
};
static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@@ -144,6 +147,9 @@ static void evergreen_cs_track_init(struct evergreen_cs_track *track)
track->db_s_read_bo = NULL;
track->db_s_write_bo = NULL;
track->db_dirty = true;
+ track->htile_bo = NULL;
+ track->htile_offset = 0xFFFFFFFF;
+ track->htile_surface = 0;
for (i = 0; i < 4; i++) {
track->vgt_strmout_size[i] = 0;
@@ -444,6 +450,62 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i
return 0;
}
+static int evergreen_cs_track_validate_htile(struct radeon_cs_parser *p,
+ unsigned nbx, unsigned nby)
+{
+ struct evergreen_cs_track *track = p->track;
+ unsigned long size;
+
+ if (track->htile_bo == NULL) {
+ dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
+ __func__, __LINE__, track->db_z_info);
+ return -EINVAL;
+ }
+
+ if (G_028ABC_LINEAR(track->htile_surface)) {
+ /* pitch must be 16 htiles aligned == 16 * 8 pixel aligned */
+ nbx = round_up(nbx, 16 * 8);
+ /* height is npipes htiles aligned == npipes * 8 pixel aligned */
+ nby = round_up(nby, track->npipes * 8);
+ } else {
+ switch (track->npipes) {
+ case 8:
+ nbx = round_up(nbx, 64 * 8);
+ nby = round_up(nby, 64 * 8);
+ break;
+ case 4:
+ nbx = round_up(nbx, 64 * 8);
+ nby = round_up(nby, 32 * 8);
+ break;
+ case 2:
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 32 * 8);
+ break;
+ case 1:
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 16 * 8);
+ break;
+ default:
+ dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
+ __func__, __LINE__, track->npipes);
+ return -EINVAL;
+ }
+ }
+ /* compute number of htile */
+ nbx = nbx / 8;
+ nby = nby / 8;
+ size = nbx * nby * 4;
+ size += track->htile_offset;
+
+ if (size > radeon_bo_size(track->htile_bo)) {
+ dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
+ __func__, __LINE__, radeon_bo_size(track->htile_bo),
+ size, nbx, nby);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
{
struct evergreen_cs_track *track = p->track;
@@ -530,6 +592,14 @@ static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
return -EINVAL;
}
+ /* hyperz */
+ if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
+ r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
+ if (r) {
+ return r;
+ }
+ }
+
return 0;
}
@@ -617,6 +687,14 @@ static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p)
return -EINVAL;
}
+ /* hyperz */
+ if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
+ r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
+ if (r) {
+ return r;
+ }
+ }
+
return 0;
}
@@ -850,7 +928,7 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)
return r;
}
/* Check depth buffer */
- if (G_028800_Z_WRITE_ENABLE(track->db_depth_control)) {
+ if (G_028800_Z_ENABLE(track->db_depth_control)) {
r = evergreen_cs_track_validate_depth(p);
if (r)
return r;
@@ -1616,6 +1694,23 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
track->cb_color_bo[tmp] = reloc->robj;
track->cb_dirty = true;
break;
+ case DB_HTILE_DATA_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->htile_offset = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->htile_bo = reloc->robj;
+ track->db_dirty = true;
+ break;
+ case DB_HTILE_SURFACE:
+ /* 8x8 only */
+ track->htile_surface = radeon_get_ib_value(p, idx);
+ track->db_dirty = true;
+ break;
case CB_IMMED0_BASE:
case CB_IMMED1_BASE:
case CB_IMMED2_BASE:
@@ -1628,7 +1723,6 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
case CB_IMMED9_BASE:
case CB_IMMED10_BASE:
case CB_IMMED11_BASE:
- case DB_HTILE_DATA_BASE:
case SQ_PGM_START_FS:
case SQ_PGM_START_ES:
case SQ_PGM_START_VS:
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index eb5708c7159d..b4eefc355f16 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -991,6 +991,14 @@
#define G_028008_SLICE_MAX(x) (((x) >> 13) & 0x7FF)
#define C_028008_SLICE_MAX 0xFF001FFF
#define DB_HTILE_DATA_BASE 0x28014
+#define DB_HTILE_SURFACE 0x28abc
+#define S_028ABC_HTILE_WIDTH(x) (((x) & 0x1) << 0)
+#define G_028ABC_HTILE_WIDTH(x) (((x) >> 0) & 0x1)
+#define C_028ABC_HTILE_WIDTH 0xFFFFFFFE
+#define S_028ABC_HTILE_HEIGHT(x) (((x) & 0x1) << 1)
+#define G_028ABC_HTILE_HEIGHT(x) (((x) >> 1) & 0x1)
+#define C_028ABC_HTILE_HEIGHT 0xFFFFFFFD
+#define G_028ABC_LINEAR(x) (((x) >> 2) & 0x1)
#define DB_Z_INFO 0x28040
# define Z_ARRAY_MODE(x) ((x) << 4)
# define DB_TILE_SPLIT(x) (((x) & 0x7) << 8)
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 0ec3f205f9c4..b8e12af304a9 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -78,6 +78,9 @@ struct r600_cs_track {
bool cb_dirty;
bool db_dirty;
bool streamout_dirty;
+ struct radeon_bo *htile_bo;
+ u64 htile_offset;
+ u32 htile_surface;
};
#define FMT_8_BIT(fmt, vc) [fmt] = { 1, 1, 1, vc, CHIP_R600 }
@@ -321,6 +324,9 @@ static void r600_cs_track_init(struct r600_cs_track *track)
track->db_depth_size_idx = 0;
track->db_depth_control = 0xFFFFFFFF;
track->db_dirty = true;
+ track->htile_bo = NULL;
+ track->htile_offset = 0xFFFFFFFF;
+ track->htile_surface = 0;
for (i = 0; i < 4; i++) {
track->vgt_strmout_size[i] = 0;
@@ -455,12 +461,256 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
return 0;
}
+static int r600_cs_track_validate_db(struct radeon_cs_parser *p)
+{
+ struct r600_cs_track *track = p->track;
+ u32 nviews, bpe, ntiles, size, slice_tile_max, tmp;
+ u32 height_align, pitch_align, depth_align;
+ u32 pitch = 8192;
+ u32 height = 8192;
+ u64 base_offset, base_align;
+ struct array_mode_checker array_check;
+ int array_mode;
+ volatile u32 *ib = p->ib->ptr;
+
+
+ if (track->db_bo == NULL) {
+ dev_warn(p->dev, "z/stencil with no depth buffer\n");
+ return -EINVAL;
+ }
+ switch (G_028010_FORMAT(track->db_depth_info)) {
+ case V_028010_DEPTH_16:
+ bpe = 2;
+ break;
+ case V_028010_DEPTH_X8_24:
+ case V_028010_DEPTH_8_24:
+ case V_028010_DEPTH_X8_24_FLOAT:
+ case V_028010_DEPTH_8_24_FLOAT:
+ case V_028010_DEPTH_32_FLOAT:
+ bpe = 4;
+ break;
+ case V_028010_DEPTH_X24_8_32_FLOAT:
+ bpe = 8;
+ break;
+ default:
+ dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
+ return -EINVAL;
+ }
+ if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
+ if (!track->db_depth_size_idx) {
+ dev_warn(p->dev, "z/stencil buffer size not set\n");
+ return -EINVAL;
+ }
+ tmp = radeon_bo_size(track->db_bo) - track->db_offset;
+ tmp = (tmp / bpe) >> 6;
+ if (!tmp) {
+ dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
+ track->db_depth_size, bpe, track->db_offset,
+ radeon_bo_size(track->db_bo));
+ return -EINVAL;
+ }
+ ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
+ } else {
+ size = radeon_bo_size(track->db_bo);
+ /* pitch in pixels */
+ pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
+ slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+ slice_tile_max *= 64;
+ height = slice_tile_max / pitch;
+ if (height > 8192)
+ height = 8192;
+ base_offset = track->db_bo_mc + track->db_offset;
+ array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
+ array_check.array_mode = array_mode;
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = track->nsamples;
+ array_check.blocksize = bpe;
+ if (r600_get_array_mode_alignment(&array_check,
+ &pitch_align, &height_align, &depth_align, &base_align)) {
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+ G_028010_ARRAY_MODE(track->db_depth_info),
+ track->db_depth_info);
+ return -EINVAL;
+ }
+ switch (array_mode) {
+ case V_028010_ARRAY_1D_TILED_THIN1:
+ /* don't break userspace */
+ height &= ~0x7;
+ break;
+ case V_028010_ARRAY_2D_TILED_THIN1:
+ break;
+ default:
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+ G_028010_ARRAY_MODE(track->db_depth_info),
+ track->db_depth_info);
+ return -EINVAL;
+ }
+
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
+ __func__, __LINE__, pitch, pitch_align, array_mode);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(height, height_align)) {
+ dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
+ __func__, __LINE__, height, height_align, array_mode);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(base_offset, base_align)) {
+ dev_warn(p->dev, "%s offset 0x%llx, 0x%llx, %d not aligned\n", __func__,
+ base_offset, base_align, array_mode);
+ return -EINVAL;
+ }
+
+ ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+ nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
+ tmp = ntiles * bpe * 64 * nviews;
+ if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
+ dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
+ array_mode,
+ track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
+ radeon_bo_size(track->db_bo));
+ return -EINVAL;
+ }
+ }
+
+ /* hyperz */
+ if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
+ unsigned long size;
+ unsigned nbx, nby;
+
+ if (track->htile_bo == NULL) {
+ dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
+ __func__, __LINE__, track->db_depth_info);
+ return -EINVAL;
+ }
+ if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
+ dev_warn(p->dev, "%s:%d htile can't be enabled with bogus db_depth_size 0x%08x\n",
+ __func__, __LINE__, track->db_depth_size);
+ return -EINVAL;
+ }
+
+ nbx = pitch;
+ nby = height;
+ if (G_028D24_LINEAR(track->htile_surface)) {
+ /* nbx must be 16 htiles aligned == 16 * 8 pixel aligned */
+ nbx = round_up(nbx, 16 * 8);
+ /* nby is npipes htiles aligned == npipes * 8 pixel aligned */
+ nby = round_up(nby, track->npipes * 8);
+ } else {
+ /* htile widht & nby (8 or 4) make 2 bits number */
+ tmp = track->htile_surface & 3;
+ /* align is htile align * 8, htile align vary according to
+ * number of pipe and tile width and nby
+ */
+ switch (track->npipes) {
+ case 8:
+ switch (tmp) {
+ case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+ nbx = round_up(nbx, 64 * 8);
+ nby = round_up(nby, 64 * 8);
+ break;
+ case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+ case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 64 * 8);
+ nby = round_up(nby, 32 * 8);
+ break;
+ case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 32 * 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 4:
+ switch (tmp) {
+ case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+ nbx = round_up(nbx, 64 * 8);
+ nby = round_up(nby, 32 * 8);
+ break;
+ case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+ case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 32 * 8);
+ break;
+ case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 16 * 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ switch (tmp) {
+ case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 32 * 8);
+ break;
+ case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+ case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 16 * 8);
+ break;
+ case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 16 * 8);
+ nby = round_up(nby, 16 * 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 1:
+ switch (tmp) {
+ case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+ nbx = round_up(nbx, 32 * 8);
+ nby = round_up(nby, 16 * 8);
+ break;
+ case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+ case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 16 * 8);
+ nby = round_up(nby, 16 * 8);
+ break;
+ case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+ nbx = round_up(nbx, 16 * 8);
+ nby = round_up(nby, 8 * 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
+ __func__, __LINE__, track->npipes);
+ return -EINVAL;
+ }
+ }
+ /* compute number of htile */
+ nbx = G_028D24_HTILE_WIDTH(track->htile_surface) ? nbx / 8 : nbx / 4;
+ nby = G_028D24_HTILE_HEIGHT(track->htile_surface) ? nby / 8 : nby / 4;
+ size = nbx * nby * 4;
+ size += track->htile_offset;
+
+ if (size > radeon_bo_size(track->htile_bo)) {
+ dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
+ __func__, __LINE__, radeon_bo_size(track->htile_bo),
+ size, nbx, nby);
+ return -EINVAL;
+ }
+ }
+
+ track->db_dirty = false;
+ return 0;
+}
+
static int r600_cs_track_check(struct radeon_cs_parser *p)
{
struct r600_cs_track *track = p->track;
u32 tmp;
int r, i;
- volatile u32 *ib = p->ib->ptr;
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
@@ -513,124 +763,14 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
track->cb_dirty = false;
}
- if (track->db_dirty) {
- /* Check depth buffer */
- if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
- G_028800_Z_ENABLE(track->db_depth_control)) {
- u32 nviews, bpe, ntiles, size, slice_tile_max;
- u32 height, height_align, pitch, pitch_align, depth_align;
- u64 base_offset, base_align;
- struct array_mode_checker array_check;
- int array_mode;
-
- if (track->db_bo == NULL) {
- dev_warn(p->dev, "z/stencil with no depth buffer\n");
- return -EINVAL;
- }
- if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
- dev_warn(p->dev, "this kernel doesn't support z/stencil htile\n");
- return -EINVAL;
- }
- switch (G_028010_FORMAT(track->db_depth_info)) {
- case V_028010_DEPTH_16:
- bpe = 2;
- break;
- case V_028010_DEPTH_X8_24:
- case V_028010_DEPTH_8_24:
- case V_028010_DEPTH_X8_24_FLOAT:
- case V_028010_DEPTH_8_24_FLOAT:
- case V_028010_DEPTH_32_FLOAT:
- bpe = 4;
- break;
- case V_028010_DEPTH_X24_8_32_FLOAT:
- bpe = 8;
- break;
- default:
- dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
- return -EINVAL;
- }
- if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
- if (!track->db_depth_size_idx) {
- dev_warn(p->dev, "z/stencil buffer size not set\n");
- return -EINVAL;
- }
- tmp = radeon_bo_size(track->db_bo) - track->db_offset;
- tmp = (tmp / bpe) >> 6;
- if (!tmp) {
- dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
- track->db_depth_size, bpe, track->db_offset,
- radeon_bo_size(track->db_bo));
- return -EINVAL;
- }
- ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
- } else {
- size = radeon_bo_size(track->db_bo);
- /* pitch in pixels */
- pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
- slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
- slice_tile_max *= 64;
- height = slice_tile_max / pitch;
- if (height > 8192)
- height = 8192;
- base_offset = track->db_bo_mc + track->db_offset;
- array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
- array_check.array_mode = array_mode;
- array_check.group_size = track->group_size;
- array_check.nbanks = track->nbanks;
- array_check.npipes = track->npipes;
- array_check.nsamples = track->nsamples;
- array_check.blocksize = bpe;
- if (r600_get_array_mode_alignment(&array_check,
- &pitch_align, &height_align, &depth_align, &base_align)) {
- dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
- G_028010_ARRAY_MODE(track->db_depth_info),
- track->db_depth_info);
- return -EINVAL;
- }
- switch (array_mode) {
- case V_028010_ARRAY_1D_TILED_THIN1:
- /* don't break userspace */
- height &= ~0x7;
- break;
- case V_028010_ARRAY_2D_TILED_THIN1:
- break;
- default:
- dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
- G_028010_ARRAY_MODE(track->db_depth_info),
- track->db_depth_info);
- return -EINVAL;
- }
-
- if (!IS_ALIGNED(pitch, pitch_align)) {
- dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
- __func__, __LINE__, pitch, pitch_align, array_mode);
- return -EINVAL;
- }
- if (!IS_ALIGNED(height, height_align)) {
- dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
- __func__, __LINE__, height, height_align, array_mode);
- return -EINVAL;
- }
- if (!IS_ALIGNED(base_offset, base_align)) {
- dev_warn(p->dev, "%s offset[%d] 0x%llx, 0x%llx, %d not aligned\n", __func__, i,
- base_offset, base_align, array_mode);
- return -EINVAL;
- }
-
- ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
- nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
- tmp = ntiles * bpe * 64 * nviews;
- if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
- dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
- array_mode,
- track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
- radeon_bo_size(track->db_bo));
- return -EINVAL;
- }
- }
- }
- track->db_dirty = false;
+ /* Check depth buffer */
+ if (track->db_dirty && (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
+ G_028800_Z_ENABLE(track->db_depth_control))) {
+ r = r600_cs_track_validate_db(p);
+ if (r)
+ return r;
}
+
return 0;
}
@@ -1244,6 +1384,21 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
track->db_dirty = true;
break;
case DB_HTILE_DATA_BASE:
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->htile_offset = radeon_get_ib_value(p, idx) << 8;
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->htile_bo = reloc->robj;
+ track->db_dirty = true;
+ break;
+ case DB_HTILE_SURFACE:
+ track->htile_surface = radeon_get_ib_value(p, idx);
+ track->db_dirty = true;
+ break;
case SQ_PGM_START_FS:
case SQ_PGM_START_ES:
case SQ_PGM_START_VS:
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 3568a2e345fa..59f9c993cc31 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -195,6 +195,14 @@
#define PREZ_MUST_WAIT_FOR_POSTZ_DONE (1 << 31)
#define DB_DEPTH_BASE 0x2800C
#define DB_HTILE_DATA_BASE 0x28014
+#define DB_HTILE_SURFACE 0x28D24
+#define S_028D24_HTILE_WIDTH(x) (((x) & 0x1) << 0)
+#define G_028D24_HTILE_WIDTH(x) (((x) >> 0) & 0x1)
+#define C_028D24_HTILE_WIDTH 0xFFFFFFFE
+#define S_028D24_HTILE_HEIGHT(x) (((x) & 0x1) << 1)
+#define G_028D24_HTILE_HEIGHT(x) (((x) >> 1) & 0x1)
+#define C_028D24_HTILE_HEIGHT 0xFFFFFFFD
+#define G_028D24_LINEAR(x) (((x) >> 2) & 0x1)
#define DB_WATERMARKS 0x9838
#define DEPTH_FREE(x) ((x) << 0)
#define DEPTH_FLUSH(x) ((x) << 5)
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 91541e63d582..6f70158d34e4 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -233,7 +233,17 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
bo->pin_count++;
if (gpu_addr)
*gpu_addr = radeon_bo_gpu_offset(bo);
- WARN_ON_ONCE(max_offset != 0);
+
+ if (max_offset != 0) {
+ u64 domain_start;
+
+ if (domain == RADEON_GEM_DOMAIN_VRAM)
+ domain_start = bo->rdev->mc.vram_start;
+ else
+ domain_start = bo->rdev->mc.gtt_start;
+ WARN_ON_ONCE((*gpu_addr - domain_start) > max_offset);
+ }
+
return 0;
}
radeon_ttm_placement_from_domain(bo, domain);
diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman
index aea63c415852..0f656b111c15 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/cayman
+++ b/drivers/gpu/drm/radeon/reg_srcs/cayman
@@ -509,7 +509,6 @@ cayman 0x9400
0x00028AA8 IA_MULTI_VGT_PARAM
0x00028AB4 VGT_REUSE_OFF
0x00028AB8 VGT_VTX_CNT_EN
-0x00028ABC DB_HTILE_SURFACE
0x00028AC0 DB_SRESULTS_COMPARE_STATE0
0x00028AC4 DB_SRESULTS_COMPARE_STATE1
0x00028AC8 DB_PRELOAD_CONTROL
diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen
index 77c37202376f..b912a37689bf 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/evergreen
+++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen
@@ -519,7 +519,6 @@ evergreen 0x9400
0x00028AA4 VGT_INSTANCE_STEP_RATE_1
0x00028AB4 VGT_REUSE_OFF
0x00028AB8 VGT_VTX_CNT_EN
-0x00028ABC DB_HTILE_SURFACE
0x00028AC0 DB_SRESULTS_COMPARE_STATE0
0x00028AC4 DB_SRESULTS_COMPARE_STATE1
0x00028AC8 DB_PRELOAD_CONTROL
diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600
index 626c24ea0b56..5e659b034d9a 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/r600
+++ b/drivers/gpu/drm/radeon/reg_srcs/r600
@@ -713,7 +713,6 @@ r600 0x9400
0x0000A710 TD_VS_SAMPLER17_BORDER_RED
0x00009508 TA_CNTL_AUX
0x0002802C DB_DEPTH_CLEAR
-0x00028D24 DB_HTILE_SURFACE
0x00028D34 DB_PREFETCH_LIMIT
0x00028D30 DB_PRELOAD_CONTROL
0x00028D0C DB_RENDER_CONTROL
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 8305d29459bd..519ce8b9c142 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -53,8 +53,8 @@
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
/* Insmod parameters */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
index 6c6b240a782e..ce86c5e3c2c2 100644
--- a/drivers/hwmon/mc13783-adc.c
+++ b/drivers/hwmon/mc13783-adc.c
@@ -59,7 +59,7 @@ static int mc13783_adc_read(struct device *dev,
ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
MC13XXX_ADC_MODE_MULT_CHAN,
- channel, sample);
+ channel, 0, 0, sample);
if (ret)
return ret;
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 834e49d1827b..d6b0bdd48651 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -71,8 +71,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in minutes. 2<= timeout <=255 (default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index acba1c686c65..7f0b83219744 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -15,7 +15,8 @@
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.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA.
* ------------------------------------------------------------------------- */
/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
@@ -111,7 +112,7 @@ static int sclhi(struct i2c_algo_bit_data *adap)
break;
return -ETIMEDOUT;
}
- cond_resched();
+ cpu_relax();
}
#ifdef DEBUG
if (jiffies != start && i2c_debug >= 3)
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index beb9ffe2564b..73133b1063f0 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -15,7 +15,8 @@
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
*/
#include <linux/kernel.h>
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 5eebf562ff31..5c2379522aa9 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -16,7 +16,8 @@
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
*
* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
* Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey
diff --git a/drivers/i2c/algos/i2c-algo-pcf.h b/drivers/i2c/algos/i2c-algo-pcf.h
index 5263a9eeb8d7..1ec703ee788d 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.h
+++ b/drivers/i2c/algos/i2c-algo-pcf.h
@@ -16,7 +16,8 @@
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. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA. */
/* -------------------------------------------------------------------- */
/* With some changes from Frodo Looijaard <frodol@dds.nl> */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 71c1b0a7535c..d2c5095deeac 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -103,6 +103,7 @@ config I2C_I801
Patsburg (PCH)
DH89xxCC (PCH)
Panther Point (PCH)
+ Lynx Point (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index 86796488ef4f..ed9f48d566db 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -19,7 +19,6 @@
#include <mach/hardware.h>
#include <asm/hardware/ioc.h>
-#include <asm/system.h>
#define FORCE_ONES 0xdc
#define SCL 0x02
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index a651779d9ff7..c0330a41db03 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -14,8 +14,15 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-
-#include <asm/gpio.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
+
+struct i2c_gpio_private_data {
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data bit_data;
+ struct i2c_gpio_platform_data pdata;
+};
/* Toggle SDA by changing the direction of the pin */
static void i2c_gpio_setsda_dir(void *data, int state)
@@ -78,24 +85,62 @@ static int i2c_gpio_getscl(void *data)
return gpio_get_value(pdata->scl_pin);
}
+static int __devinit of_i2c_gpio_probe(struct device_node *np,
+ struct i2c_gpio_platform_data *pdata)
+{
+ u32 reg;
+
+ if (of_gpio_count(np) < 2)
+ return -ENODEV;
+
+ pdata->sda_pin = of_get_gpio(np, 0);
+ pdata->scl_pin = of_get_gpio(np, 1);
+
+ if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) {
+ pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
+ np->full_name, pdata->sda_pin, pdata->scl_pin);
+ return -ENODEV;
+ }
+
+ of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+
+ if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
+ pdata->timeout = msecs_to_jiffies(reg);
+
+ pdata->sda_is_open_drain =
+ of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+ pdata->scl_is_open_drain =
+ of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+ pdata->scl_is_output_only =
+ of_property_read_bool(np, "i2c-gpio,scl-output-only");
+
+ return 0;
+}
+
static int __devinit i2c_gpio_probe(struct platform_device *pdev)
{
+ struct i2c_gpio_private_data *priv;
struct i2c_gpio_platform_data *pdata;
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata)
- return -ENXIO;
-
- ret = -ENOMEM;
- adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
- if (!adap)
- goto err_alloc_adap;
- bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
- if (!bit_data)
- goto err_alloc_bit_data;
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ adap = &priv->adap;
+ bit_data = &priv->bit_data;
+ pdata = &priv->pdata;
+
+ if (pdev->dev.of_node) {
+ ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata);
+ if (ret)
+ return ret;
+ } else {
+ if (!pdev->dev.platform_data)
+ return -ENXIO;
+ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
+ }
ret = gpio_request(pdata->sda_pin, "sda");
if (ret)
@@ -143,6 +188,7 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev)
adap->algo_data = bit_data;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
/*
* If "dev->id" is negative we consider it as zero.
@@ -154,7 +200,9 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev)
if (ret)
goto err_add_bus;
- platform_set_drvdata(pdev, adap);
+ of_i2c_register_devices(adap);
+
+ platform_set_drvdata(pdev, priv);
dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
pdata->sda_pin, pdata->scl_pin,
@@ -168,34 +216,40 @@ err_add_bus:
err_request_scl:
gpio_free(pdata->sda_pin);
err_request_sda:
- kfree(bit_data);
-err_alloc_bit_data:
- kfree(adap);
-err_alloc_adap:
return ret;
}
static int __devexit i2c_gpio_remove(struct platform_device *pdev)
{
+ struct i2c_gpio_private_data *priv;
struct i2c_gpio_platform_data *pdata;
struct i2c_adapter *adap;
- adap = platform_get_drvdata(pdev);
- pdata = pdev->dev.platform_data;
+ priv = platform_get_drvdata(pdev);
+ adap = &priv->adap;
+ pdata = &priv->pdata;
i2c_del_adapter(adap);
gpio_free(pdata->scl_pin);
gpio_free(pdata->sda_pin);
- kfree(adap->algo_data);
- kfree(adap);
return 0;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id i2c_gpio_dt_ids[] = {
+ { .compatible = "i2c-gpio", },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
+#endif
+
static struct platform_driver i2c_gpio_driver = {
.driver = {
.name = "i2c-gpio",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(i2c_gpio_dt_ids),
},
.probe = i2c_gpio_probe,
.remove = __devexit_p(i2c_gpio_remove),
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 5d2e2816831f..ae2945a5e007 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -2,7 +2,7 @@
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
<mdsxyz123@yahoo.com>
- Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2007 - 2012 Jean Delvare <khali@linux-fr.org>
Copyright (C) 2010 Intel Corporation,
David Woodhouse <dwmw2@infradead.org>
@@ -51,6 +51,7 @@
Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
DH89xxCC (PCH) 0x2330 32 hard yes yes yes
Panther Point (PCH) 0x1e22 32 hard yes yes yes
+ Lynx Point (PCH) 0x8c22 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -105,7 +106,7 @@
#define SMBHSTCNT_KILL 2
/* Other settings */
-#define MAX_TIMEOUT 100
+#define MAX_RETRIES 400
#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
/* I801 command constants */
@@ -145,6 +146,7 @@
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
struct i801_priv {
struct i2c_adapter adapter;
@@ -215,7 +217,7 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout)
dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
SMBHSTCNT(priv));
- msleep(1);
+ usleep_range(1000, 2000);
outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
SMBHSTCNT(priv));
@@ -272,11 +274,11 @@ static int i801_transaction(struct i801_priv *priv, int xact)
/* We will always wait for a fraction of a second! */
do {
- msleep(1);
+ usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
- } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
+ } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
- result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+ result = i801_check_post(priv, status, timeout > MAX_RETRIES);
if (result < 0)
return result;
@@ -291,12 +293,12 @@ static void i801_wait_hwpec(struct i801_priv *priv)
int status;
do {
- msleep(1);
+ usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
} while ((!(status & SMBHSTSTS_INTR))
- && (timeout++ < MAX_TIMEOUT));
+ && (timeout++ < MAX_RETRIES));
- if (timeout > MAX_TIMEOUT)
+ if (timeout > MAX_RETRIES)
dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
outb_p(status, SMBHSTSTS(priv));
@@ -380,12 +382,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
/* We will always wait for a fraction of a second! */
timeout = 0;
do {
- msleep(1);
+ usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
} while ((!(status & SMBHSTSTS_BYTE_DONE))
- && (timeout++ < MAX_TIMEOUT));
+ && (timeout++ < MAX_RETRIES));
- result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+ result = i801_check_post(priv, status, timeout > MAX_RETRIES);
if (result < 0)
return result;
@@ -633,6 +635,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index 6561d275b8cf..f90a6057508d 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -47,7 +47,7 @@
#define SMBBLKDAT (0x20 + sch_smba)
/* Other settings */
-#define MAX_TIMEOUT 500
+#define MAX_RETRIES 5000
/* I2C constants */
#define SCH_QUICK 0x00
@@ -68,7 +68,7 @@ static int sch_transaction(void)
{
int temp;
int result = 0;
- int timeout = 0;
+ int retries = 0;
dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
@@ -100,12 +100,12 @@ static int sch_transaction(void)
outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
do {
- msleep(1);
+ usleep_range(100, 200);
temp = inb(SMBHSTSTS) & 0x0f;
- } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT));
+ } while ((temp & 0x08) && (retries++ < MAX_RETRIES));
/* If the SMBus is still busy, we give up */
- if (timeout > MAX_TIMEOUT) {
+ if (retries > MAX_RETRIES) {
dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
result = -ETIMEDOUT;
}
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index 10274ffb66d7..f24cc64e2e8c 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -13,7 +13,8 @@
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
*/
#include <linux/kernel.h>
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index e9c18939eda7..feb7dc359186 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -14,7 +14,8 @@
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. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA. */
/* ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
index 9f9c57ff6708..18a8fd21d2c2 100644
--- a/drivers/i2c/i2c-core.h
+++ b/drivers/i2c/i2c-core.h
@@ -13,7 +13,8 @@
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
*/
#include <linux/rwsem.h>
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 10e7f1e76586..45048323b75e 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -17,7 +17,8 @@
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.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA.
*/
/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index f61ccc1e5ea3..9836d08f7a77 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -16,7 +16,8 @@
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
*/
#include <linux/kernel.h>
diff --git a/drivers/i2c/muxes/pca9541.c b/drivers/i2c/muxes/pca9541.c
index ed699c5aa79d..e0df9b6c66b3 100644
--- a/drivers/i2c/muxes/pca9541.c
+++ b/drivers/i2c/muxes/pca9541.c
@@ -393,18 +393,7 @@ static struct i2c_driver pca9541_driver = {
.id_table = pca9541_id,
};
-static int __init pca9541_init(void)
-{
- return i2c_add_driver(&pca9541_driver);
-}
-
-static void __exit pca9541_exit(void)
-{
- i2c_del_driver(&pca9541_driver);
-}
-
-module_init(pca9541_init);
-module_exit(pca9541_exit);
+module_i2c_driver(pca9541_driver);
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
index 6f8953664636..0e37ef27aa12 100644
--- a/drivers/i2c/muxes/pca954x.c
+++ b/drivers/i2c/muxes/pca954x.c
@@ -284,18 +284,7 @@ static struct i2c_driver pca954x_driver = {
.id_table = pca954x_id,
};
-static int __init pca954x_init(void)
-{
- return i2c_add_driver(&pca954x_driver);
-}
-
-static void __exit pca954x_exit(void)
-{
- i2c_del_driver(&pca954x_driver);
-}
-
-module_init(pca954x_init);
-module_exit(pca954x_exit);
+module_i2c_driver(pca954x_driver);
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index d2f3db3cf3ed..28e344ea514c 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -41,7 +41,6 @@
#include <linux/major.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
index 8bbfe5557c7b..e03f4f19c1d6 100644
--- a/drivers/ide/qd65xx.c
+++ b/drivers/ide/qd65xx.c
@@ -29,7 +29,6 @@
#include <linux/blkdev.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <asm/system.h>
#include <asm/io.h>
#define DRV_NAME "qd65xx"
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 9a3fbfca9b41..fd05f48f6b0b 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -42,7 +42,6 @@
*/
-#include <asm/system.h>
#include "ehca_classes.h"
#include "ehca_tools.h"
#include "ehca_qes.h"
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
index e46a86776a6b..64ca7113ff28 100644
--- a/drivers/input/input-compat.c
+++ b/drivers/input/input-compat.c
@@ -17,7 +17,7 @@
int input_event_from_user(const char __user *buffer,
struct input_event *event)
{
- if (INPUT_COMPAT_TEST) {
+ if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
struct input_event_compat compat_event;
if (copy_from_user(&compat_event, buffer,
@@ -41,7 +41,7 @@ int input_event_from_user(const char __user *buffer,
int input_event_to_user(char __user *buffer,
const struct input_event *event)
{
- if (INPUT_COMPAT_TEST) {
+ if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
struct input_event_compat compat_event;
compat_event.time.tv_sec = event->time.tv_sec;
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 22be27b424de..148f66fe3205 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -67,7 +67,7 @@ struct ff_effect_compat {
static inline size_t input_event_size(void)
{
- return INPUT_COMPAT_TEST ?
+ return (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) ?
sizeof(struct input_event_compat) : sizeof(struct input_event);
}
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index c24ec2d5f926..26043cc6a016 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -13,7 +13,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/joystick.h>
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index 0bc86204213e..c65b5fa69f1e 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -35,7 +35,6 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
-#include <asm/system.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
@@ -108,6 +107,9 @@ static int __init amijoy_init(void)
int i, j;
int err;
+ if (!MACH_IS_AMIGA)
+ return -ENODEV;
+
for (i = 0; i < 2; i++) {
if (!amijoy[i])
continue;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index ed1ed469d085..62bfce468f9f 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -28,14 +28,18 @@
#include <linux/gpio.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
+#include <linux/spinlock.h>
struct gpio_button_data {
- struct gpio_keys_button *button;
+ const struct gpio_keys_button *button;
struct input_dev *input;
struct timer_list timer;
struct work_struct work;
- int timer_debounce; /* in msecs */
+ unsigned int timer_debounce; /* in msecs */
+ unsigned int irq;
+ spinlock_t lock;
bool disabled;
+ bool key_pressed;
};
struct gpio_keys_drvdata {
@@ -114,7 +118,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
/*
* Disable IRQ and possible debouncing timer.
*/
- disable_irq(gpio_to_irq(bdata->button->gpio));
+ disable_irq(bdata->irq);
if (bdata->timer_debounce)
del_timer_sync(&bdata->timer);
@@ -135,7 +139,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
static void gpio_keys_enable_button(struct gpio_button_data *bdata)
{
if (bdata->disabled) {
- enable_irq(gpio_to_irq(bdata->button->gpio));
+ enable_irq(bdata->irq);
bdata->disabled = false;
}
}
@@ -195,7 +199,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
* @type: button type (%EV_KEY, %EV_SW)
*
* This function parses stringified bitmap from @buf and disables/enables
- * GPIO buttons accordinly. Returns 0 on success and negative error
+ * GPIO buttons accordingly. Returns 0 on success and negative error
* on failure.
*/
static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
@@ -320,9 +324,9 @@ static struct attribute_group gpio_keys_attr_group = {
.attrs = gpio_keys_attrs,
};
-static void gpio_keys_report_event(struct gpio_button_data *bdata)
+static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{
- struct gpio_keys_button *button = bdata->button;
+ const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
@@ -336,27 +340,26 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
input_sync(input);
}
-static void gpio_keys_work_func(struct work_struct *work)
+static void gpio_keys_gpio_work_func(struct work_struct *work)
{
struct gpio_button_data *bdata =
container_of(work, struct gpio_button_data, work);
- gpio_keys_report_event(bdata);
+ gpio_keys_gpio_report_event(bdata);
}
-static void gpio_keys_timer(unsigned long _data)
+static void gpio_keys_gpio_timer(unsigned long _data)
{
- struct gpio_button_data *data = (struct gpio_button_data *)_data;
+ struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
- schedule_work(&data->work);
+ schedule_work(&bdata->work);
}
-static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
+static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
{
struct gpio_button_data *bdata = dev_id;
- struct gpio_keys_button *button = bdata->button;
- BUG_ON(irq != gpio_to_irq(button->gpio));
+ BUG_ON(irq != bdata->irq);
if (bdata->timer_debounce)
mod_timer(&bdata->timer,
@@ -367,50 +370,133 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void gpio_keys_irq_timer(unsigned long _data)
+{
+ struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
+ struct input_dev *input = bdata->input;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bdata->lock, flags);
+ if (bdata->key_pressed) {
+ input_event(input, EV_KEY, bdata->button->code, 0);
+ input_sync(input);
+ bdata->key_pressed = false;
+ }
+ spin_unlock_irqrestore(&bdata->lock, flags);
+}
+
+static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
+{
+ struct gpio_button_data *bdata = dev_id;
+ const struct gpio_keys_button *button = bdata->button;
+ struct input_dev *input = bdata->input;
+ unsigned long flags;
+
+ BUG_ON(irq != bdata->irq);
+
+ spin_lock_irqsave(&bdata->lock, flags);
+
+ if (!bdata->key_pressed) {
+ input_event(input, EV_KEY, button->code, 1);
+ input_sync(input);
+
+ if (!bdata->timer_debounce) {
+ input_event(input, EV_KEY, button->code, 0);
+ input_sync(input);
+ goto out;
+ }
+
+ bdata->key_pressed = true;
+ }
+
+ if (bdata->timer_debounce)
+ mod_timer(&bdata->timer,
+ jiffies + msecs_to_jiffies(bdata->timer_debounce));
+out:
+ spin_unlock_irqrestore(&bdata->lock, flags);
+ return IRQ_HANDLED;
+}
+
static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
+ struct input_dev *input,
struct gpio_button_data *bdata,
- struct gpio_keys_button *button)
+ const struct gpio_keys_button *button)
{
const char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev;
+ irq_handler_t isr;
unsigned long irqflags;
int irq, error;
- setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
- INIT_WORK(&bdata->work, gpio_keys_work_func);
+ bdata->input = input;
+ bdata->button = button;
+ spin_lock_init(&bdata->lock);
- error = gpio_request(button->gpio, desc);
- if (error < 0) {
- dev_err(dev, "failed to request GPIO %d, error %d\n",
- button->gpio, error);
- goto fail2;
- }
+ if (gpio_is_valid(button->gpio)) {
- error = gpio_direction_input(button->gpio);
- if (error < 0) {
- dev_err(dev, "failed to configure"
- " direction for GPIO %d, error %d\n",
- button->gpio, error);
- goto fail3;
- }
+ error = gpio_request(button->gpio, desc);
+ if (error < 0) {
+ dev_err(dev, "Failed to request GPIO %d, error %d\n",
+ button->gpio, error);
+ return error;
+ }
- if (button->debounce_interval) {
- error = gpio_set_debounce(button->gpio,
- button->debounce_interval * 1000);
- /* use timer if gpiolib doesn't provide debounce */
- if (error < 0)
- bdata->timer_debounce = button->debounce_interval;
- }
+ error = gpio_direction_input(button->gpio);
+ if (error < 0) {
+ dev_err(dev,
+ "Failed to configure direction for GPIO %d, error %d\n",
+ button->gpio, error);
+ goto fail;
+ }
- irq = gpio_to_irq(button->gpio);
- if (irq < 0) {
- error = irq;
- dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",
- button->gpio, error);
- goto fail3;
+ if (button->debounce_interval) {
+ error = gpio_set_debounce(button->gpio,
+ button->debounce_interval * 1000);
+ /* use timer if gpiolib doesn't provide debounce */
+ if (error < 0)
+ bdata->timer_debounce =
+ button->debounce_interval;
+ }
+
+ irq = gpio_to_irq(button->gpio);
+ if (irq < 0) {
+ error = irq;
+ dev_err(dev,
+ "Unable to get irq number for GPIO %d, error %d\n",
+ button->gpio, error);
+ goto fail;
+ }
+ bdata->irq = irq;
+
+ INIT_WORK(&bdata->work, gpio_keys_gpio_work_func);
+ setup_timer(&bdata->timer,
+ gpio_keys_gpio_timer, (unsigned long)bdata);
+
+ isr = gpio_keys_gpio_isr;
+ irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+ } else {
+ if (!button->irq) {
+ dev_err(dev, "No IRQ specified\n");
+ return -EINVAL;
+ }
+ bdata->irq = button->irq;
+
+ if (button->type && button->type != EV_KEY) {
+ dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");
+ return -EINVAL;
+ }
+
+ bdata->timer_debounce = button->debounce_interval;
+ setup_timer(&bdata->timer,
+ gpio_keys_irq_timer, (unsigned long)bdata);
+
+ isr = gpio_keys_irq_isr;
+ irqflags = 0;
}
- irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+ input_set_capability(input, button->type ?: EV_KEY, button->code);
+
/*
* If platform has specified that the button can be disabled,
* we don't want it to share the interrupt line.
@@ -418,18 +504,19 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
if (!button->can_disable)
irqflags |= IRQF_SHARED;
- error = request_threaded_irq(irq, NULL, gpio_keys_isr, irqflags, desc, bdata);
+ error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata);
if (error < 0) {
dev_err(dev, "Unable to claim irq %d; error %d\n",
- irq, error);
- goto fail3;
+ bdata->irq, error);
+ goto fail;
}
return 0;
-fail3:
- gpio_free(button->gpio);
-fail2:
+fail:
+ if (gpio_is_valid(button->gpio))
+ gpio_free(button->gpio);
+
return error;
}
@@ -547,9 +634,19 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
#endif
+static void gpio_remove_key(struct gpio_button_data *bdata)
+{
+ free_irq(bdata->irq, bdata);
+ if (bdata->timer_debounce)
+ del_timer_sync(&bdata->timer);
+ cancel_work_sync(&bdata->work);
+ if (gpio_is_valid(bdata->button->gpio))
+ gpio_free(bdata->button->gpio);
+}
+
static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
- struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ const struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct gpio_keys_drvdata *ddata;
struct device *dev = &pdev->dev;
struct gpio_keys_platform_data alt_pdata;
@@ -599,21 +696,15 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
__set_bit(EV_REP, input->evbit);
for (i = 0; i < pdata->nbuttons; i++) {
- struct gpio_keys_button *button = &pdata->buttons[i];
+ const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
- unsigned int type = button->type ?: EV_KEY;
-
- bdata->input = input;
- bdata->button = button;
- error = gpio_keys_setup_key(pdev, bdata, button);
+ error = gpio_keys_setup_key(pdev, input, bdata, button);
if (error)
goto fail2;
if (button->wakeup)
wakeup = 1;
-
- input_set_capability(input, type, button->code);
}
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
@@ -630,9 +721,12 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
goto fail3;
}
- /* get current state of buttons */
- for (i = 0; i < pdata->nbuttons; i++)
- gpio_keys_report_event(&ddata->data[i]);
+ /* get current state of buttons that are connected to GPIOs */
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_button_data *bdata = &ddata->data[i];
+ if (gpio_is_valid(bdata->button->gpio))
+ gpio_keys_gpio_report_event(bdata);
+ }
input_sync(input);
device_init_wakeup(&pdev->dev, wakeup);
@@ -642,13 +736,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
fail3:
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
fail2:
- while (--i >= 0) {
- free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
- if (ddata->data[i].timer_debounce)
- del_timer_sync(&ddata->data[i].timer);
- cancel_work_sync(&ddata->data[i].work);
- gpio_free(pdata->buttons[i].gpio);
- }
+ while (--i >= 0)
+ gpio_remove_key(&ddata->data[i]);
platform_set_drvdata(pdev, NULL);
fail1:
@@ -671,14 +760,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
- for (i = 0; i < ddata->n_buttons; i++) {
- int irq = gpio_to_irq(ddata->data[i].button->gpio);
- free_irq(irq, &ddata->data[i]);
- if (ddata->data[i].timer_debounce)
- del_timer_sync(&ddata->data[i].timer);
- cancel_work_sync(&ddata->data[i].work);
- gpio_free(ddata->data[i].button->gpio);
- }
+ for (i = 0; i < ddata->n_buttons; i++)
+ gpio_remove_key(&ddata->data[i]);
input_unregister_device(input);
@@ -703,11 +786,9 @@ static int gpio_keys_suspend(struct device *dev)
if (device_may_wakeup(dev)) {
for (i = 0; i < ddata->n_buttons; i++) {
- struct gpio_keys_button *button = ddata->data[i].button;
- if (button->wakeup) {
- int irq = gpio_to_irq(button->gpio);
- enable_irq_wake(irq);
- }
+ struct gpio_button_data *bdata = &ddata->data[i];
+ if (bdata->button->wakeup)
+ enable_irq_wake(bdata->irq);
}
}
@@ -720,14 +801,12 @@ static int gpio_keys_resume(struct device *dev)
int i;
for (i = 0; i < ddata->n_buttons; i++) {
+ struct gpio_button_data *bdata = &ddata->data[i];
+ if (bdata->button->wakeup && device_may_wakeup(dev))
+ disable_irq_wake(bdata->irq);
- struct gpio_keys_button *button = ddata->data[i].button;
- if (button->wakeup && device_may_wakeup(dev)) {
- int irq = gpio_to_irq(button->gpio);
- disable_irq_wake(irq);
- }
-
- gpio_keys_report_event(&ddata->data[i]);
+ if (gpio_is_valid(bdata->button->gpio))
+ gpio_keys_gpio_report_event(bdata);
}
input_sync(ddata->input);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 21c42f852343..fe4ac95ca6c8 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -630,6 +630,7 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
if (!np)
return NULL;
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
index f2e0cbc5ab64..f9ce1835e4d7 100644
--- a/drivers/input/misc/88pm860x_onkey.c
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -105,6 +105,8 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, info);
+ device_init_wakeup(&pdev->dev, 1);
+
return 0;
out_irq:
@@ -129,10 +131,34 @@ static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_onkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev))
+ chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
+ return 0;
+}
+static int pm860x_onkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev))
+ chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+
static struct platform_driver pm860x_onkey_driver = {
.driver = {
.name = "88pm860x-onkey",
.owner = THIS_MODULE,
+ .pm = &pm860x_onkey_pm_ops,
},
.probe = pm860x_onkey_probe,
.remove = __devexit_p(pm860x_onkey_remove),
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index ff5f61a0fd3a..5fa99341a39d 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -25,7 +25,6 @@
#include <asm/irq.h>
#include <asm/setup.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
index 5c4a692bf73a..d1c43236b125 100644
--- a/drivers/input/mouse/atarimouse.c
+++ b/drivers/input/mouse/atarimouse.c
@@ -47,7 +47,6 @@
#include <asm/irq.h>
#include <asm/setup.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/atarihw.h>
#include <asm/atarikb.h>
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 2a77a52d2e62..a977bfaa6821 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -2,7 +2,7 @@
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/ctype.h>
#include <linux/libps2.h>
#include <linux/serio.h>
@@ -36,6 +37,9 @@
#define FSP_CMD_TIMEOUT 200
#define FSP_CMD_TIMEOUT2 30
+#define GET_ABS_X(packet) ((packet[1] << 2) | ((packet[3] >> 2) & 0x03))
+#define GET_ABS_Y(packet) ((packet[2] << 2) | (packet[3] & 0x03))
+
/** Driver version. */
static const char fsp_drv_ver[] = "1.0.0-K";
@@ -128,8 +132,9 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
out:
ps2_end_command(ps2dev);
psmouse_activate(psmouse);
- dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
- reg_addr, *reg_val, rc);
+ psmouse_dbg(psmouse,
+ "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
+ reg_addr, *reg_val, rc);
return rc;
}
@@ -179,8 +184,9 @@ static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
out:
ps2_end_command(ps2dev);
- dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
- reg_addr, reg_val, rc);
+ psmouse_dbg(psmouse,
+ "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
+ reg_addr, reg_val, rc);
return rc;
}
@@ -237,8 +243,9 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
out:
ps2_end_command(ps2dev);
psmouse_activate(psmouse);
- dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
- *reg_val, rc);
+ psmouse_dbg(psmouse,
+ "READ PAGE REG: 0x%02x (rc = %d)\n",
+ *reg_val, rc);
return rc;
}
@@ -274,8 +281,9 @@ static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
out:
ps2_end_command(ps2dev);
- dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
- reg_val, rc);
+ psmouse_dbg(psmouse,
+ "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
+ reg_val, rc);
return rc;
}
@@ -319,7 +327,7 @@ static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable)
int res = 0;
if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
- dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n");
+ psmouse_err(psmouse, "Unable get OPC state.\n");
return -EIO;
}
@@ -336,8 +344,7 @@ static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable)
}
if (res != 0) {
- dev_err(&psmouse->ps2dev.serio->dev,
- "Unable to enable OPC tag.\n");
+ psmouse_err(psmouse, "Unable to enable OPC tag.\n");
res = -EIO;
}
@@ -615,18 +622,40 @@ static struct attribute_group fsp_attribute_group = {
.attrs = fsp_attributes,
};
-#ifdef FSP_DEBUG
-static void fsp_packet_debug(unsigned char packet[])
+#ifdef FSP_DEBUG
+static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[])
{
static unsigned int ps2_packet_cnt;
static unsigned int ps2_last_second;
unsigned int jiffies_msec;
+ const char *packet_type = "UNKNOWN";
+ unsigned short abs_x = 0, abs_y = 0;
+
+ /* Interpret & dump the packet data. */
+ switch (packet[0] >> FSP_PKT_TYPE_SHIFT) {
+ case FSP_PKT_TYPE_ABS:
+ packet_type = "Absolute";
+ abs_x = GET_ABS_X(packet);
+ abs_y = GET_ABS_Y(packet);
+ break;
+ case FSP_PKT_TYPE_NORMAL:
+ packet_type = "Normal";
+ break;
+ case FSP_PKT_TYPE_NOTIFY:
+ packet_type = "Notify";
+ break;
+ case FSP_PKT_TYPE_NORMAL_OPC:
+ packet_type = "Normal-OPC";
+ break;
+ }
ps2_packet_cnt++;
jiffies_msec = jiffies_to_msecs(jiffies);
psmouse_dbg(psmouse,
- "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
- jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
+ "%08dms %s packets: %02x, %02x, %02x, %02x; "
+ "abs_x: %d, abs_y: %d\n",
+ jiffies_msec, packet_type,
+ packet[0], packet[1], packet[2], packet[3], abs_x, abs_y);
if (jiffies_msec - ps2_last_second > 1000) {
psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt);
@@ -635,17 +664,29 @@ static void fsp_packet_debug(unsigned char packet[])
}
}
#else
-static void fsp_packet_debug(unsigned char packet[])
+static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[])
{
}
#endif
+static void fsp_set_slot(struct input_dev *dev, int slot, bool active,
+ unsigned int x, unsigned int y)
+{
+ input_mt_slot(dev, 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, y);
+ }
+}
+
static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
struct fsp_data *ad = psmouse->private;
unsigned char *packet = psmouse->packet;
unsigned char button_status = 0, lscroll = 0, rscroll = 0;
+ unsigned short abs_x, abs_y, fgrs = 0;
int rel_x, rel_y;
if (psmouse->pktcnt < 4)
@@ -655,16 +696,76 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
* Full packet accumulated, process it
*/
+ fsp_packet_debug(psmouse, packet);
+
switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
case FSP_PKT_TYPE_ABS:
- dev_warn(&psmouse->ps2dev.serio->dev,
- "Unexpected absolute mode packet, ignored.\n");
+ abs_x = GET_ABS_X(packet);
+ abs_y = GET_ABS_Y(packet);
+
+ if (packet[0] & FSP_PB0_MFMC) {
+ /*
+ * MFMC packet: assume that there are two fingers on
+ * pad
+ */
+ fgrs = 2;
+
+ /* MFMC packet */
+ if (packet[0] & FSP_PB0_MFMC_FGR2) {
+ /* 2nd finger */
+ if (ad->last_mt_fgr == 2) {
+ /*
+ * workaround for buggy firmware
+ * which doesn't clear MFMC bit if
+ * the 1st finger is up
+ */
+ fgrs = 1;
+ fsp_set_slot(dev, 0, false, 0, 0);
+ }
+ ad->last_mt_fgr = 2;
+
+ fsp_set_slot(dev, 1, fgrs == 2, abs_x, abs_y);
+ } else {
+ /* 1st finger */
+ if (ad->last_mt_fgr == 1) {
+ /*
+ * workaround for buggy firmware
+ * which doesn't clear MFMC bit if
+ * the 2nd finger is up
+ */
+ fgrs = 1;
+ fsp_set_slot(dev, 1, false, 0, 0);
+ }
+ ad->last_mt_fgr = 1;
+ fsp_set_slot(dev, 0, fgrs != 0, abs_x, abs_y);
+ }
+ } else {
+ /* SFAC packet */
+
+ /* no multi-finger information */
+ ad->last_mt_fgr = 0;
+
+ if (abs_x != 0 && abs_y != 0)
+ fgrs = 1;
+
+ fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y);
+ fsp_set_slot(dev, 1, false, 0, 0);
+ }
+ if (fgrs > 0) {
+ input_report_abs(dev, ABS_X, abs_x);
+ input_report_abs(dev, ABS_Y, abs_y);
+ }
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ input_report_key(dev, BTN_TOUCH, fgrs);
+ input_report_key(dev, BTN_TOOL_FINGER, fgrs == 1);
+ input_report_key(dev, BTN_TOOL_DOUBLETAP, fgrs == 2);
break;
case FSP_PKT_TYPE_NORMAL_OPC:
/* on-pad click, filter it if necessary */
if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
- packet[0] &= ~BIT(0);
+ packet[0] &= ~FSP_PB0_LBTN;
/* fall through */
case FSP_PKT_TYPE_NORMAL:
@@ -711,8 +812,6 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
input_sync(dev);
- fsp_packet_debug(packet);
-
return PSMOUSE_FULL_PACKET;
}
@@ -736,42 +835,106 @@ static int fsp_activate_protocol(struct psmouse *psmouse)
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
if (param[0] != 0x04) {
- dev_err(&psmouse->ps2dev.serio->dev,
- "Unable to enable 4 bytes packet format.\n");
+ psmouse_err(psmouse,
+ "Unable to enable 4 bytes packet format.\n");
return -EIO;
}
- if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
- dev_err(&psmouse->ps2dev.serio->dev,
- "Unable to read SYSCTL5 register.\n");
- return -EIO;
- }
+ if (pad->ver < FSP_VER_STL3888_C0) {
+ /* Preparing relative coordinates output for older hardware */
+ if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
+ psmouse_err(psmouse,
+ "Unable to read SYSCTL5 register.\n");
+ return -EIO;
+ }
- val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
- /* Ensure we are not in absolute mode */
- val &= ~FSP_BIT_EN_PKT_G0;
- if (pad->buttons == 0x06) {
- /* Left/Middle/Right & Scroll Up/Down/Right/Left */
- val |= FSP_BIT_EN_MSID6;
- }
+ if (fsp_get_buttons(psmouse, &pad->buttons)) {
+ psmouse_err(psmouse,
+ "Unable to retrieve number of buttons.\n");
+ return -EIO;
+ }
- if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
- dev_err(&psmouse->ps2dev.serio->dev,
- "Unable to set up required mode bits.\n");
- return -EIO;
+ val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
+ /* Ensure we are not in absolute mode */
+ val &= ~FSP_BIT_EN_PKT_G0;
+ if (pad->buttons == 0x06) {
+ /* Left/Middle/Right & Scroll Up/Down/Right/Left */
+ val |= FSP_BIT_EN_MSID6;
+ }
+
+ if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
+ psmouse_err(psmouse,
+ "Unable to set up required mode bits.\n");
+ return -EIO;
+ }
+
+ /*
+ * Enable OPC tags such that driver can tell the difference
+ * between on-pad and real button click
+ */
+ if (fsp_opc_tag_enable(psmouse, true))
+ psmouse_warn(psmouse,
+ "Failed to enable OPC tag mode.\n");
+ /* enable on-pad click by default */
+ pad->flags |= FSPDRV_FLAG_EN_OPC;
+
+ /* Enable on-pad vertical and horizontal scrolling */
+ fsp_onpad_vscr(psmouse, true);
+ fsp_onpad_hscr(psmouse, true);
+ } else {
+ /* Enable absolute coordinates output for Cx/Dx hardware */
+ if (fsp_reg_write(psmouse, FSP_REG_SWC1,
+ FSP_BIT_SWC1_EN_ABS_1F |
+ FSP_BIT_SWC1_EN_ABS_2F |
+ FSP_BIT_SWC1_EN_FUP_OUT |
+ FSP_BIT_SWC1_EN_ABS_CON)) {
+ psmouse_err(psmouse,
+ "Unable to enable absolute coordinates output.\n");
+ return -EIO;
+ }
}
- /*
- * Enable OPC tags such that driver can tell the difference between
- * on-pad and real button click
- */
- if (fsp_opc_tag_enable(psmouse, true))
- dev_warn(&psmouse->ps2dev.serio->dev,
- "Failed to enable OPC tag mode.\n");
+ return 0;
+}
- /* Enable on-pad vertical and horizontal scrolling */
- fsp_onpad_vscr(psmouse, true);
- fsp_onpad_hscr(psmouse, true);
+static int fsp_set_input_params(struct psmouse *psmouse)
+{
+ struct input_dev *dev = psmouse->dev;
+ struct fsp_data *pad = psmouse->private;
+
+ if (pad->ver < FSP_VER_STL3888_C0) {
+ __set_bit(BTN_MIDDLE, dev->keybit);
+ __set_bit(BTN_BACK, dev->keybit);
+ __set_bit(BTN_FORWARD, dev->keybit);
+ __set_bit(REL_WHEEL, dev->relbit);
+ __set_bit(REL_HWHEEL, dev->relbit);
+ } else {
+ /*
+ * Hardware prior to Cx performs much better in relative mode;
+ * hence, only enable absolute coordinates output as well as
+ * multi-touch output for the newer hardware.
+ *
+ * Maximum coordinates can be computed as:
+ *
+ * number of scanlines * 64 - 57
+ *
+ * where number of X/Y scanline lines are 16/12.
+ */
+ int abs_x = 967, abs_y = 711;
+
+ __set_bit(EV_ABS, dev->evbit);
+ __clear_bit(EV_REL, dev->evbit);
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+
+ input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
+ input_mt_init_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
+ }
return 0;
}
@@ -829,18 +992,16 @@ static int fsp_reconnect(struct psmouse *psmouse)
int fsp_init(struct psmouse *psmouse)
{
struct fsp_data *priv;
- int ver, rev, buttons;
+ int ver, rev;
int error;
if (fsp_get_version(psmouse, &ver) ||
- fsp_get_revision(psmouse, &rev) ||
- fsp_get_buttons(psmouse, &buttons)) {
+ fsp_get_revision(psmouse, &rev)) {
return -ENODEV;
}
- 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_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n",
+ ver >> 4, ver & 0x0F, rev, fsp_drv_ver);
psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
if (!priv)
@@ -848,17 +1009,6 @@ int fsp_init(struct psmouse *psmouse)
priv->ver = ver;
priv->rev = rev;
- priv->buttons = buttons;
-
- /* enable on-pad click by default */
- priv->flags |= FSPDRV_FLAG_EN_OPC;
-
- /* Set up various supported input event bits */
- __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
- __set_bit(BTN_BACK, psmouse->dev->keybit);
- __set_bit(BTN_FORWARD, psmouse->dev->keybit);
- __set_bit(REL_WHEEL, psmouse->dev->relbit);
- __set_bit(REL_HWHEEL, psmouse->dev->relbit);
psmouse->protocol_handler = fsp_process_byte;
psmouse->disconnect = fsp_disconnect;
@@ -866,16 +1016,20 @@ int fsp_init(struct psmouse *psmouse)
psmouse->cleanup = fsp_reset;
psmouse->pktsize = 4;
- /* set default packet output based on number of buttons we found */
error = fsp_activate_protocol(psmouse);
if (error)
goto err_out;
+ /* Set up various supported input event bits */
+ error = fsp_set_input_params(psmouse);
+ if (error)
+ goto err_out;
+
error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
&fsp_attribute_group);
if (error) {
- dev_err(&psmouse->ps2dev.serio->dev,
- "Failed to create sysfs attributes (%d)", error);
+ psmouse_err(psmouse,
+ "Failed to create sysfs attributes (%d)", error);
goto err_out;
}
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index 2e4af24f8c15..334de19e5ddb 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -2,7 +2,7 @@
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -55,6 +55,16 @@
#define FSP_BIT_FIX_HSCR BIT(5)
#define FSP_BIT_DRAG_LOCK BIT(6)
+#define FSP_REG_SWC1 (0x90)
+#define FSP_BIT_SWC1_EN_ABS_1F BIT(0)
+#define FSP_BIT_SWC1_EN_GID BIT(1)
+#define FSP_BIT_SWC1_EN_ABS_2F BIT(2)
+#define FSP_BIT_SWC1_EN_FUP_OUT BIT(3)
+#define FSP_BIT_SWC1_EN_ABS_CON BIT(4)
+#define FSP_BIT_SWC1_GST_GRP0 BIT(5)
+#define FSP_BIT_SWC1_GST_GRP1 BIT(6)
+#define FSP_BIT_SWC1_BX_COMPAT BIT(7)
+
/* Finger-sensing Pad packet formating related definitions */
/* absolute packet type */
@@ -64,12 +74,32 @@
#define FSP_PKT_TYPE_NORMAL_OPC (0x03)
#define FSP_PKT_TYPE_SHIFT (6)
+/* bit definitions for the first byte of report packet */
+#define FSP_PB0_LBTN BIT(0)
+#define FSP_PB0_RBTN BIT(1)
+#define FSP_PB0_MBTN BIT(2)
+#define FSP_PB0_MFMC_FGR2 FSP_PB0_MBTN
+#define FSP_PB0_MUST_SET BIT(3)
+#define FSP_PB0_PHY_BTN BIT(4)
+#define FSP_PB0_MFMC BIT(5)
+
+/* hardware revisions */
+#define FSP_VER_STL3888_A4 (0xC1)
+#define FSP_VER_STL3888_B0 (0xD0)
+#define FSP_VER_STL3888_B1 (0xD1)
+#define FSP_VER_STL3888_B2 (0xD2)
+#define FSP_VER_STL3888_C0 (0xE0)
+#define FSP_VER_STL3888_C1 (0xE1)
+#define FSP_VER_STL3888_D0 (0xE2)
+#define FSP_VER_STL3888_D1 (0xE3)
+#define FSP_VER_STL3888_E0 (0xE4)
+
#ifdef __KERNEL__
struct fsp_data {
unsigned char ver; /* hardware version */
unsigned char rev; /* hardware revison */
- unsigned char buttons; /* Number of buttons */
+ unsigned int buttons; /* Number of buttons */
unsigned int flags;
#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */
@@ -78,6 +108,7 @@ struct fsp_data {
unsigned char last_reg; /* Last register we requested read from */
unsigned char last_val;
+ unsigned int last_mt_fgr; /* Last seen finger(multitouch) */
};
#ifdef CONFIG_MOUSE_PS2_SENTELIC
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index bd5b10eeeb40..f5fbdf94de3b 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -184,7 +184,7 @@ module_init(ams_delta_serio_init);
static void __exit ams_delta_serio_exit(void)
{
serio_unregister_port(ams_delta_serio);
- free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
+ free_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
gpio_free_array(ams_delta_gpios,
ARRAY_SIZE(ams_delta_gpios));
}
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index be3316073ae7..09a089996ded 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -71,7 +71,6 @@
#include <linux/slab.h>
#include <linux/hil.h>
#include <asm/io.h>
-#include <asm/system.h>
/* Machine-specific abstraction */
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index 558200e96d0f..61da763b1209 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -21,7 +21,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/ip32/mace.h>
#include <asm/ip32/ip32_ints.h>
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 58b224498b35..2af5df6a8fba 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -38,7 +38,6 @@
#include <mach/hardware.h>
#include <asm/hardware/iomd.h>
-#include <asm/system.h>
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index 5ebabe3fc845..389766707534 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -20,7 +20,6 @@
#include <linux/spinlock.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/hardware/sa1111.h>
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index e53f4081a586..bed7cbf84cfd 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -76,6 +76,7 @@ config TABLET_USB_KBTAB
config TABLET_USB_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on USB_ARCH_HAS_HCD
+ select POWER_SUPPLY
select USB
select NEW_LEDS
select LEDS_CLASS
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index 0783864a7dc2..b4842d0e61dd 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -88,6 +88,7 @@
#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/usb/input.h>
+#include <linux/power_supply.h>
#include <asm/unaligned.h>
/*
@@ -112,6 +113,7 @@ struct wacom {
struct urb *irq;
struct wacom_wac wacom_wac;
struct mutex lock;
+ struct work_struct work;
bool open;
char phys[32];
struct wacom_led {
@@ -120,8 +122,15 @@ struct wacom {
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
+ struct power_supply battery;
};
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
+{
+ struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ schedule_work(&wacom->work);
+}
+
extern const struct usb_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index ca28066dc81e..0d269212931e 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -167,6 +167,19 @@ static void wacom_close(struct input_dev *dev)
usb_autopm_put_interface(wacom->intf);
}
+/*
+ * Static values for max X/Y and resolution of Pen interface is stored in
+ * features. This mean physical size of active area can be computed.
+ * This is useful to do when Pen and Touch have same active area of tablet.
+ * This means for Touch device, we only need to find max X/Y value and we
+ * have enough information to compute resolution of touch.
+ */
+static void wacom_set_phy_from_res(struct wacom_features *features)
+{
+ features->x_phy = (features->x_max * 100) / features->x_resolution;
+ features->y_phy = (features->y_max * 100) / features->y_resolution;
+}
+
static int wacom_parse_logical_collection(unsigned char *report,
struct wacom_features *features)
{
@@ -178,15 +191,7 @@ static int wacom_parse_logical_collection(unsigned char *report,
features->pktlen = WACOM_PKGLEN_BBTOUCH3;
features->device_type = BTN_TOOL_FINGER;
- /*
- * Stylus and Touch have same active area
- * so compute physical size based on stylus
- * data before its overwritten.
- */
- features->x_phy =
- (features->x_max * 100) / features->x_resolution;
- features->y_phy =
- (features->y_max * 100) / features->y_resolution;
+ wacom_set_phy_from_res(features);
features->x_max = features->y_max =
get_unaligned_le16(&report[10]);
@@ -422,6 +427,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
report_id, rep_data, 4, 1);
} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
} else if (features->type != TABLETPC &&
+ features->type != WIRELESS &&
features->device_type == BTN_TOOL_PEN) {
do {
rep_data[0] = 2;
@@ -454,6 +460,21 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
features->pressure_fuzz = 0;
features->distance_fuzz = 0;
+ /*
+ * The wireless device HID is basic and layout conflicts with
+ * other tablets (monitor and touch interface can look like pen).
+ * Skip the query for this type and modify defaults based on
+ * interface number.
+ */
+ if (features->type == WIRELESS) {
+ if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+ features->device_type = 0;
+ } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) {
+ features->device_type = BTN_TOOL_DOUBLETAP;
+ features->pktlen = WACOM_PKGLEN_BBTOUCH3;
+ }
+ }
+
/* only Tablet PCs and Bamboo P&T need to retrieve the info */
if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
(features->type != BAMBOO_PT))
@@ -822,6 +843,152 @@ static void wacom_destroy_leds(struct wacom *wacom)
}
}
+static enum power_supply_property wacom_battery_props[] = {
+ POWER_SUPPLY_PROP_CAPACITY
+};
+
+static int wacom_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wacom *wacom = container_of(psy, struct wacom, battery);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval =
+ wacom->wacom_wac.battery_capacity * 100 / 31;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wacom_initialize_battery(struct wacom *wacom)
+{
+ int error = 0;
+
+ if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR) {
+ wacom->battery.properties = wacom_battery_props;
+ wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
+ wacom->battery.get_property = wacom_battery_get_property;
+ wacom->battery.name = "wacom_battery";
+ wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ wacom->battery.use_for_apm = 0;
+
+ error = power_supply_register(&wacom->usbdev->dev,
+ &wacom->battery);
+ }
+
+ return error;
+}
+
+static void wacom_destroy_battery(struct wacom *wacom)
+{
+ if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR)
+ power_supply_unregister(&wacom->battery);
+}
+
+static int wacom_register_input(struct wacom *wacom)
+{
+ struct input_dev *input_dev;
+ struct usb_interface *intf = wacom->intf;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+ int error;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ input_dev->name = wacom_wac->name;
+ input_dev->dev.parent = &intf->dev;
+ input_dev->open = wacom_open;
+ input_dev->close = wacom_close;
+ usb_to_input_id(dev, &input_dev->id);
+ input_set_drvdata(input_dev, wacom);
+
+ wacom_wac->input = input_dev;
+ wacom_setup_input_capabilities(input_dev, wacom_wac);
+
+ error = input_register_device(input_dev);
+ if (error) {
+ input_free_device(input_dev);
+ wacom_wac->input = NULL;
+ }
+
+ return error;
+}
+
+static void wacom_wireless_work(struct work_struct *work)
+{
+ struct wacom *wacom = container_of(work, struct wacom, work);
+ struct usb_device *usbdev = wacom->usbdev;
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+ /*
+ * Regardless if this is a disconnect or a new tablet,
+ * remove any existing input devices.
+ */
+
+ /* Stylus interface */
+ wacom = usb_get_intfdata(usbdev->config->interface[1]);
+ if (wacom->wacom_wac.input)
+ input_unregister_device(wacom->wacom_wac.input);
+ wacom->wacom_wac.input = 0;
+
+ /* Touch interface */
+ wacom = usb_get_intfdata(usbdev->config->interface[2]);
+ if (wacom->wacom_wac.input)
+ input_unregister_device(wacom->wacom_wac.input);
+ wacom->wacom_wac.input = 0;
+
+ if (wacom_wac->pid == 0) {
+ printk(KERN_INFO "wacom: wireless tablet disconnected\n");
+ } else {
+ const struct usb_device_id *id = wacom_ids;
+
+ printk(KERN_INFO
+ "wacom: wireless tablet connected with PID %x\n",
+ wacom_wac->pid);
+
+ while (id->match_flags) {
+ if (id->idVendor == USB_VENDOR_ID_WACOM &&
+ id->idProduct == wacom_wac->pid)
+ break;
+ id++;
+ }
+
+ if (!id->match_flags) {
+ printk(KERN_INFO
+ "wacom: ignorning unknown PID.\n");
+ return;
+ }
+
+ /* Stylus interface */
+ wacom = usb_get_intfdata(usbdev->config->interface[1]);
+ wacom_wac = &wacom->wacom_wac;
+ wacom_wac->features =
+ *((struct wacom_features *)id->driver_info);
+ wacom_wac->features.device_type = BTN_TOOL_PEN;
+ wacom_register_input(wacom);
+
+ /* Touch interface */
+ wacom = usb_get_intfdata(usbdev->config->interface[2]);
+ wacom_wac = &wacom->wacom_wac;
+ wacom_wac->features =
+ *((struct wacom_features *)id->driver_info);
+ wacom_wac->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
+ wacom_wac->features.device_type = BTN_TOOL_FINGER;
+ wacom_set_phy_from_res(&wacom_wac->features);
+ wacom_wac->features.x_max = wacom_wac->features.y_max = 4096;
+ wacom_register_input(wacom);
+ }
+}
+
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -829,18 +996,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
struct wacom *wacom;
struct wacom_wac *wacom_wac;
struct wacom_features *features;
- struct input_dev *input_dev;
int error;
if (!id->driver_info)
return -EINVAL;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!wacom || !input_dev) {
- error = -ENOMEM;
- goto fail1;
- }
+ if (!wacom)
+ return -ENOMEM;
wacom_wac = &wacom->wacom_wac;
wacom_wac->features = *((struct wacom_features *)id->driver_info);
@@ -866,11 +1029,10 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
+ INIT_WORK(&wacom->work, wacom_wireless_work);
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
- wacom_wac->input = input_dev;
-
endpoint = &intf->cur_altsetting->endpoint[0].desc;
/* Retrieve the physical and logical size for OEM devices */
@@ -894,15 +1056,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
goto fail3;
}
- input_dev->name = wacom_wac->name;
- input_dev->dev.parent = &intf->dev;
- input_dev->open = wacom_open;
- input_dev->close = wacom_close;
- usb_to_input_id(dev, &input_dev->id);
- input_set_drvdata(input_dev, wacom);
-
- wacom_setup_input_capabilities(input_dev, wacom_wac);
-
usb_fill_int_urb(wacom->irq, dev,
usb_rcvintpipe(dev, endpoint->bEndpointAddress),
wacom_wac->data, features->pktlen,
@@ -914,22 +1067,34 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (error)
goto fail4;
- error = input_register_device(input_dev);
+ error = wacom_initialize_battery(wacom);
if (error)
goto fail5;
+ if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
+ error = wacom_register_input(wacom);
+ if (error)
+ goto fail6;
+ }
+
/* Note that if query fails it is not a hard failure */
wacom_query_tablet_data(intf, features);
usb_set_intfdata(intf, wacom);
+
+ if (features->quirks & WACOM_QUIRK_MONITOR) {
+ if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+ goto fail5;
+ }
+
return 0;
+ fail6: wacom_destroy_battery(wacom);
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);
- fail1: input_free_device(input_dev);
- kfree(wacom);
+ fail1: kfree(wacom);
return error;
}
@@ -940,7 +1105,10 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
usb_kill_urb(wacom->irq);
- input_unregister_device(wacom->wacom_wac.input);
+ cancel_work_sync(&wacom->work);
+ if (wacom->wacom_wac.input)
+ input_unregister_device(wacom->wacom_wac.input);
+ wacom_destroy_battery(wacom);
wacom_destroy_leds(wacom);
usb_free_urb(wacom->irq);
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
@@ -972,7 +1140,8 @@ static int wacom_resume(struct usb_interface *intf)
wacom_query_tablet_data(intf, features);
wacom_led_control(wacom);
- if (wacom->open && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
+ if ((wacom->open || features->quirks & WACOM_QUIRK_MONITOR)
+ && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
rv = -EIO;
mutex_unlock(&wacom->lock);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 89a96427faa0..cecd35c8f0b3 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -1044,6 +1044,35 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
return 0;
}
+static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
+{
+ unsigned char *data = wacom->data;
+ int connected;
+
+ if (len != WACOM_PKGLEN_WIRELESS || data[0] != 0x80)
+ return 0;
+
+ connected = data[1] & 0x01;
+ if (connected) {
+ int pid, battery;
+
+ pid = get_unaligned_be16(&data[6]);
+ battery = data[5] & 0x3f;
+ if (wacom->pid != pid) {
+ wacom->pid = pid;
+ wacom_schedule_work(wacom);
+ }
+ wacom->battery_capacity = battery;
+ } else if (wacom->pid != 0) {
+ /* disconnected while previously connected */
+ wacom->pid = 0;
+ wacom_schedule_work(wacom);
+ wacom->battery_capacity = 0;
+ }
+
+ return 0;
+}
+
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
{
bool sync;
@@ -1094,6 +1123,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_bpt_irq(wacom_wac, len);
break;
+ case WIRELESS:
+ sync = wacom_wireless_irq(wacom_wac, len);
+ break;
+
default:
sync = false;
break;
@@ -1155,7 +1188,7 @@ void wacom_setup_device_quirks(struct wacom_features *features)
/* these device have multiple inputs */
if (features->type == TABLETPC || features->type == TABLETPC2FG ||
- features->type == BAMBOO_PT)
+ features->type == BAMBOO_PT || features->type == WIRELESS)
features->quirks |= WACOM_QUIRK_MULTI_INPUT;
/* quirk for bamboo touch with 2 low res touches */
@@ -1167,6 +1200,16 @@ void wacom_setup_device_quirks(struct wacom_features *features)
features->y_fuzz <<= 5;
features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
}
+
+ if (features->type == WIRELESS) {
+
+ /* monitor never has input and pen/touch have delayed create */
+ features->quirks |= WACOM_QUIRK_NO_INPUT;
+
+ /* must be monitor interface if no device_type set */
+ if (!features->device_type)
+ features->quirks |= WACOM_QUIRK_MONITOR;
+ }
}
static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
@@ -1640,6 +1683,9 @@ static const struct wacom_features wacom_features_0xEC =
static const struct wacom_features wacom_features_0x47 =
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x84 =
+ { "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0,
+ 0, WIRELESS, 0, 0 };
static const struct wacom_features wacom_features_0xD0 =
{ "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1766,6 +1812,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
+ { USB_DEVICE_WACOM(0x84) },
{ USB_DEVICE_WACOM(0xD0) },
{ USB_DEVICE_WACOM(0xD1) },
{ USB_DEVICE_WACOM(0xD2) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 4f0ba21b0196..ba5a334e54d6 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -24,6 +24,7 @@
#define WACOM_PKGLEN_BBTOUCH 20
#define WACOM_PKGLEN_BBTOUCH3 64
#define WACOM_PKGLEN_BBPEN 10
+#define WACOM_PKGLEN_WIRELESS 32
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
@@ -45,6 +46,8 @@
/* device quirks */
#define WACOM_QUIRK_MULTI_INPUT 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
+#define WACOM_QUIRK_NO_INPUT 0x0004
+#define WACOM_QUIRK_MONITOR 0x0008
enum {
PENPARTNER = 0,
@@ -54,6 +57,7 @@ enum {
PL,
DTU,
BAMBOO_PT,
+ WIRELESS,
INTUOS,
INTUOS3S,
INTUOS3,
@@ -107,6 +111,8 @@ struct wacom_wac {
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
+ int pid;
+ int battery_capacity;
};
#endif
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index ede02743eac1..48dc5b0d26f1 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -39,6 +39,7 @@ struct mc13783_ts_priv {
struct delayed_work work;
struct workqueue_struct *workq;
unsigned int sample[4];
+ struct mc13xxx_ts_platform_data *touch;
};
static irqreturn_t mc13783_ts_handler(int irq, void *data)
@@ -125,7 +126,9 @@ static void mc13783_ts_work(struct work_struct *work)
unsigned int channel = 12;
if (mc13xxx_adc_do_conversion(priv->mc13xxx,
- mode, channel, priv->sample) == 0)
+ mode, channel,
+ priv->touch->ato, priv->touch->atox,
+ priv->sample) == 0)
mc13783_ts_report_sample(priv);
}
@@ -179,6 +182,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
priv->idev = idev;
+ priv->touch = dev_get_platdata(&pdev->dev);
+ if (!priv->touch) {
+ dev_err(&pdev->dev, "missing platform data\n");
+ ret = -ENODEV;
+ goto err_free_mem;
+ }
/*
* We need separate workqueue because mc13783_adc_do_conversion
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 44b50cc645e6..c21353d8e915 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -18,7 +18,6 @@
#include <linux/serial.h>
#include <linux/major.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 33e3c94887d8..c644557ae614 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index fe254e74a850..a8c4d3fc9a6d 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -44,7 +44,6 @@
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 68f50495d166..f0dfc0c976eb 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -44,7 +44,6 @@
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index bfe94284b0d5..4deac451807c 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -25,7 +25,6 @@
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
index 7f3c54d40474..c59e8d2c0675 100644
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ b/drivers/isdn/i4l/isdn_bsdcomp.c
@@ -69,7 +69,6 @@
#include <linux/signal.h> /* used in new tty drivers */
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/types.h>
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index 682911f81138..a18e639b40d7 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -36,7 +36,6 @@
#include <linux/isdnif.h>
-#include <asm/system.h>
#include <asm/io.h>
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 4ca00624bd18..5b61aaf7ac0f 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -114,6 +114,27 @@ static inline int __blink_ctl_mask(int port)
return ret;
}
+static int led_power_set(struct pm860x_chip *chip, int port, int on)
+{
+ int ret = -EINVAL;
+
+ switch (port) {
+ case PM8606_LED1_RED:
+ case PM8606_LED1_GREEN:
+ case PM8606_LED1_BLUE:
+ ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) :
+ pm8606_osc_disable(chip, RGB1_ENABLE);
+ break;
+ case PM8606_LED2_RED:
+ case PM8606_LED2_GREEN:
+ case PM8606_LED2_BLUE:
+ ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) :
+ pm8606_osc_disable(chip, RGB2_ENABLE);
+ break;
+ }
+ return ret;
+}
+
static void pm860x_led_work(struct work_struct *work)
{
@@ -126,6 +147,7 @@ static void pm860x_led_work(struct work_struct *work)
chip = led->chip;
mutex_lock(&led->lock);
if ((led->current_brightness == 0) && led->brightness) {
+ led_power_set(chip, led->port, 1);
if (led->iset) {
pm860x_set_bits(led->i2c, __led_off(led->port),
LED_CURRENT_MASK, led->iset);
@@ -149,6 +171,7 @@ static void pm860x_led_work(struct work_struct *work)
LED_CURRENT_MASK, 0);
mask = __blink_ctl_mask(led->port);
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
+ led_power_set(chip, led->port, 0);
}
}
led->current_brightness = led->brightness;
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index b6ef8f590764..87de8d9bcfad 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -14,7 +14,6 @@
#include <asm/pgtable.h>
#include <asm/hydra.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <linux/init.h>
#include <linux/ioport.h>
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index c60d025044ee..fc71723cbc48 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -29,7 +29,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#undef DEBUG
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 0ff92c208005..97cfc5ac9fd0 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -127,7 +127,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/macio.h>
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 46c4e95f10d6..3b4a157714b1 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -41,7 +41,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/macio.h>
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 971bc9582a5f..86511c570dd8 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -26,7 +26,6 @@
#include <asm/mac_via.h>
#endif
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/init.h>
static volatile unsigned char __iomem *via;
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index c9570fcf1cce..3725f088f17e 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -34,7 +34,6 @@
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_via.h>
-#include <asm/system.h>
static volatile unsigned char *via;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 6cccd60c594e..22b8ce4191cc 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -50,7 +50,6 @@
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/pmac_feature.h>
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index aeb30d07d5a2..a00ee41f0573 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -37,7 +37,6 @@
#include <asm/mac_via.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 647c6add2193..4d6a90a1372b 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -18,7 +18,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/pmac_low_i2c.h>
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
index 30e6195e19d4..04067e073aa9 100644
--- a/drivers/macintosh/windfarm_pm121.c
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -215,7 +215,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/smu.h>
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index 749d174b0dc6..fc13d0f2663b 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -107,7 +107,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/smu.h>
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 344273235124..a9430ed4f36c 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -41,7 +41,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/smu.h>
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 43137b421f92..3c2be5193fd5 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -18,7 +18,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/smu.h>
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 3c193504bb80..1cc4e4953d89 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -18,7 +18,6 @@
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sections.h>
#include <asm/smu.h>
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index faa4741df6d3..10f122a3a856 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -277,8 +277,8 @@ config DM_MIRROR
needed for live data migration tools such as 'pvmove'.
config DM_RAID
- tristate "RAID 1/4/5/6 target (EXPERIMENTAL)"
- depends on BLK_DEV_DM && EXPERIMENTAL
+ tristate "RAID 1/4/5/6 target"
+ depends on BLK_DEV_DM
select MD_RAID1
select MD_RAID456
select BLK_DEV_MD
@@ -359,8 +359,8 @@ config DM_DELAY
If unsure, say N.
config DM_UEVENT
- bool "DM uevents (EXPERIMENTAL)"
- depends on BLK_DEV_DM && EXPERIMENTAL
+ bool "DM uevents"
+ depends on BLK_DEV_DM
---help---
Generate udev events for DM events.
@@ -370,4 +370,24 @@ config DM_FLAKEY
---help---
A target that intermittently fails I/O for debugging purposes.
+config DM_VERITY
+ tristate "Verity target support (EXPERIMENTAL)"
+ depends on BLK_DEV_DM && EXPERIMENTAL
+ select CRYPTO
+ select CRYPTO_HASH
+ select DM_BUFIO
+ ---help---
+ This device-mapper target creates a read-only device that
+ transparently validates the data on one underlying device against
+ a pre-generated tree of cryptographic checksums stored on a second
+ device.
+
+ You'll need to activate the digests you're going to use in the
+ cryptoapi configuration.
+
+ To compile this code as a module, choose M here: the module will
+ be called dm-verity.
+
+ If unsure, say N.
+
endif # MD
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 046860c7a166..8b2e0dffe82e 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
obj-$(CONFIG_DM_RAID) += dm-raid.o
obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o
+obj-$(CONFIG_DM_VERITY) += dm-verity.o
ifeq ($(CONFIG_DM_UEVENT),y)
dm-mod-objs += dm-uevent.o
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index b6e58c7b6df5..cc06a1e52423 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -578,7 +578,7 @@ static void write_endio(struct bio *bio, int error)
struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);
b->write_error = error;
- if (error) {
+ if (unlikely(error)) {
struct dm_bufio_client *c = b->c;
(void)cmpxchg(&c->async_write_error, 0, error);
}
@@ -697,13 +697,20 @@ static void __wait_for_free_buffer(struct dm_bufio_client *c)
dm_bufio_lock(c);
}
+enum new_flag {
+ NF_FRESH = 0,
+ NF_READ = 1,
+ NF_GET = 2,
+ NF_PREFETCH = 3
+};
+
/*
* Allocate a new buffer. If the allocation is not possible, wait until
* some other thread frees a buffer.
*
* May drop the lock and regain it.
*/
-static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
{
struct dm_buffer *b;
@@ -726,6 +733,9 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client
return b;
}
+ if (nf == NF_PREFETCH)
+ return NULL;
+
if (!list_empty(&c->reserved_buffers)) {
b = list_entry(c->reserved_buffers.next,
struct dm_buffer, lru_list);
@@ -743,9 +753,12 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client
}
}
-static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c, enum new_flag nf)
{
- struct dm_buffer *b = __alloc_buffer_wait_no_callback(c);
+ struct dm_buffer *b = __alloc_buffer_wait_no_callback(c, nf);
+
+ if (!b)
+ return NULL;
if (c->alloc_callback)
c->alloc_callback(b);
@@ -865,32 +878,23 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
* Getting a buffer
*--------------------------------------------------------------*/
-enum new_flag {
- NF_FRESH = 0,
- NF_READ = 1,
- NF_GET = 2
-};
-
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
- enum new_flag nf, struct dm_buffer **bp,
- int *need_submit)
+ enum new_flag nf, int *need_submit)
{
struct dm_buffer *b, *new_b = NULL;
*need_submit = 0;
b = __find(c, block);
- if (b) {
- b->hold_count++;
- __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
- test_bit(B_WRITING, &b->state));
- return b;
- }
+ if (b)
+ goto found_buffer;
if (nf == NF_GET)
return NULL;
- new_b = __alloc_buffer_wait(c);
+ new_b = __alloc_buffer_wait(c, nf);
+ if (!new_b)
+ return NULL;
/*
* We've had a period where the mutex was unlocked, so need to
@@ -899,10 +903,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
b = __find(c, block);
if (b) {
__free_buffer_wake(new_b);
- b->hold_count++;
- __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
- test_bit(B_WRITING, &b->state));
- return b;
+ goto found_buffer;
}
__check_watermark(c);
@@ -922,6 +923,24 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
*need_submit = 1;
return b;
+
+found_buffer:
+ if (nf == NF_PREFETCH)
+ return NULL;
+ /*
+ * Note: it is essential that we don't wait for the buffer to be
+ * read if dm_bufio_get function is used. Both dm_bufio_get and
+ * dm_bufio_prefetch can be used in the driver request routine.
+ * If the user called both dm_bufio_prefetch and dm_bufio_get on
+ * the same buffer, it would deadlock if we waited.
+ */
+ if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
+ return NULL;
+
+ b->hold_count++;
+ __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
+ test_bit(B_WRITING, &b->state));
+ return b;
}
/*
@@ -956,10 +975,10 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
struct dm_buffer *b;
dm_bufio_lock(c);
- b = __bufio_new(c, block, nf, bp, &need_submit);
+ b = __bufio_new(c, block, nf, &need_submit);
dm_bufio_unlock(c);
- if (!b || IS_ERR(b))
+ if (!b)
return b;
if (need_submit)
@@ -1005,13 +1024,47 @@ void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
}
EXPORT_SYMBOL_GPL(dm_bufio_new);
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+ sector_t block, unsigned n_blocks)
+{
+ struct blk_plug plug;
+
+ blk_start_plug(&plug);
+ dm_bufio_lock(c);
+
+ for (; n_blocks--; block++) {
+ int need_submit;
+ struct dm_buffer *b;
+ b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+ if (unlikely(b != NULL)) {
+ dm_bufio_unlock(c);
+
+ if (need_submit)
+ submit_io(b, READ, b->block, read_endio);
+ dm_bufio_release(b);
+
+ dm_bufio_cond_resched();
+
+ if (!n_blocks)
+ goto flush_plug;
+ dm_bufio_lock(c);
+ }
+
+ }
+
+ dm_bufio_unlock(c);
+
+flush_plug:
+ blk_finish_plug(&plug);
+}
+EXPORT_SYMBOL_GPL(dm_bufio_prefetch);
+
void dm_bufio_release(struct dm_buffer *b)
{
struct dm_bufio_client *c = b->c;
dm_bufio_lock(c);
- BUG_ON(test_bit(B_READING, &b->state));
BUG_ON(!b->hold_count);
b->hold_count--;
@@ -1024,6 +1077,7 @@ void dm_bufio_release(struct dm_buffer *b)
* invalid buffer.
*/
if ((b->read_error || b->write_error) &&
+ !test_bit(B_READING, &b->state) &&
!test_bit(B_WRITING, &b->state) &&
!test_bit(B_DIRTY, &b->state)) {
__unlink_buffer(b);
@@ -1041,6 +1095,8 @@ void dm_bufio_mark_buffer_dirty(struct dm_buffer *b)
dm_bufio_lock(c);
+ BUG_ON(test_bit(B_READING, &b->state));
+
if (!test_and_set_bit(B_DIRTY, &b->state))
__relink_lru(b, LIST_DIRTY);
diff --git a/drivers/md/dm-bufio.h b/drivers/md/dm-bufio.h
index 5c4c3a04e381..b142946a9e32 100644
--- a/drivers/md/dm-bufio.h
+++ b/drivers/md/dm-bufio.h
@@ -63,6 +63,14 @@ void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
struct dm_buffer **bp);
/*
+ * Prefetch the specified blocks to the cache.
+ * The function starts to read the blocks and returns without waiting for
+ * I/O to finish.
+ */
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+ sector_t block, unsigned n_blocks);
+
+/*
* Release a reference obtained with dm_bufio_{read,get,new}. The data
* pointer and dm_buffer pointer is no longer valid after this call.
*/
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index db6b51639cee..3f06df59fd82 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -176,7 +176,6 @@ struct crypt_config {
#define MIN_IOS 16
#define MIN_POOL_PAGES 32
-#define MIN_BIO_PAGES 8
static struct kmem_cache *_crypt_io_pool;
@@ -848,12 +847,11 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
}
/*
- * if additional pages cannot be allocated without waiting,
- * return a partially allocated bio, the caller will then try
- * to allocate additional bios while submitting this partial bio
+ * If additional pages cannot be allocated without waiting,
+ * return a partially-allocated bio. The caller will then try
+ * to allocate more bios while submitting this partial bio.
*/
- if (i == (MIN_BIO_PAGES - 1))
- gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+ gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
@@ -1046,16 +1044,14 @@ static void kcryptd_queue_io(struct dm_crypt_io *io)
queue_work(cc->io_queue, &io->work);
}
-static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
- int error, int async)
+static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
{
struct bio *clone = io->ctx.bio_out;
struct crypt_config *cc = io->target->private;
- if (unlikely(error < 0)) {
+ if (unlikely(io->error < 0)) {
crypt_free_buffer_pages(cc, clone);
bio_put(clone);
- io->error = -EIO;
crypt_dec_pending(io);
return;
}
@@ -1106,12 +1102,16 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
sector += bio_sectors(clone);
crypt_inc_pending(io);
+
r = crypt_convert(cc, &io->ctx);
+ if (r < 0)
+ io->error = -EIO;
+
crypt_finished = atomic_dec_and_test(&io->ctx.pending);
/* Encryption was already finished, submit io now */
if (crypt_finished) {
- kcryptd_crypt_write_io_submit(io, r, 0);
+ kcryptd_crypt_write_io_submit(io, 0);
/*
* If there was an error, do not try next fragments.
@@ -1162,11 +1162,8 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
crypt_dec_pending(io);
}
-static void kcryptd_crypt_read_done(struct dm_crypt_io *io, int error)
+static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
{
- if (unlikely(error < 0))
- io->error = -EIO;
-
crypt_dec_pending(io);
}
@@ -1181,9 +1178,11 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
io->sector);
r = crypt_convert(cc, &io->ctx);
+ if (r < 0)
+ io->error = -EIO;
if (atomic_dec_and_test(&io->ctx.pending))
- kcryptd_crypt_read_done(io, r);
+ kcryptd_crypt_read_done(io);
crypt_dec_pending(io);
}
@@ -1204,15 +1203,18 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post)
error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq);
+ if (error < 0)
+ io->error = -EIO;
+
mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
if (!atomic_dec_and_test(&ctx->pending))
return;
if (bio_data_dir(io->base_bio) == READ)
- kcryptd_crypt_read_done(io, error);
+ kcryptd_crypt_read_done(io);
else
- kcryptd_crypt_write_io_submit(io, error, 1);
+ kcryptd_crypt_write_io_submit(io, 1);
}
static void kcryptd_crypt(struct work_struct *work)
@@ -1413,6 +1415,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
char *cipher_api = NULL;
int cpu, ret = -EINVAL;
+ char dummy;
/* Convert to crypto api definition? */
if (strchr(cipher_in, '(')) {
@@ -1434,7 +1437,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
if (!keycount)
cc->tfms_count = 1;
- else if (sscanf(keycount, "%u", &cc->tfms_count) != 1 ||
+ else if (sscanf(keycount, "%u%c", &cc->tfms_count, &dummy) != 1 ||
!is_power_of_2(cc->tfms_count)) {
ti->error = "Bad cipher key count specification";
return -EINVAL;
@@ -1579,6 +1582,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
int ret;
struct dm_arg_set as;
const char *opt_string;
+ char dummy;
static struct dm_arg _args[] = {
{0, 1, "Invalid number of feature args"},
@@ -1636,7 +1640,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ret = -EINVAL;
- if (sscanf(argv[2], "%llu", &tmpll) != 1) {
+ if (sscanf(argv[2], "%llu%c", &tmpll, &dummy) != 1) {
ti->error = "Invalid iv_offset sector";
goto bad;
}
@@ -1647,7 +1651,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
- if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+ if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
ti->error = "Invalid device sector";
goto bad;
}
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index f18375dcedd9..2dc22dddb2ae 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -131,6 +131,7 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct delay_c *dc;
unsigned long long tmpll;
+ char dummy;
if (argc != 3 && argc != 6) {
ti->error = "requires exactly 3 or 6 arguments";
@@ -145,13 +146,13 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
dc->reads = dc->writes = 0;
- if (sscanf(argv[1], "%llu", &tmpll) != 1) {
+ if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) {
ti->error = "Invalid device sector";
goto bad;
}
dc->start_read = tmpll;
- if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
+ if (sscanf(argv[2], "%u%c", &dc->read_delay, &dummy) != 1) {
ti->error = "Invalid delay";
goto bad;
}
@@ -166,13 +167,13 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (argc == 3)
goto out;
- if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+ if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
ti->error = "Invalid write device sector";
goto bad_dev_read;
}
dc->start_write = tmpll;
- if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
+ if (sscanf(argv[5], "%u%c", &dc->write_delay, &dummy) != 1) {
ti->error = "Invalid write delay";
goto bad_dev_read;
}
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 042e71996569..aa70f7d43a1a 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -283,7 +283,7 @@ int dm_exception_store_init(void)
return 0;
persistent_fail:
- dm_persistent_snapshot_exit();
+ dm_transient_snapshot_exit();
transient_fail:
return r;
}
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index b280c433e4a0..ac49c01f1a44 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -160,6 +160,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned long long tmpll;
struct dm_arg_set as;
const char *devname;
+ char dummy;
as.argc = argc;
as.argv = argv;
@@ -178,7 +179,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
devname = dm_shift_arg(&as);
- if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) {
+ if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) {
ti->error = "Invalid device sector";
goto bad;
}
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 1ce84ed0b765..a1a3e6df17b8 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -880,6 +880,7 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
struct hd_geometry geometry;
unsigned long indata[4];
char *geostr = (char *) param + param->data_start;
+ char dummy;
md = find_device(param);
if (!md)
@@ -891,8 +892,8 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
goto out;
}
- x = sscanf(geostr, "%lu %lu %lu %lu", indata,
- indata + 1, indata + 2, indata + 3);
+ x = sscanf(geostr, "%lu %lu %lu %lu%c", indata,
+ indata + 1, indata + 2, indata + 3, &dummy);
if (x != 4) {
DMWARN("Unable to interpret geometry settings.");
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 9728839f844a..3639eeab6042 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -29,6 +29,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct linear_c *lc;
unsigned long long tmp;
+ char dummy;
if (argc != 2) {
ti->error = "Invalid argument count";
@@ -41,7 +42,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return -ENOMEM;
}
- if (sscanf(argv[1], "%llu", &tmp) != 1) {
+ if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) {
ti->error = "dm-linear: Invalid device sector";
goto bad;
}
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 3b52bb72bd1f..65ebaebf502b 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -369,6 +369,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
unsigned int region_count;
size_t bitset_size, buf_size;
int r;
+ char dummy;
if (argc < 1 || argc > 2) {
DMWARN("wrong number of arguments to dirty region log");
@@ -387,7 +388,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
}
}
- if (sscanf(argv[0], "%u", &region_size) != 1 ||
+ if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
!_check_region_size(ti, region_size)) {
DMWARN("invalid region size %s", argv[0]);
return -EINVAL;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 801d92d237cf..922a3385eead 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -226,6 +226,27 @@ static void free_multipath(struct multipath *m)
kfree(m);
}
+static int set_mapinfo(struct multipath *m, union map_info *info)
+{
+ struct dm_mpath_io *mpio;
+
+ mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
+ if (!mpio)
+ return -ENOMEM;
+
+ memset(mpio, 0, sizeof(*mpio));
+ info->ptr = mpio;
+
+ return 0;
+}
+
+static void clear_mapinfo(struct multipath *m, union map_info *info)
+{
+ struct dm_mpath_io *mpio = info->ptr;
+
+ info->ptr = NULL;
+ mempool_free(mpio, m->mpio_pool);
+}
/*-----------------------------------------------
* Path selection
@@ -341,13 +362,14 @@ static int __must_push_back(struct multipath *m)
}
static int map_io(struct multipath *m, struct request *clone,
- struct dm_mpath_io *mpio, unsigned was_queued)
+ union map_info *map_context, unsigned was_queued)
{
int r = DM_MAPIO_REMAPPED;
size_t nr_bytes = blk_rq_bytes(clone);
unsigned long flags;
struct pgpath *pgpath;
struct block_device *bdev;
+ struct dm_mpath_io *mpio = map_context->ptr;
spin_lock_irqsave(&m->lock, flags);
@@ -423,7 +445,6 @@ static void dispatch_queued_ios(struct multipath *m)
{
int r;
unsigned long flags;
- struct dm_mpath_io *mpio;
union map_info *info;
struct request *clone, *n;
LIST_HEAD(cl);
@@ -436,16 +457,15 @@ static void dispatch_queued_ios(struct multipath *m)
list_del_init(&clone->queuelist);
info = dm_get_rq_mapinfo(clone);
- mpio = info->ptr;
- r = map_io(m, clone, mpio, 1);
+ r = map_io(m, clone, info, 1);
if (r < 0) {
- mempool_free(mpio, m->mpio_pool);
+ clear_mapinfo(m, info);
dm_kill_unmapped_request(clone, r);
} else if (r == DM_MAPIO_REMAPPED)
dm_dispatch_request(clone);
else if (r == DM_MAPIO_REQUEUE) {
- mempool_free(mpio, m->mpio_pool);
+ clear_mapinfo(m, info);
dm_requeue_unmapped_request(clone);
}
}
@@ -908,20 +928,16 @@ static int multipath_map(struct dm_target *ti, struct request *clone,
union map_info *map_context)
{
int r;
- struct dm_mpath_io *mpio;
struct multipath *m = (struct multipath *) ti->private;
- mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
- if (!mpio)
+ if (set_mapinfo(m, map_context) < 0)
/* ENOMEM, requeue */
return DM_MAPIO_REQUEUE;
- memset(mpio, 0, sizeof(*mpio));
- map_context->ptr = mpio;
clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
- r = map_io(m, clone, mpio, 0);
+ r = map_io(m, clone, map_context, 0);
if (r < 0 || r == DM_MAPIO_REQUEUE)
- mempool_free(mpio, m->mpio_pool);
+ clear_mapinfo(m, map_context);
return r;
}
@@ -1054,8 +1070,9 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)
struct priority_group *pg;
unsigned pgnum;
unsigned long flags;
+ char dummy;
- if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+ if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
(pgnum > m->nr_priority_groups)) {
DMWARN("invalid PG number supplied to switch_pg_num");
return -EINVAL;
@@ -1085,8 +1102,9 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
{
struct priority_group *pg;
unsigned pgnum;
+ char dummy;
- if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+ if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
(pgnum > m->nr_priority_groups)) {
DMWARN("invalid PG number supplied to bypass_pg");
return -EINVAL;
@@ -1261,13 +1279,15 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
struct path_selector *ps;
int r;
+ BUG_ON(!mpio);
+
r = do_end_io(m, clone, error, mpio);
if (pgpath) {
ps = &pgpath->pg->ps;
if (ps->type->end_io)
ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes);
}
- mempool_free(mpio, m->mpio_pool);
+ clear_mapinfo(m, map_context);
return r;
}
diff --git a/drivers/md/dm-queue-length.c b/drivers/md/dm-queue-length.c
index 03a837aa5ce6..3941fae0de9f 100644
--- a/drivers/md/dm-queue-length.c
+++ b/drivers/md/dm-queue-length.c
@@ -112,6 +112,7 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
struct selector *s = ps->context;
struct path_info *pi;
unsigned repeat_count = QL_MIN_IO;
+ char dummy;
/*
* Arguments: [<repeat_count>]
@@ -123,7 +124,7 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
return -EINVAL;
}
- if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+ if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
*error = "queue-length ps: invalid repeat count";
return -EINVAL;
}
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index c5a875d7b882..b0ba52459ed7 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -604,7 +604,9 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
return 0;
if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
- DMERR("Failed to read device superblock");
+ DMERR("Failed to read superblock of device at position %d",
+ rdev->raid_disk);
+ set_bit(Faulty, &rdev->flags);
return -EINVAL;
}
@@ -855,9 +857,25 @@ static int super_validate(struct mddev *mddev, struct md_rdev *rdev)
static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
{
int ret;
+ unsigned redundancy = 0;
+ struct raid_dev *dev;
struct md_rdev *rdev, *freshest;
struct mddev *mddev = &rs->md;
+ switch (rs->raid_type->level) {
+ case 1:
+ redundancy = rs->md.raid_disks - 1;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ redundancy = rs->raid_type->parity_devs;
+ break;
+ default:
+ ti->error = "Unknown RAID type";
+ return -EINVAL;
+ }
+
freshest = NULL;
rdev_for_each(rdev, mddev) {
if (!rdev->meta_bdev)
@@ -872,6 +890,37 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
case 0:
break;
default:
+ dev = container_of(rdev, struct raid_dev, rdev);
+ if (redundancy--) {
+ if (dev->meta_dev)
+ dm_put_device(ti, dev->meta_dev);
+
+ dev->meta_dev = NULL;
+ rdev->meta_bdev = NULL;
+
+ if (rdev->sb_page)
+ put_page(rdev->sb_page);
+
+ rdev->sb_page = NULL;
+
+ rdev->sb_loaded = 0;
+
+ /*
+ * We might be able to salvage the data device
+ * even though the meta device has failed. For
+ * now, we behave as though '- -' had been
+ * set for this device in the table.
+ */
+ if (dev->data_dev)
+ dm_put_device(ti, dev->data_dev);
+
+ dev->data_dev = NULL;
+ rdev->bdev = NULL;
+
+ list_del(&rdev->same_set);
+
+ continue;
+ }
ti->error = "Failed to load superblock";
return ret;
}
@@ -1214,7 +1263,7 @@ static void raid_resume(struct dm_target *ti)
static struct target_type raid_target = {
.name = "raid",
- .version = {1, 1, 0},
+ .version = {1, 2, 0},
.module = THIS_MODULE,
.ctr = raid_ctr,
.dtr = raid_dtr,
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 9bfd057be686..d039de8322f0 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -924,8 +924,9 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
unsigned int mirror, char **argv)
{
unsigned long long offset;
+ char dummy;
- if (sscanf(argv[1], "%llu", &offset) != 1) {
+ if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) {
ti->error = "Invalid offset";
return -EINVAL;
}
@@ -953,13 +954,14 @@ static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
{
unsigned param_count;
struct dm_dirty_log *dl;
+ char dummy;
if (argc < 2) {
ti->error = "Insufficient mirror log arguments";
return NULL;
}
- if (sscanf(argv[1], "%u", &param_count) != 1) {
+ if (sscanf(argv[1], "%u%c", &param_count, &dummy) != 1) {
ti->error = "Invalid mirror log argument count";
return NULL;
}
@@ -986,13 +988,14 @@ static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
{
unsigned num_features;
struct dm_target *ti = ms->ti;
+ char dummy;
*args_used = 0;
if (!argc)
return 0;
- if (sscanf(argv[0], "%u", &num_features) != 1) {
+ if (sscanf(argv[0], "%u%c", &num_features, &dummy) != 1) {
ti->error = "Invalid number of features";
return -EINVAL;
}
@@ -1036,6 +1039,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned int nr_mirrors, m, args_used;
struct mirror_set *ms;
struct dm_dirty_log *dl;
+ char dummy;
dl = create_dirty_log(ti, argc, argv, &args_used);
if (!dl)
@@ -1044,7 +1048,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argv += args_used;
argc -= args_used;
- if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
+ if (!argc || sscanf(argv[0], "%u%c", &nr_mirrors, &dummy) != 1 ||
nr_mirrors < 2 || nr_mirrors > DM_KCOPYD_MAX_REGIONS + 1) {
ti->error = "Invalid number of mirrors";
dm_dirty_log_destroy(dl);
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index 27f1d423b76c..6ab1192cdd5f 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -114,6 +114,7 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
struct selector *s = (struct selector *) ps->context;
struct path_info *pi;
unsigned repeat_count = RR_MIN_IO;
+ char dummy;
if (argc > 1) {
*error = "round-robin ps: incorrect number of arguments";
@@ -121,7 +122,7 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
}
/* First path argument is number of I/Os before switching path */
- if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+ if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
*error = "round-robin ps: invalid repeat count";
return -EINVAL;
}
diff --git a/drivers/md/dm-service-time.c b/drivers/md/dm-service-time.c
index 59883bd78214..9df8f6bd6418 100644
--- a/drivers/md/dm-service-time.c
+++ b/drivers/md/dm-service-time.c
@@ -110,6 +110,7 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
struct path_info *pi;
unsigned repeat_count = ST_MIN_IO;
unsigned relative_throughput = 1;
+ char dummy;
/*
* Arguments: [<repeat_count> [<relative_throughput>]]
@@ -128,13 +129,13 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
return -EINVAL;
}
- if (argc && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+ if (argc && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
*error = "service-time ps: invalid repeat count";
return -EINVAL;
}
if ((argc == 2) &&
- (sscanf(argv[1], "%u", &relative_throughput) != 1 ||
+ (sscanf(argv[1], "%u%c", &relative_throughput, &dummy) != 1 ||
relative_throughput > ST_MAX_RELATIVE_THROUGHPUT)) {
*error = "service-time ps: invalid relative_throughput value";
return -EINVAL;
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 3d80cf0c152d..35c94ff24ad5 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -75,8 +75,9 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
unsigned int stripe, char **argv)
{
unsigned long long start;
+ char dummy;
- if (sscanf(argv[1], "%llu", &start) != 1)
+ if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1)
return -EINVAL;
if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 63cc54289aff..2e227fbf1622 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -268,8 +268,7 @@ void dm_table_destroy(struct dm_table *t)
vfree(t->highs);
/* free the device list */
- if (t->devices.next != &t->devices)
- free_devices(&t->devices);
+ free_devices(&t->devices);
dm_free_md_mempools(t->mempools);
@@ -464,10 +463,11 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
struct dm_dev_internal *dd;
unsigned int major, minor;
struct dm_table *t = ti->table;
+ char dummy;
BUG_ON(!t);
- if (sscanf(path, "%u:%u", &major, &minor) == 2) {
+ if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
/* Extract the major/minor numbers */
dev = MKDEV(major, minor);
if (MAJOR(dev) != major || MINOR(dev) != minor)
@@ -842,9 +842,10 @@ static int validate_next_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
unsigned *value, char **error, unsigned grouped)
{
const char *arg_str = dm_shift_arg(arg_set);
+ char dummy;
if (!arg_str ||
- (sscanf(arg_str, "%u", value) != 1) ||
+ (sscanf(arg_str, "%u%c", value, &dummy) != 1) ||
(*value < arg->min) ||
(*value > arg->max) ||
(grouped && arg_set->argc < *value)) {
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 237571af77fd..737d38865b69 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -614,7 +614,7 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
if (r < 0)
goto out;
- r = dm_sm_root_size(pmd->metadata_sm, &data_len);
+ r = dm_sm_root_size(pmd->data_sm, &data_len);
if (r < 0)
goto out;
@@ -713,6 +713,9 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
if (r)
goto bad;
+ if (bdev_size > THIN_METADATA_MAX_SECTORS)
+ bdev_size = THIN_METADATA_MAX_SECTORS;
+
disk_super = dm_block_data(sblock);
disk_super->magic = cpu_to_le64(THIN_SUPERBLOCK_MAGIC);
disk_super->version = cpu_to_le32(THIN_VERSION);
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 859c16896877..ed4725e67c96 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -11,6 +11,19 @@
#define THIN_METADATA_BLOCK_SIZE 4096
+/*
+ * The metadata device is currently limited in size.
+ *
+ * We have one block of index, which can hold 255 index entries. Each
+ * index entry contains allocation info about 16k metadata blocks.
+ */
+#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
+
+/*
+ * A metadata device larger than 16GB triggers a warning.
+ */
+#define THIN_METADATA_MAX_SECTORS_WARNING (16 * (1024 * 1024 * 1024 >> SECTOR_SHIFT))
+
/*----------------------------------------------------------------*/
struct dm_pool_metadata;
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index c3087575fef0..213ae32a0fc4 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -23,6 +23,7 @@
#define DEFERRED_SET_SIZE 64
#define MAPPING_POOL_SIZE 1024
#define PRISON_CELLS 1024
+#define COMMIT_PERIOD HZ
/*
* The block size of the device holding pool data must be
@@ -32,16 +33,6 @@
#define DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
/*
- * The metadata device is currently limited in size. The limitation is
- * checked lower down in dm-space-map-metadata, but we also check it here
- * so we can fail early.
- *
- * We have one block of index, which can hold 255 index entries. Each
- * index entry contains allocation info about 16k metadata blocks.
- */
-#define METADATA_DEV_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
-
-/*
* Device id is restricted to 24 bits.
*/
#define MAX_DEV_ID ((1 << 24) - 1)
@@ -72,7 +63,7 @@
* missed out if the io covers the block. (schedule_copy).
*
* iv) insert the new mapping into the origin's btree
- * (process_prepared_mappings). This act of inserting breaks some
+ * (process_prepared_mapping). This act of inserting breaks some
* sharing of btree nodes between the two devices. Breaking sharing only
* effects the btree of that specific device. Btrees for the other
* devices that share the block never change. The btree for the origin
@@ -124,7 +115,7 @@ struct cell {
struct hlist_node list;
struct bio_prison *prison;
struct cell_key key;
- unsigned count;
+ struct bio *holder;
struct bio_list bios;
};
@@ -220,54 +211,59 @@ static struct cell *__search_bucket(struct hlist_head *bucket,
* This may block if a new cell needs allocating. You must ensure that
* cells will be unlocked even if the calling thread is blocked.
*
- * Returns the number of entries in the cell prior to the new addition
- * or < 0 on failure.
+ * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
*/
static int bio_detain(struct bio_prison *prison, struct cell_key *key,
struct bio *inmate, struct cell **ref)
{
- int r;
+ int r = 1;
unsigned long flags;
uint32_t hash = hash_key(prison, key);
- struct cell *uninitialized_var(cell), *cell2 = NULL;
+ struct cell *cell, *cell2;
BUG_ON(hash > prison->nr_buckets);
spin_lock_irqsave(&prison->lock, flags);
+
cell = __search_bucket(prison->cells + hash, key);
+ if (cell) {
+ bio_list_add(&cell->bios, inmate);
+ goto out;
+ }
- if (!cell) {
- /*
- * Allocate a new cell
- */
- spin_unlock_irqrestore(&prison->lock, flags);
- cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
- spin_lock_irqsave(&prison->lock, flags);
+ /*
+ * Allocate a new cell
+ */
+ spin_unlock_irqrestore(&prison->lock, flags);
+ cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
+ spin_lock_irqsave(&prison->lock, flags);
- /*
- * We've been unlocked, so we have to double check that
- * nobody else has inserted this cell in the meantime.
- */
- cell = __search_bucket(prison->cells + hash, key);
+ /*
+ * We've been unlocked, so we have to double check that
+ * nobody else has inserted this cell in the meantime.
+ */
+ cell = __search_bucket(prison->cells + hash, key);
+ if (cell) {
+ mempool_free(cell2, prison->cell_pool);
+ bio_list_add(&cell->bios, inmate);
+ goto out;
+ }
- if (!cell) {
- cell = cell2;
- cell2 = NULL;
+ /*
+ * Use new cell.
+ */
+ cell = cell2;
- cell->prison = prison;
- memcpy(&cell->key, key, sizeof(cell->key));
- cell->count = 0;
- bio_list_init(&cell->bios);
- hlist_add_head(&cell->list, prison->cells + hash);
- }
- }
+ cell->prison = prison;
+ memcpy(&cell->key, key, sizeof(cell->key));
+ cell->holder = inmate;
+ bio_list_init(&cell->bios);
+ hlist_add_head(&cell->list, prison->cells + hash);
- r = cell->count++;
- bio_list_add(&cell->bios, inmate);
- spin_unlock_irqrestore(&prison->lock, flags);
+ r = 0;
- if (cell2)
- mempool_free(cell2, prison->cell_pool);
+out:
+ spin_unlock_irqrestore(&prison->lock, flags);
*ref = cell;
@@ -283,8 +279,8 @@ static void __cell_release(struct cell *cell, struct bio_list *inmates)
hlist_del(&cell->list);
- if (inmates)
- bio_list_merge(inmates, &cell->bios);
+ bio_list_add(inmates, cell->holder);
+ bio_list_merge(inmates, &cell->bios);
mempool_free(cell, prison->cell_pool);
}
@@ -305,22 +301,44 @@ static void cell_release(struct cell *cell, struct bio_list *bios)
* bio may be in the cell. This function releases the cell, and also does
* a sanity check.
*/
+static void __cell_release_singleton(struct cell *cell, struct bio *bio)
+{
+ hlist_del(&cell->list);
+ BUG_ON(cell->holder != bio);
+ BUG_ON(!bio_list_empty(&cell->bios));
+}
+
static void cell_release_singleton(struct cell *cell, struct bio *bio)
{
- struct bio_prison *prison = cell->prison;
- struct bio_list bios;
- struct bio *b;
unsigned long flags;
-
- bio_list_init(&bios);
+ struct bio_prison *prison = cell->prison;
spin_lock_irqsave(&prison->lock, flags);
- __cell_release(cell, &bios);
+ __cell_release_singleton(cell, bio);
spin_unlock_irqrestore(&prison->lock, flags);
+}
+
+/*
+ * Sometimes we don't want the holder, just the additional bios.
+ */
+static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+ struct bio_prison *prison = cell->prison;
+
+ hlist_del(&cell->list);
+ bio_list_merge(inmates, &cell->bios);
- b = bio_list_pop(&bios);
- BUG_ON(b != bio);
- BUG_ON(!bio_list_empty(&bios));
+ mempool_free(cell, prison->cell_pool);
+}
+
+static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+ unsigned long flags;
+ struct bio_prison *prison = cell->prison;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release_no_holder(cell, inmates);
+ spin_unlock_irqrestore(&prison->lock, flags);
}
static void cell_error(struct cell *cell)
@@ -471,6 +489,13 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
* devices.
*/
struct new_mapping;
+
+struct pool_features {
+ unsigned zero_new_blocks:1;
+ unsigned discard_enabled:1;
+ unsigned discard_passdown:1;
+};
+
struct pool {
struct list_head list;
struct dm_target *ti; /* Only set if a pool target is bound */
@@ -484,7 +509,7 @@ struct pool {
dm_block_t offset_mask;
dm_block_t low_water_blocks;
- unsigned zero_new_blocks:1;
+ struct pool_features pf;
unsigned low_water_triggered:1; /* A dm event has been sent */
unsigned no_free_space:1; /* A -ENOSPC warning has been issued */
@@ -493,17 +518,21 @@ struct pool {
struct workqueue_struct *wq;
struct work_struct worker;
+ struct delayed_work waker;
unsigned ref_count;
+ unsigned long last_commit_jiffies;
spinlock_t lock;
struct bio_list deferred_bios;
struct bio_list deferred_flush_bios;
struct list_head prepared_mappings;
+ struct list_head prepared_discards;
struct bio_list retry_on_resume_list;
- struct deferred_set ds; /* FIXME: move to thin_c */
+ struct deferred_set shared_read_ds;
+ struct deferred_set all_io_ds;
struct new_mapping *next_mapping;
mempool_t *mapping_pool;
@@ -521,7 +550,7 @@ struct pool_c {
struct dm_target_callbacks callbacks;
dm_block_t low_water_blocks;
- unsigned zero_new_blocks:1;
+ struct pool_features pf;
};
/*
@@ -529,6 +558,7 @@ struct pool_c {
*/
struct thin_c {
struct dm_dev *pool_dev;
+ struct dm_dev *origin_dev;
dm_thin_id dev_id;
struct pool *pool;
@@ -597,6 +627,13 @@ static struct pool *__pool_table_lookup_metadata_dev(struct block_device *md_dev
/*----------------------------------------------------------------*/
+struct endio_hook {
+ struct thin_c *tc;
+ struct deferred_entry *shared_read_entry;
+ struct deferred_entry *all_io_entry;
+ struct new_mapping *overwrite_mapping;
+};
+
static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
{
struct bio *bio;
@@ -607,7 +644,8 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
bio_list_init(master);
while ((bio = bio_list_pop(&bios))) {
- if (dm_get_mapinfo(bio)->ptr == tc)
+ struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+ if (h->tc == tc)
bio_endio(bio, DM_ENDIO_REQUEUE);
else
bio_list_add(master, bio);
@@ -646,14 +684,16 @@ static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block)
(bio->bi_sector & pool->offset_mask);
}
-static void remap_and_issue(struct thin_c *tc, struct bio *bio,
- dm_block_t block)
+static void remap_to_origin(struct thin_c *tc, struct bio *bio)
+{
+ bio->bi_bdev = tc->origin_dev->bdev;
+}
+
+static void issue(struct thin_c *tc, struct bio *bio)
{
struct pool *pool = tc->pool;
unsigned long flags;
- remap(tc, bio, block);
-
/*
* Batch together any FUA/FLUSH bios we find and then issue
* a single commit for them in process_deferred_bios().
@@ -666,6 +706,19 @@ static void remap_and_issue(struct thin_c *tc, struct bio *bio,
generic_make_request(bio);
}
+static void remap_to_origin_and_issue(struct thin_c *tc, struct bio *bio)
+{
+ remap_to_origin(tc, bio);
+ issue(tc, bio);
+}
+
+static void remap_and_issue(struct thin_c *tc, struct bio *bio,
+ dm_block_t block)
+{
+ remap(tc, bio, block);
+ issue(tc, bio);
+}
+
/*
* wake_worker() is used when new work is queued and when pool_resume is
* ready to continue deferred IO processing.
@@ -680,21 +733,17 @@ static void wake_worker(struct pool *pool)
/*
* Bio endio functions.
*/
-struct endio_hook {
- struct thin_c *tc;
- bio_end_io_t *saved_bi_end_io;
- struct deferred_entry *entry;
-};
-
struct new_mapping {
struct list_head list;
- int prepared;
+ unsigned quiesced:1;
+ unsigned prepared:1;
+ unsigned pass_discard:1;
struct thin_c *tc;
dm_block_t virt_block;
dm_block_t data_block;
- struct cell *cell;
+ struct cell *cell, *cell2;
int err;
/*
@@ -711,7 +760,7 @@ static void __maybe_add_mapping(struct new_mapping *m)
{
struct pool *pool = m->tc->pool;
- if (list_empty(&m->list) && m->prepared) {
+ if (m->quiesced && m->prepared) {
list_add(&m->list, &pool->prepared_mappings);
wake_worker(pool);
}
@@ -734,7 +783,8 @@ static void copy_complete(int read_err, unsigned long write_err, void *context)
static void overwrite_endio(struct bio *bio, int err)
{
unsigned long flags;
- struct new_mapping *m = dm_get_mapinfo(bio)->ptr;
+ struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+ struct new_mapping *m = h->overwrite_mapping;
struct pool *pool = m->tc->pool;
m->err = err;
@@ -745,31 +795,6 @@ static void overwrite_endio(struct bio *bio, int err)
spin_unlock_irqrestore(&pool->lock, flags);
}
-static void shared_read_endio(struct bio *bio, int err)
-{
- struct list_head mappings;
- struct new_mapping *m, *tmp;
- struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
- unsigned long flags;
- struct pool *pool = h->tc->pool;
-
- bio->bi_end_io = h->saved_bi_end_io;
- bio_endio(bio, err);
-
- INIT_LIST_HEAD(&mappings);
- ds_dec(h->entry, &mappings);
-
- spin_lock_irqsave(&pool->lock, flags);
- list_for_each_entry_safe(m, tmp, &mappings, list) {
- list_del(&m->list);
- INIT_LIST_HEAD(&m->list);
- __maybe_add_mapping(m);
- }
- spin_unlock_irqrestore(&pool->lock, flags);
-
- mempool_free(h, pool->endio_hook_pool);
-}
-
/*----------------------------------------------------------------*/
/*
@@ -800,21 +825,16 @@ static void cell_defer(struct thin_c *tc, struct cell *cell,
* Same as cell_defer above, except it omits one particular detainee,
* a write bio that covers the block and has already been processed.
*/
-static void cell_defer_except(struct thin_c *tc, struct cell *cell,
- struct bio *exception)
+static void cell_defer_except(struct thin_c *tc, struct cell *cell)
{
struct bio_list bios;
- struct bio *bio;
struct pool *pool = tc->pool;
unsigned long flags;
bio_list_init(&bios);
- cell_release(cell, &bios);
spin_lock_irqsave(&pool->lock, flags);
- while ((bio = bio_list_pop(&bios)))
- if (bio != exception)
- bio_list_add(&pool->deferred_bios, bio);
+ cell_release_no_holder(cell, &pool->deferred_bios);
spin_unlock_irqrestore(&pool->lock, flags);
wake_worker(pool);
@@ -854,7 +874,7 @@ static void process_prepared_mapping(struct new_mapping *m)
* the bios in the cell.
*/
if (bio) {
- cell_defer_except(tc, m->cell, bio);
+ cell_defer_except(tc, m->cell);
bio_endio(bio, 0);
} else
cell_defer(tc, m->cell, m->data_block);
@@ -863,7 +883,30 @@ static void process_prepared_mapping(struct new_mapping *m)
mempool_free(m, tc->pool->mapping_pool);
}
-static void process_prepared_mappings(struct pool *pool)
+static void process_prepared_discard(struct new_mapping *m)
+{
+ int r;
+ struct thin_c *tc = m->tc;
+
+ r = dm_thin_remove_block(tc->td, m->virt_block);
+ if (r)
+ DMERR("dm_thin_remove_block() failed");
+
+ /*
+ * Pass the discard down to the underlying device?
+ */
+ if (m->pass_discard)
+ remap_and_issue(tc, m->bio, m->data_block);
+ else
+ bio_endio(m->bio, 0);
+
+ cell_defer_except(tc, m->cell);
+ cell_defer_except(tc, m->cell2);
+ mempool_free(m, tc->pool->mapping_pool);
+}
+
+static void process_prepared(struct pool *pool, struct list_head *head,
+ void (*fn)(struct new_mapping *))
{
unsigned long flags;
struct list_head maps;
@@ -871,21 +914,27 @@ static void process_prepared_mappings(struct pool *pool)
INIT_LIST_HEAD(&maps);
spin_lock_irqsave(&pool->lock, flags);
- list_splice_init(&pool->prepared_mappings, &maps);
+ list_splice_init(head, &maps);
spin_unlock_irqrestore(&pool->lock, flags);
list_for_each_entry_safe(m, tmp, &maps, list)
- process_prepared_mapping(m);
+ fn(m);
}
/*
* Deferred bio jobs.
*/
-static int io_overwrites_block(struct pool *pool, struct bio *bio)
+static int io_overlaps_block(struct pool *pool, struct bio *bio)
{
- return ((bio_data_dir(bio) == WRITE) &&
- !(bio->bi_sector & pool->offset_mask)) &&
+ return !(bio->bi_sector & pool->offset_mask) &&
(bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT));
+
+}
+
+static int io_overwrites_block(struct pool *pool, struct bio *bio)
+{
+ return (bio_data_dir(bio) == WRITE) &&
+ io_overlaps_block(pool, bio);
}
static void save_and_set_endio(struct bio *bio, bio_end_io_t **save,
@@ -917,7 +966,8 @@ static struct new_mapping *get_next_mapping(struct pool *pool)
}
static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
- dm_block_t data_origin, dm_block_t data_dest,
+ struct dm_dev *origin, dm_block_t data_origin,
+ dm_block_t data_dest,
struct cell *cell, struct bio *bio)
{
int r;
@@ -925,6 +975,7 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
struct new_mapping *m = get_next_mapping(pool);
INIT_LIST_HEAD(&m->list);
+ m->quiesced = 0;
m->prepared = 0;
m->tc = tc;
m->virt_block = virt_block;
@@ -933,7 +984,8 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
m->err = 0;
m->bio = NULL;
- ds_add_work(&pool->ds, &m->list);
+ if (!ds_add_work(&pool->shared_read_ds, &m->list))
+ m->quiesced = 1;
/*
* IO to pool_dev remaps to the pool target's data_dev.
@@ -942,14 +994,15 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
* bio immediately. Otherwise we use kcopyd to clone the data first.
*/
if (io_overwrites_block(pool, bio)) {
+ struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+ h->overwrite_mapping = m;
m->bio = bio;
save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
- dm_get_mapinfo(bio)->ptr = m;
remap_and_issue(tc, bio, data_dest);
} else {
struct dm_io_region from, to;
- from.bdev = tc->pool_dev->bdev;
+ from.bdev = origin->bdev;
from.sector = data_origin * pool->sectors_per_block;
from.count = pool->sectors_per_block;
@@ -967,6 +1020,22 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
}
}
+static void schedule_internal_copy(struct thin_c *tc, dm_block_t virt_block,
+ dm_block_t data_origin, dm_block_t data_dest,
+ struct cell *cell, struct bio *bio)
+{
+ schedule_copy(tc, virt_block, tc->pool_dev,
+ data_origin, data_dest, cell, bio);
+}
+
+static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block,
+ dm_block_t data_dest,
+ struct cell *cell, struct bio *bio)
+{
+ schedule_copy(tc, virt_block, tc->origin_dev,
+ virt_block, data_dest, cell, bio);
+}
+
static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
dm_block_t data_block, struct cell *cell,
struct bio *bio)
@@ -975,6 +1044,7 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
struct new_mapping *m = get_next_mapping(pool);
INIT_LIST_HEAD(&m->list);
+ m->quiesced = 1;
m->prepared = 0;
m->tc = tc;
m->virt_block = virt_block;
@@ -988,13 +1058,14 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
* zeroing pre-existing data, we can issue the bio immediately.
* Otherwise we use kcopyd to zero the data first.
*/
- if (!pool->zero_new_blocks)
+ if (!pool->pf.zero_new_blocks)
process_prepared_mapping(m);
else if (io_overwrites_block(pool, bio)) {
+ struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+ h->overwrite_mapping = m;
m->bio = bio;
save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
- dm_get_mapinfo(bio)->ptr = m;
remap_and_issue(tc, bio, data_block);
} else {
@@ -1081,7 +1152,8 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
*/
static void retry_on_resume(struct bio *bio)
{
- struct thin_c *tc = dm_get_mapinfo(bio)->ptr;
+ struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+ struct thin_c *tc = h->tc;
struct pool *pool = tc->pool;
unsigned long flags;
@@ -1102,6 +1174,86 @@ static void no_space(struct cell *cell)
retry_on_resume(bio);
}
+static void process_discard(struct thin_c *tc, struct bio *bio)
+{
+ int r;
+ struct pool *pool = tc->pool;
+ struct cell *cell, *cell2;
+ struct cell_key key, key2;
+ dm_block_t block = get_bio_block(tc, bio);
+ struct dm_thin_lookup_result lookup_result;
+ struct new_mapping *m;
+
+ build_virtual_key(tc->td, block, &key);
+ if (bio_detain(tc->pool->prison, &key, bio, &cell))
+ return;
+
+ r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
+ switch (r) {
+ case 0:
+ /*
+ * Check nobody is fiddling with this pool block. This can
+ * happen if someone's in the process of breaking sharing
+ * on this block.
+ */
+ build_data_key(tc->td, lookup_result.block, &key2);
+ if (bio_detain(tc->pool->prison, &key2, bio, &cell2)) {
+ cell_release_singleton(cell, bio);
+ break;
+ }
+
+ if (io_overlaps_block(pool, bio)) {
+ /*
+ * IO may still be going to the destination block. We must
+ * quiesce before we can do the removal.
+ */
+ m = get_next_mapping(pool);
+ m->tc = tc;
+ m->pass_discard = (!lookup_result.shared) & pool->pf.discard_passdown;
+ m->virt_block = block;
+ m->data_block = lookup_result.block;
+ m->cell = cell;
+ m->cell2 = cell2;
+ m->err = 0;
+ m->bio = bio;
+
+ if (!ds_add_work(&pool->all_io_ds, &m->list)) {
+ list_add(&m->list, &pool->prepared_discards);
+ wake_worker(pool);
+ }
+ } else {
+ /*
+ * This path is hit if people are ignoring
+ * limits->discard_granularity. It ignores any
+ * part of the discard that is in a subsequent
+ * block.
+ */
+ sector_t offset = bio->bi_sector - (block << pool->block_shift);
+ unsigned remaining = (pool->sectors_per_block - offset) << 9;
+ bio->bi_size = min(bio->bi_size, remaining);
+
+ cell_release_singleton(cell, bio);
+ cell_release_singleton(cell2, bio);
+ remap_and_issue(tc, bio, lookup_result.block);
+ }
+ break;
+
+ case -ENODATA:
+ /*
+ * It isn't provisioned, just forget it.
+ */
+ cell_release_singleton(cell, bio);
+ bio_endio(bio, 0);
+ break;
+
+ default:
+ DMERR("discard: find block unexpectedly returned %d", r);
+ cell_release_singleton(cell, bio);
+ bio_io_error(bio);
+ break;
+ }
+}
+
static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
struct cell_key *key,
struct dm_thin_lookup_result *lookup_result,
@@ -1113,8 +1265,8 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
r = alloc_data_block(tc, &data_block);
switch (r) {
case 0:
- schedule_copy(tc, block, lookup_result->block,
- data_block, cell, bio);
+ schedule_internal_copy(tc, block, lookup_result->block,
+ data_block, cell, bio);
break;
case -ENOSPC:
@@ -1147,13 +1299,9 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio,
if (bio_data_dir(bio) == WRITE)
break_sharing(tc, bio, block, &key, lookup_result, cell);
else {
- struct endio_hook *h;
- h = mempool_alloc(pool->endio_hook_pool, GFP_NOIO);
+ struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
- h->tc = tc;
- h->entry = ds_inc(&pool->ds);
- save_and_set_endio(bio, &h->saved_bi_end_io, shared_read_endio);
- dm_get_mapinfo(bio)->ptr = h;
+ h->shared_read_entry = ds_inc(&pool->shared_read_ds);
cell_release_singleton(cell, bio);
remap_and_issue(tc, bio, lookup_result->block);
@@ -1188,7 +1336,10 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
r = alloc_data_block(tc, &data_block);
switch (r) {
case 0:
- schedule_zero(tc, block, data_block, cell, bio);
+ if (tc->origin_dev)
+ schedule_external_copy(tc, block, data_block, cell, bio);
+ else
+ schedule_zero(tc, block, data_block, cell, bio);
break;
case -ENOSPC:
@@ -1239,16 +1390,27 @@ static void process_bio(struct thin_c *tc, struct bio *bio)
break;
case -ENODATA:
- provision_block(tc, bio, block, cell);
+ if (bio_data_dir(bio) == READ && tc->origin_dev) {
+ cell_release_singleton(cell, bio);
+ remap_to_origin_and_issue(tc, bio);
+ } else
+ provision_block(tc, bio, block, cell);
break;
default:
DMERR("dm_thin_find_block() failed, error = %d", r);
+ cell_release_singleton(cell, bio);
bio_io_error(bio);
break;
}
}
+static int need_commit_due_to_time(struct pool *pool)
+{
+ return jiffies < pool->last_commit_jiffies ||
+ jiffies > pool->last_commit_jiffies + COMMIT_PERIOD;
+}
+
static void process_deferred_bios(struct pool *pool)
{
unsigned long flags;
@@ -1264,7 +1426,9 @@ static void process_deferred_bios(struct pool *pool)
spin_unlock_irqrestore(&pool->lock, flags);
while ((bio = bio_list_pop(&bios))) {
- struct thin_c *tc = dm_get_mapinfo(bio)->ptr;
+ struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+ struct thin_c *tc = h->tc;
+
/*
* If we've got no free new_mapping structs, and processing
* this bio might require one, we pause until there are some
@@ -1277,7 +1441,11 @@ static void process_deferred_bios(struct pool *pool)
break;
}
- process_bio(tc, bio);
+
+ if (bio->bi_rw & REQ_DISCARD)
+ process_discard(tc, bio);
+ else
+ process_bio(tc, bio);
}
/*
@@ -1290,7 +1458,7 @@ static void process_deferred_bios(struct pool *pool)
bio_list_init(&pool->deferred_flush_bios);
spin_unlock_irqrestore(&pool->lock, flags);
- if (bio_list_empty(&bios))
+ if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
return;
r = dm_pool_commit_metadata(pool->pmd);
@@ -1301,6 +1469,7 @@ static void process_deferred_bios(struct pool *pool)
bio_io_error(bio);
return;
}
+ pool->last_commit_jiffies = jiffies;
while ((bio = bio_list_pop(&bios)))
generic_make_request(bio);
@@ -1310,10 +1479,22 @@ static void do_worker(struct work_struct *ws)
{
struct pool *pool = container_of(ws, struct pool, worker);
- process_prepared_mappings(pool);
+ process_prepared(pool, &pool->prepared_mappings, process_prepared_mapping);
+ process_prepared(pool, &pool->prepared_discards, process_prepared_discard);
process_deferred_bios(pool);
}
+/*
+ * We want to commit periodically so that not too much
+ * unwritten data builds up.
+ */
+static void do_waker(struct work_struct *ws)
+{
+ struct pool *pool = container_of(to_delayed_work(ws), struct pool, waker);
+ wake_worker(pool);
+ queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD);
+}
+
/*----------------------------------------------------------------*/
/*
@@ -1335,6 +1516,19 @@ static void thin_defer_bio(struct thin_c *tc, struct bio *bio)
wake_worker(pool);
}
+static struct endio_hook *thin_hook_bio(struct thin_c *tc, struct bio *bio)
+{
+ struct pool *pool = tc->pool;
+ struct endio_hook *h = mempool_alloc(pool->endio_hook_pool, GFP_NOIO);
+
+ h->tc = tc;
+ h->shared_read_entry = NULL;
+ h->all_io_entry = bio->bi_rw & REQ_DISCARD ? NULL : ds_inc(&pool->all_io_ds);
+ h->overwrite_mapping = NULL;
+
+ return h;
+}
+
/*
* Non-blocking function called from the thin target's map function.
*/
@@ -1347,12 +1541,8 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
struct dm_thin_device *td = tc->td;
struct dm_thin_lookup_result result;
- /*
- * Save the thin context for easy access from the deferred bio later.
- */
- map_context->ptr = tc;
-
- if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
+ map_context->ptr = thin_hook_bio(tc, bio);
+ if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) {
thin_defer_bio(tc, bio);
return DM_MAPIO_SUBMITTED;
}
@@ -1434,7 +1624,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
pool->ti = ti;
pool->low_water_blocks = pt->low_water_blocks;
- pool->zero_new_blocks = pt->zero_new_blocks;
+ pool->pf = pt->pf;
return 0;
}
@@ -1448,6 +1638,14 @@ static void unbind_control_target(struct pool *pool, struct dm_target *ti)
/*----------------------------------------------------------------
* Pool creation
*--------------------------------------------------------------*/
+/* Initialize pool features. */
+static void pool_features_init(struct pool_features *pf)
+{
+ pf->zero_new_blocks = 1;
+ pf->discard_enabled = 1;
+ pf->discard_passdown = 1;
+}
+
static void __pool_destroy(struct pool *pool)
{
__pool_table_remove(pool);
@@ -1495,7 +1693,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
pool->block_shift = ffs(block_size) - 1;
pool->offset_mask = block_size - 1;
pool->low_water_blocks = 0;
- pool->zero_new_blocks = 1;
+ pool_features_init(&pool->pf);
pool->prison = prison_create(PRISON_CELLS);
if (!pool->prison) {
*error = "Error creating pool's bio prison";
@@ -1523,14 +1721,17 @@ static struct pool *pool_create(struct mapped_device *pool_md,
}
INIT_WORK(&pool->worker, do_worker);
+ INIT_DELAYED_WORK(&pool->waker, do_waker);
spin_lock_init(&pool->lock);
bio_list_init(&pool->deferred_bios);
bio_list_init(&pool->deferred_flush_bios);
INIT_LIST_HEAD(&pool->prepared_mappings);
+ INIT_LIST_HEAD(&pool->prepared_discards);
pool->low_water_triggered = 0;
pool->no_free_space = 0;
bio_list_init(&pool->retry_on_resume_list);
- ds_init(&pool->ds);
+ ds_init(&pool->shared_read_ds);
+ ds_init(&pool->all_io_ds);
pool->next_mapping = NULL;
pool->mapping_pool =
@@ -1549,6 +1750,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
goto bad_endio_hook_pool;
}
pool->ref_count = 1;
+ pool->last_commit_jiffies = jiffies;
pool->pool_md = pool_md;
pool->md_dev = metadata_dev;
__pool_table_insert(pool);
@@ -1588,7 +1790,8 @@ static void __pool_dec(struct pool *pool)
static struct pool *__pool_find(struct mapped_device *pool_md,
struct block_device *metadata_dev,
- unsigned long block_size, char **error)
+ unsigned long block_size, char **error,
+ int *created)
{
struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev);
@@ -1604,8 +1807,10 @@ static struct pool *__pool_find(struct mapped_device *pool_md,
return ERR_PTR(-EINVAL);
__pool_inc(pool);
- } else
+ } else {
pool = pool_create(pool_md, metadata_dev, block_size, error);
+ *created = 1;
+ }
}
return pool;
@@ -1629,10 +1834,6 @@ static void pool_dtr(struct dm_target *ti)
mutex_unlock(&dm_thin_pool_table.mutex);
}
-struct pool_features {
- unsigned zero_new_blocks:1;
-};
-
static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
struct dm_target *ti)
{
@@ -1641,7 +1842,7 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
const char *arg_name;
static struct dm_arg _args[] = {
- {0, 1, "Invalid number of pool feature arguments"},
+ {0, 3, "Invalid number of pool feature arguments"},
};
/*
@@ -1661,6 +1862,12 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
if (!strcasecmp(arg_name, "skip_block_zeroing")) {
pf->zero_new_blocks = 0;
continue;
+ } else if (!strcasecmp(arg_name, "ignore_discard")) {
+ pf->discard_enabled = 0;
+ continue;
+ } else if (!strcasecmp(arg_name, "no_discard_passdown")) {
+ pf->discard_passdown = 0;
+ continue;
}
ti->error = "Unrecognised pool feature requested";
@@ -1678,10 +1885,12 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
*
* Optional feature arguments are:
* skip_block_zeroing: skips the zeroing of newly-provisioned blocks.
+ * ignore_discard: disable discard
+ * no_discard_passdown: don't pass discards down to the data device
*/
static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
- int r;
+ int r, pool_created = 0;
struct pool_c *pt;
struct pool *pool;
struct pool_features pf;
@@ -1691,6 +1900,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
dm_block_t low_water_blocks;
struct dm_dev *metadata_dev;
sector_t metadata_dev_size;
+ char b[BDEVNAME_SIZE];
/*
* FIXME Remove validation from scope of lock.
@@ -1712,11 +1922,9 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
}
metadata_dev_size = i_size_read(metadata_dev->bdev->bd_inode) >> SECTOR_SHIFT;
- if (metadata_dev_size > METADATA_DEV_MAX_SECTORS) {
- ti->error = "Metadata device is too large";
- r = -EINVAL;
- goto out_metadata;
- }
+ if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)
+ DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
+ bdevname(metadata_dev->bdev, b), THIN_METADATA_MAX_SECTORS);
r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
if (r) {
@@ -1742,8 +1950,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
/*
* Set default pool features.
*/
- memset(&pf, 0, sizeof(pf));
- pf.zero_new_blocks = 1;
+ pool_features_init(&pf);
dm_consume_args(&as, 4);
r = parse_pool_features(&as, &pf, ti);
@@ -1757,20 +1964,58 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
}
pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev,
- block_size, &ti->error);
+ block_size, &ti->error, &pool_created);
if (IS_ERR(pool)) {
r = PTR_ERR(pool);
goto out_free_pt;
}
+ /*
+ * 'pool_created' reflects whether this is the first table load.
+ * Top level discard support is not allowed to be changed after
+ * initial load. This would require a pool reload to trigger thin
+ * device changes.
+ */
+ if (!pool_created && pf.discard_enabled != pool->pf.discard_enabled) {
+ ti->error = "Discard support cannot be disabled once enabled";
+ r = -EINVAL;
+ goto out_flags_changed;
+ }
+
+ /*
+ * If discard_passdown was enabled verify that the data device
+ * supports discards. Disable discard_passdown if not; otherwise
+ * -EOPNOTSUPP will be returned.
+ */
+ if (pf.discard_passdown) {
+ struct request_queue *q = bdev_get_queue(data_dev->bdev);
+ if (!q || !blk_queue_discard(q)) {
+ DMWARN("Discard unsupported by data device: Disabling discard passdown.");
+ pf.discard_passdown = 0;
+ }
+ }
+
pt->pool = pool;
pt->ti = ti;
pt->metadata_dev = metadata_dev;
pt->data_dev = data_dev;
pt->low_water_blocks = low_water_blocks;
- pt->zero_new_blocks = pf.zero_new_blocks;
+ pt->pf = pf;
ti->num_flush_requests = 1;
- ti->num_discard_requests = 0;
+ /*
+ * Only need to enable discards if the pool should pass
+ * them down to the data device. The thin device's discard
+ * processing will cause mappings to be removed from the btree.
+ */
+ if (pf.discard_enabled && pf.discard_passdown) {
+ ti->num_discard_requests = 1;
+ /*
+ * Setting 'discards_supported' circumvents the normal
+ * stacking of discard limits (this keeps the pool and
+ * thin devices' discard limits consistent).
+ */
+ ti->discards_supported = 1;
+ }
ti->private = pt;
pt->callbacks.congested_fn = pool_is_congested;
@@ -1780,6 +2025,8 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
return 0;
+out_flags_changed:
+ __pool_dec(pool);
out_free_pt:
kfree(pt);
out:
@@ -1878,7 +2125,7 @@ static void pool_resume(struct dm_target *ti)
__requeue_bios(pool);
spin_unlock_irqrestore(&pool->lock, flags);
- wake_worker(pool);
+ do_waker(&pool->waker.work);
}
static void pool_postsuspend(struct dm_target *ti)
@@ -1887,6 +2134,7 @@ static void pool_postsuspend(struct dm_target *ti)
struct pool_c *pt = ti->private;
struct pool *pool = pt->pool;
+ cancel_delayed_work(&pool->waker);
flush_workqueue(pool->wq);
r = dm_pool_commit_metadata(pool->pmd);
@@ -2067,7 +2315,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
static int pool_status(struct dm_target *ti, status_type_t type,
char *result, unsigned maxlen)
{
- int r;
+ int r, count;
unsigned sz = 0;
uint64_t transaction_id;
dm_block_t nr_free_blocks_data;
@@ -2130,10 +2378,19 @@ static int pool_status(struct dm_target *ti, status_type_t type,
(unsigned long)pool->sectors_per_block,
(unsigned long long)pt->low_water_blocks);
- DMEMIT("%u ", !pool->zero_new_blocks);
+ count = !pool->pf.zero_new_blocks + !pool->pf.discard_enabled +
+ !pool->pf.discard_passdown;
+ DMEMIT("%u ", count);
- if (!pool->zero_new_blocks)
+ if (!pool->pf.zero_new_blocks)
DMEMIT("skip_block_zeroing ");
+
+ if (!pool->pf.discard_enabled)
+ DMEMIT("ignore_discard ");
+
+ if (!pool->pf.discard_passdown)
+ DMEMIT("no_discard_passdown ");
+
break;
}
@@ -2162,6 +2419,21 @@ static int pool_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
}
+static void set_discard_limits(struct pool *pool, struct queue_limits *limits)
+{
+ /*
+ * FIXME: these limits may be incompatible with the pool's data device
+ */
+ limits->max_discard_sectors = pool->sectors_per_block;
+
+ /*
+ * This is just a hint, and not enforced. We have to cope with
+ * bios that overlap 2 blocks.
+ */
+ limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
+ limits->discard_zeroes_data = pool->pf.zero_new_blocks;
+}
+
static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
{
struct pool_c *pt = ti->private;
@@ -2169,13 +2441,15 @@ static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
blk_limits_io_min(limits, 0);
blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+ if (pool->pf.discard_enabled)
+ set_discard_limits(pool, limits);
}
static struct target_type pool_target = {
.name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE,
- .version = {1, 0, 0},
+ .version = {1, 1, 0},
.module = THIS_MODULE,
.ctr = pool_ctr,
.dtr = pool_dtr,
@@ -2202,6 +2476,8 @@ static void thin_dtr(struct dm_target *ti)
__pool_dec(tc->pool);
dm_pool_close_thin_device(tc->td);
dm_put_device(ti, tc->pool_dev);
+ if (tc->origin_dev)
+ dm_put_device(ti, tc->origin_dev);
kfree(tc);
mutex_unlock(&dm_thin_pool_table.mutex);
@@ -2210,21 +2486,25 @@ static void thin_dtr(struct dm_target *ti)
/*
* Thin target parameters:
*
- * <pool_dev> <dev_id>
+ * <pool_dev> <dev_id> [origin_dev]
*
* pool_dev: the path to the pool (eg, /dev/mapper/my_pool)
* dev_id: the internal device identifier
+ * origin_dev: a device external to the pool that should act as the origin
+ *
+ * If the pool device has discards disabled, they get disabled for the thin
+ * device as well.
*/
static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
int r;
struct thin_c *tc;
- struct dm_dev *pool_dev;
+ struct dm_dev *pool_dev, *origin_dev;
struct mapped_device *pool_md;
mutex_lock(&dm_thin_pool_table.mutex);
- if (argc != 2) {
+ if (argc != 2 && argc != 3) {
ti->error = "Invalid argument count";
r = -EINVAL;
goto out_unlock;
@@ -2237,6 +2517,15 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto out_unlock;
}
+ if (argc == 3) {
+ r = dm_get_device(ti, argv[2], FMODE_READ, &origin_dev);
+ if (r) {
+ ti->error = "Error opening origin device";
+ goto bad_origin_dev;
+ }
+ tc->origin_dev = origin_dev;
+ }
+
r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &pool_dev);
if (r) {
ti->error = "Error opening pool device";
@@ -2273,8 +2562,12 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->split_io = tc->pool->sectors_per_block;
ti->num_flush_requests = 1;
- ti->num_discard_requests = 0;
- ti->discards_supported = 0;
+
+ /* In case the pool supports discards, pass them on. */
+ if (tc->pool->pf.discard_enabled) {
+ ti->discards_supported = 1;
+ ti->num_discard_requests = 1;
+ }
dm_put(pool_md);
@@ -2289,6 +2582,9 @@ bad_pool_lookup:
bad_common:
dm_put_device(ti, tc->pool_dev);
bad_pool_dev:
+ if (tc->origin_dev)
+ dm_put_device(ti, tc->origin_dev);
+bad_origin_dev:
kfree(tc);
out_unlock:
mutex_unlock(&dm_thin_pool_table.mutex);
@@ -2299,11 +2595,46 @@ out_unlock:
static int thin_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
- bio->bi_sector -= ti->begin;
+ bio->bi_sector = dm_target_offset(ti, bio->bi_sector);
return thin_bio_map(ti, bio, map_context);
}
+static int thin_endio(struct dm_target *ti,
+ struct bio *bio, int err,
+ union map_info *map_context)
+{
+ unsigned long flags;
+ struct endio_hook *h = map_context->ptr;
+ struct list_head work;
+ struct new_mapping *m, *tmp;
+ struct pool *pool = h->tc->pool;
+
+ if (h->shared_read_entry) {
+ INIT_LIST_HEAD(&work);
+ ds_dec(h->shared_read_entry, &work);
+
+ spin_lock_irqsave(&pool->lock, flags);
+ list_for_each_entry_safe(m, tmp, &work, list) {
+ list_del(&m->list);
+ m->quiesced = 1;
+ __maybe_add_mapping(m);
+ }
+ spin_unlock_irqrestore(&pool->lock, flags);
+ }
+
+ if (h->all_io_entry) {
+ INIT_LIST_HEAD(&work);
+ ds_dec(h->all_io_entry, &work);
+ list_for_each_entry_safe(m, tmp, &work, list)
+ list_add(&m->list, &pool->prepared_discards);
+ }
+
+ mempool_free(h, pool->endio_hook_pool);
+
+ return 0;
+}
+
static void thin_postsuspend(struct dm_target *ti)
{
if (dm_noflush_suspending(ti))
@@ -2347,6 +2678,8 @@ static int thin_status(struct dm_target *ti, status_type_t type,
DMEMIT("%s %lu",
format_dev_t(buf, tc->pool_dev->bdev->bd_dev),
(unsigned long) tc->dev_id);
+ if (tc->origin_dev)
+ DMEMIT(" %s", format_dev_t(buf, tc->origin_dev->bdev->bd_dev));
break;
}
}
@@ -2377,18 +2710,21 @@ static int thin_iterate_devices(struct dm_target *ti,
static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
{
struct thin_c *tc = ti->private;
+ struct pool *pool = tc->pool;
blk_limits_io_min(limits, 0);
- blk_limits_io_opt(limits, tc->pool->sectors_per_block << SECTOR_SHIFT);
+ blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+ set_discard_limits(pool, limits);
}
static struct target_type thin_target = {
.name = "thin",
- .version = {1, 0, 0},
+ .version = {1, 1, 0},
.module = THIS_MODULE,
.ctr = thin_ctr,
.dtr = thin_dtr,
.map = thin_map,
+ .end_io = thin_endio,
.postsuspend = thin_postsuspend,
.status = thin_status,
.iterate_devices = thin_iterate_devices,
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
new file mode 100644
index 000000000000..fa365d39b612
--- /dev/null
+++ b/drivers/md/dm-verity.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ *
+ * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
+ * default prefetch value. Data are read in "prefetch_cluster" chunks from the
+ * hash device. Setting this greatly improves performance when data and hash
+ * are on the same disk on different partitions on devices with poor random
+ * access behavior.
+ */
+
+#include "dm-bufio.h"
+
+#include <linux/module.h>
+#include <linux/device-mapper.h>
+#include <crypto/hash.h>
+
+#define DM_MSG_PREFIX "verity"
+
+#define DM_VERITY_IO_VEC_INLINE 16
+#define DM_VERITY_MEMPOOL_SIZE 4
+#define DM_VERITY_DEFAULT_PREFETCH_SIZE 262144
+
+#define DM_VERITY_MAX_LEVELS 63
+
+static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
+
+module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
+
+struct dm_verity {
+ struct dm_dev *data_dev;
+ struct dm_dev *hash_dev;
+ struct dm_target *ti;
+ struct dm_bufio_client *bufio;
+ char *alg_name;
+ struct crypto_shash *tfm;
+ u8 *root_digest; /* digest of the root block */
+ u8 *salt; /* salt: its size is salt_size */
+ unsigned salt_size;
+ sector_t data_start; /* data offset in 512-byte sectors */
+ sector_t hash_start; /* hash start in blocks */
+ sector_t data_blocks; /* the number of data blocks */
+ sector_t hash_blocks; /* the number of hash blocks */
+ unsigned char data_dev_block_bits; /* log2(data blocksize) */
+ unsigned char hash_dev_block_bits; /* log2(hash blocksize) */
+ unsigned char hash_per_block_bits; /* log2(hashes in hash block) */
+ unsigned char levels; /* the number of tree levels */
+ unsigned char version;
+ unsigned digest_size; /* digest size for the current hash algorithm */
+ unsigned shash_descsize;/* the size of temporary space for crypto */
+ int hash_failed; /* set to 1 if hash of any block failed */
+
+ mempool_t *io_mempool; /* mempool of struct dm_verity_io */
+ mempool_t *vec_mempool; /* mempool of bio vector */
+
+ struct workqueue_struct *verify_wq;
+
+ /* starting blocks for each tree level. 0 is the lowest level. */
+ sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
+};
+
+struct dm_verity_io {
+ struct dm_verity *v;
+ struct bio *bio;
+
+ /* original values of bio->bi_end_io and bio->bi_private */
+ bio_end_io_t *orig_bi_end_io;
+ void *orig_bi_private;
+
+ sector_t block;
+ unsigned n_blocks;
+
+ /* saved bio vector */
+ struct bio_vec *io_vec;
+ unsigned io_vec_size;
+
+ struct work_struct work;
+
+ /* A space for short vectors; longer vectors are allocated separately. */
+ struct bio_vec io_vec_inline[DM_VERITY_IO_VEC_INLINE];
+
+ /*
+ * Three variably-size fields follow this struct:
+ *
+ * u8 hash_desc[v->shash_descsize];
+ * u8 real_digest[v->digest_size];
+ * u8 want_digest[v->digest_size];
+ *
+ * To access them use: io_hash_desc(), io_real_digest() and io_want_digest().
+ */
+};
+
+static struct shash_desc *io_hash_desc(struct dm_verity *v, struct dm_verity_io *io)
+{
+ return (struct shash_desc *)(io + 1);
+}
+
+static u8 *io_real_digest(struct dm_verity *v, struct dm_verity_io *io)
+{
+ return (u8 *)(io + 1) + v->shash_descsize;
+}
+
+static u8 *io_want_digest(struct dm_verity *v, struct dm_verity_io *io)
+{
+ return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
+}
+
+/*
+ * Auxiliary structure appended to each dm-bufio buffer. If the value
+ * hash_verified is nonzero, hash of the block has been verified.
+ *
+ * The variable hash_verified is set to 0 when allocating the buffer, then
+ * it can be changed to 1 and it is never reset to 0 again.
+ *
+ * There is no lock around this value, a race condition can at worst cause
+ * that multiple processes verify the hash of the same buffer simultaneously
+ * and write 1 to hash_verified simultaneously.
+ * This condition is harmless, so we don't need locking.
+ */
+struct buffer_aux {
+ int hash_verified;
+};
+
+/*
+ * Initialize struct buffer_aux for a freshly created buffer.
+ */
+static void dm_bufio_alloc_callback(struct dm_buffer *buf)
+{
+ struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
+
+ aux->hash_verified = 0;
+}
+
+/*
+ * Translate input sector number to the sector number on the target device.
+ */
+static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
+{
+ return v->data_start + dm_target_offset(v->ti, bi_sector);
+}
+
+/*
+ * Return hash position of a specified block at a specified tree level
+ * (0 is the lowest level).
+ * The lowest "hash_per_block_bits"-bits of the result denote hash position
+ * inside a hash block. The remaining bits denote location of the hash block.
+ */
+static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
+ int level)
+{
+ return block >> (level * v->hash_per_block_bits);
+}
+
+static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
+ sector_t *hash_block, unsigned *offset)
+{
+ sector_t position = verity_position_at_level(v, block, level);
+ unsigned idx;
+
+ *hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
+
+ if (!offset)
+ return;
+
+ idx = position & ((1 << v->hash_per_block_bits) - 1);
+ if (!v->version)
+ *offset = idx * v->digest_size;
+ else
+ *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
+}
+
+/*
+ * Verify hash of a metadata block pertaining to the specified data block
+ * ("block" argument) at a specified level ("level" argument).
+ *
+ * On successful return, io_want_digest(v, io) contains the hash value for
+ * a lower tree level or for the data block (if we're at the lowest leve).
+ *
+ * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
+ * If "skip_unverified" is false, unverified buffer is hashed and verified
+ * against current value of io_want_digest(v, io).
+ */
+static int verity_verify_level(struct dm_verity_io *io, sector_t block,
+ int level, bool skip_unverified)
+{
+ struct dm_verity *v = io->v;
+ struct dm_buffer *buf;
+ struct buffer_aux *aux;
+ u8 *data;
+ int r;
+ sector_t hash_block;
+ unsigned offset;
+
+ verity_hash_at_level(v, block, level, &hash_block, &offset);
+
+ data = dm_bufio_read(v->bufio, hash_block, &buf);
+ if (unlikely(IS_ERR(data)))
+ return PTR_ERR(data);
+
+ aux = dm_bufio_get_aux_data(buf);
+
+ if (!aux->hash_verified) {
+ struct shash_desc *desc;
+ u8 *result;
+
+ if (skip_unverified) {
+ r = 1;
+ goto release_ret_r;
+ }
+
+ desc = io_hash_desc(v, io);
+ desc->tfm = v->tfm;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ r = crypto_shash_init(desc);
+ if (r < 0) {
+ DMERR("crypto_shash_init failed: %d", r);
+ goto release_ret_r;
+ }
+
+ if (likely(v->version >= 1)) {
+ r = crypto_shash_update(desc, v->salt, v->salt_size);
+ if (r < 0) {
+ DMERR("crypto_shash_update failed: %d", r);
+ goto release_ret_r;
+ }
+ }
+
+ r = crypto_shash_update(desc, data, 1 << v->hash_dev_block_bits);
+ if (r < 0) {
+ DMERR("crypto_shash_update failed: %d", r);
+ goto release_ret_r;
+ }
+
+ if (!v->version) {
+ r = crypto_shash_update(desc, v->salt, v->salt_size);
+ if (r < 0) {
+ DMERR("crypto_shash_update failed: %d", r);
+ goto release_ret_r;
+ }
+ }
+
+ result = io_real_digest(v, io);
+ r = crypto_shash_final(desc, result);
+ if (r < 0) {
+ DMERR("crypto_shash_final failed: %d", r);
+ goto release_ret_r;
+ }
+ if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
+ DMERR_LIMIT("metadata block %llu is corrupted",
+ (unsigned long long)hash_block);
+ v->hash_failed = 1;
+ r = -EIO;
+ goto release_ret_r;
+ } else
+ aux->hash_verified = 1;
+ }
+
+ data += offset;
+
+ memcpy(io_want_digest(v, io), data, v->digest_size);
+
+ dm_bufio_release(buf);
+ return 0;
+
+release_ret_r:
+ dm_bufio_release(buf);
+
+ return r;
+}
+
+/*
+ * Verify one "dm_verity_io" structure.
+ */
+static int verity_verify_io(struct dm_verity_io *io)
+{
+ struct dm_verity *v = io->v;
+ unsigned b;
+ int i;
+ unsigned vector = 0, offset = 0;
+
+ for (b = 0; b < io->n_blocks; b++) {
+ struct shash_desc *desc;
+ u8 *result;
+ int r;
+ unsigned todo;
+
+ if (likely(v->levels)) {
+ /*
+ * First, we try to get the requested hash for
+ * the current block. If the hash block itself is
+ * verified, zero is returned. If it isn't, this
+ * function returns 0 and we fall back to whole
+ * chain verification.
+ */
+ int r = verity_verify_level(io, io->block + b, 0, true);
+ if (likely(!r))
+ goto test_block_hash;
+ if (r < 0)
+ return r;
+ }
+
+ memcpy(io_want_digest(v, io), v->root_digest, v->digest_size);
+
+ for (i = v->levels - 1; i >= 0; i--) {
+ int r = verity_verify_level(io, io->block + b, i, false);
+ if (unlikely(r))
+ return r;
+ }
+
+test_block_hash:
+ desc = io_hash_desc(v, io);
+ desc->tfm = v->tfm;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ r = crypto_shash_init(desc);
+ if (r < 0) {
+ DMERR("crypto_shash_init failed: %d", r);
+ return r;
+ }
+
+ if (likely(v->version >= 1)) {
+ r = crypto_shash_update(desc, v->salt, v->salt_size);
+ if (r < 0) {
+ DMERR("crypto_shash_update failed: %d", r);
+ return r;
+ }
+ }
+
+ todo = 1 << v->data_dev_block_bits;
+ do {
+ struct bio_vec *bv;
+ u8 *page;
+ unsigned len;
+
+ BUG_ON(vector >= io->io_vec_size);
+ bv = &io->io_vec[vector];
+ page = kmap_atomic(bv->bv_page);
+ len = bv->bv_len - offset;
+ if (likely(len >= todo))
+ len = todo;
+ r = crypto_shash_update(desc,
+ page + bv->bv_offset + offset, len);
+ kunmap_atomic(page);
+ if (r < 0) {
+ DMERR("crypto_shash_update failed: %d", r);
+ return r;
+ }
+ offset += len;
+ if (likely(offset == bv->bv_len)) {
+ offset = 0;
+ vector++;
+ }
+ todo -= len;
+ } while (todo);
+
+ if (!v->version) {
+ r = crypto_shash_update(desc, v->salt, v->salt_size);
+ if (r < 0) {
+ DMERR("crypto_shash_update failed: %d", r);
+ return r;
+ }
+ }
+
+ result = io_real_digest(v, io);
+ r = crypto_shash_final(desc, result);
+ if (r < 0) {
+ DMERR("crypto_shash_final failed: %d", r);
+ return r;
+ }
+ if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
+ DMERR_LIMIT("data block %llu is corrupted",
+ (unsigned long long)(io->block + b));
+ v->hash_failed = 1;
+ return -EIO;
+ }
+ }
+ BUG_ON(vector != io->io_vec_size);
+ BUG_ON(offset);
+
+ return 0;
+}
+
+/*
+ * End one "io" structure with a given error.
+ */
+static void verity_finish_io(struct dm_verity_io *io, int error)
+{
+ struct bio *bio = io->bio;
+ struct dm_verity *v = io->v;
+
+ bio->bi_end_io = io->orig_bi_end_io;
+ bio->bi_private = io->orig_bi_private;
+
+ if (io->io_vec != io->io_vec_inline)
+ mempool_free(io->io_vec, v->vec_mempool);
+
+ mempool_free(io, v->io_mempool);
+
+ bio_endio(bio, error);
+}
+
+static void verity_work(struct work_struct *w)
+{
+ struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
+
+ verity_finish_io(io, verity_verify_io(io));
+}
+
+static void verity_end_io(struct bio *bio, int error)
+{
+ struct dm_verity_io *io = bio->bi_private;
+
+ if (error) {
+ verity_finish_io(io, error);
+ return;
+ }
+
+ INIT_WORK(&io->work, verity_work);
+ queue_work(io->v->verify_wq, &io->work);
+}
+
+/*
+ * Prefetch buffers for the specified io.
+ * The root buffer is not prefetched, it is assumed that it will be cached
+ * all the time.
+ */
+static void verity_prefetch_io(struct dm_verity *v, struct dm_verity_io *io)
+{
+ int i;
+
+ for (i = v->levels - 2; i >= 0; i--) {
+ sector_t hash_block_start;
+ sector_t hash_block_end;
+ verity_hash_at_level(v, io->block, i, &hash_block_start, NULL);
+ verity_hash_at_level(v, io->block + io->n_blocks - 1, i, &hash_block_end, NULL);
+ if (!i) {
+ unsigned cluster = *(volatile unsigned *)&dm_verity_prefetch_cluster;
+
+ cluster >>= v->data_dev_block_bits;
+ if (unlikely(!cluster))
+ goto no_prefetch_cluster;
+
+ if (unlikely(cluster & (cluster - 1)))
+ cluster = 1 << (fls(cluster) - 1);
+
+ hash_block_start &= ~(sector_t)(cluster - 1);
+ hash_block_end |= cluster - 1;
+ if (unlikely(hash_block_end >= v->hash_blocks))
+ hash_block_end = v->hash_blocks - 1;
+ }
+no_prefetch_cluster:
+ dm_bufio_prefetch(v->bufio, hash_block_start,
+ hash_block_end - hash_block_start + 1);
+ }
+}
+
+/*
+ * Bio map function. It allocates dm_verity_io structure and bio vector and
+ * fills them. Then it issues prefetches and the I/O.
+ */
+static int verity_map(struct dm_target *ti, struct bio *bio,
+ union map_info *map_context)
+{
+ struct dm_verity *v = ti->private;
+ struct dm_verity_io *io;
+
+ bio->bi_bdev = v->data_dev->bdev;
+ bio->bi_sector = verity_map_sector(v, bio->bi_sector);
+
+ if (((unsigned)bio->bi_sector | bio_sectors(bio)) &
+ ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
+ DMERR_LIMIT("unaligned io");
+ return -EIO;
+ }
+
+ if ((bio->bi_sector + bio_sectors(bio)) >>
+ (v->data_dev_block_bits - SECTOR_SHIFT) > v->data_blocks) {
+ DMERR_LIMIT("io out of range");
+ return -EIO;
+ }
+
+ if (bio_data_dir(bio) == WRITE)
+ return -EIO;
+
+ io = mempool_alloc(v->io_mempool, GFP_NOIO);
+ io->v = v;
+ io->bio = bio;
+ io->orig_bi_end_io = bio->bi_end_io;
+ io->orig_bi_private = bio->bi_private;
+ io->block = bio->bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
+ io->n_blocks = bio->bi_size >> v->data_dev_block_bits;
+
+ bio->bi_end_io = verity_end_io;
+ bio->bi_private = io;
+ io->io_vec_size = bio->bi_vcnt - bio->bi_idx;
+ if (io->io_vec_size < DM_VERITY_IO_VEC_INLINE)
+ io->io_vec = io->io_vec_inline;
+ else
+ io->io_vec = mempool_alloc(v->vec_mempool, GFP_NOIO);
+ memcpy(io->io_vec, bio_iovec(bio),
+ io->io_vec_size * sizeof(struct bio_vec));
+
+ verity_prefetch_io(v, io);
+
+ generic_make_request(bio);
+
+ return DM_MAPIO_SUBMITTED;
+}
+
+/*
+ * Status: V (valid) or C (corruption found)
+ */
+static int verity_status(struct dm_target *ti, status_type_t type,
+ char *result, unsigned maxlen)
+{
+ struct dm_verity *v = ti->private;
+ unsigned sz = 0;
+ unsigned x;
+
+ switch (type) {
+ case STATUSTYPE_INFO:
+ DMEMIT("%c", v->hash_failed ? 'C' : 'V');
+ break;
+ case STATUSTYPE_TABLE:
+ DMEMIT("%u %s %s %u %u %llu %llu %s ",
+ v->version,
+ v->data_dev->name,
+ v->hash_dev->name,
+ 1 << v->data_dev_block_bits,
+ 1 << v->hash_dev_block_bits,
+ (unsigned long long)v->data_blocks,
+ (unsigned long long)v->hash_start,
+ v->alg_name
+ );
+ for (x = 0; x < v->digest_size; x++)
+ DMEMIT("%02x", v->root_digest[x]);
+ DMEMIT(" ");
+ if (!v->salt_size)
+ DMEMIT("-");
+ else
+ for (x = 0; x < v->salt_size; x++)
+ DMEMIT("%02x", v->salt[x]);
+ break;
+ }
+
+ return 0;
+}
+
+static int verity_ioctl(struct dm_target *ti, unsigned cmd,
+ unsigned long arg)
+{
+ struct dm_verity *v = ti->private;
+ int r = 0;
+
+ if (v->data_start ||
+ ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
+ r = scsi_verify_blk_ioctl(NULL, cmd);
+
+ return r ? : __blkdev_driver_ioctl(v->data_dev->bdev, v->data_dev->mode,
+ cmd, arg);
+}
+
+static int verity_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+ struct bio_vec *biovec, int max_size)
+{
+ struct dm_verity *v = ti->private;
+ struct request_queue *q = bdev_get_queue(v->data_dev->bdev);
+
+ if (!q->merge_bvec_fn)
+ return max_size;
+
+ bvm->bi_bdev = v->data_dev->bdev;
+ bvm->bi_sector = verity_map_sector(v, bvm->bi_sector);
+
+ return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
+}
+
+static int verity_iterate_devices(struct dm_target *ti,
+ iterate_devices_callout_fn fn, void *data)
+{
+ struct dm_verity *v = ti->private;
+
+ return fn(ti, v->data_dev, v->data_start, ti->len, data);
+}
+
+static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+ struct dm_verity *v = ti->private;
+
+ if (limits->logical_block_size < 1 << v->data_dev_block_bits)
+ limits->logical_block_size = 1 << v->data_dev_block_bits;
+
+ if (limits->physical_block_size < 1 << v->data_dev_block_bits)
+ limits->physical_block_size = 1 << v->data_dev_block_bits;
+
+ blk_limits_io_min(limits, limits->logical_block_size);
+}
+
+static void verity_dtr(struct dm_target *ti)
+{
+ struct dm_verity *v = ti->private;
+
+ if (v->verify_wq)
+ destroy_workqueue(v->verify_wq);
+
+ if (v->vec_mempool)
+ mempool_destroy(v->vec_mempool);
+
+ if (v->io_mempool)
+ mempool_destroy(v->io_mempool);
+
+ if (v->bufio)
+ dm_bufio_client_destroy(v->bufio);
+
+ kfree(v->salt);
+ kfree(v->root_digest);
+
+ if (v->tfm)
+ crypto_free_shash(v->tfm);
+
+ kfree(v->alg_name);
+
+ if (v->hash_dev)
+ dm_put_device(ti, v->hash_dev);
+
+ if (v->data_dev)
+ dm_put_device(ti, v->data_dev);
+
+ kfree(v);
+}
+
+/*
+ * Target parameters:
+ * <version> The current format is version 1.
+ * Vsn 0 is compatible with original Chromium OS releases.
+ * <data device>
+ * <hash device>
+ * <data block size>
+ * <hash block size>
+ * <the number of data blocks>
+ * <hash start block>
+ * <algorithm>
+ * <digest>
+ * <salt> Hex string or "-" if no salt.
+ */
+static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+ struct dm_verity *v;
+ unsigned num;
+ unsigned long long num_ll;
+ int r;
+ int i;
+ sector_t hash_position;
+ char dummy;
+
+ v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
+ if (!v) {
+ ti->error = "Cannot allocate verity structure";
+ return -ENOMEM;
+ }
+ ti->private = v;
+ v->ti = ti;
+
+ if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
+ ti->error = "Device must be readonly";
+ r = -EINVAL;
+ goto bad;
+ }
+
+ if (argc != 10) {
+ ti->error = "Invalid argument count: exactly 10 arguments required";
+ r = -EINVAL;
+ goto bad;
+ }
+
+ if (sscanf(argv[0], "%d%c", &num, &dummy) != 1 ||
+ num < 0 || num > 1) {
+ ti->error = "Invalid version";
+ r = -EINVAL;
+ goto bad;
+ }
+ v->version = num;
+
+ r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
+ if (r) {
+ ti->error = "Data device lookup failed";
+ goto bad;
+ }
+
+ r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev);
+ if (r) {
+ ti->error = "Data device lookup failed";
+ goto bad;
+ }
+
+ if (sscanf(argv[3], "%u%c", &num, &dummy) != 1 ||
+ !num || (num & (num - 1)) ||
+ num < bdev_logical_block_size(v->data_dev->bdev) ||
+ num > PAGE_SIZE) {
+ ti->error = "Invalid data device block size";
+ r = -EINVAL;
+ goto bad;
+ }
+ v->data_dev_block_bits = ffs(num) - 1;
+
+ if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
+ !num || (num & (num - 1)) ||
+ num < bdev_logical_block_size(v->hash_dev->bdev) ||
+ num > INT_MAX) {
+ ti->error = "Invalid hash device block size";
+ r = -EINVAL;
+ goto bad;
+ }
+ v->hash_dev_block_bits = ffs(num) - 1;
+
+ if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
+ num_ll << (v->data_dev_block_bits - SECTOR_SHIFT) !=
+ (sector_t)num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) {
+ ti->error = "Invalid data blocks";
+ r = -EINVAL;
+ goto bad;
+ }
+ v->data_blocks = num_ll;
+
+ if (ti->len > (v->data_blocks << (v->data_dev_block_bits - SECTOR_SHIFT))) {
+ ti->error = "Data device is too small";
+ r = -EINVAL;
+ goto bad;
+ }
+
+ if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
+ num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT) !=
+ (sector_t)num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) {
+ ti->error = "Invalid hash start";
+ r = -EINVAL;
+ goto bad;
+ }
+ v->hash_start = num_ll;
+
+ v->alg_name = kstrdup(argv[7], GFP_KERNEL);
+ if (!v->alg_name) {
+ ti->error = "Cannot allocate algorithm name";
+ r = -ENOMEM;
+ goto bad;
+ }
+
+ v->tfm = crypto_alloc_shash(v->alg_name, 0, 0);
+ if (IS_ERR(v->tfm)) {
+ ti->error = "Cannot initialize hash function";
+ r = PTR_ERR(v->tfm);
+ v->tfm = NULL;
+ goto bad;
+ }
+ v->digest_size = crypto_shash_digestsize(v->tfm);
+ if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
+ ti->error = "Digest size too big";
+ r = -EINVAL;
+ goto bad;
+ }
+ v->shash_descsize =
+ sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm);
+
+ v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
+ if (!v->root_digest) {
+ ti->error = "Cannot allocate root digest";
+ r = -ENOMEM;
+ goto bad;
+ }
+ if (strlen(argv[8]) != v->digest_size * 2 ||
+ hex2bin(v->root_digest, argv[8], v->digest_size)) {
+ ti->error = "Invalid root digest";
+ r = -EINVAL;
+ goto bad;
+ }
+
+ if (strcmp(argv[9], "-")) {
+ v->salt_size = strlen(argv[9]) / 2;
+ v->salt = kmalloc(v->salt_size, GFP_KERNEL);
+ if (!v->salt) {
+ ti->error = "Cannot allocate salt";
+ r = -ENOMEM;
+ goto bad;
+ }
+ if (strlen(argv[9]) != v->salt_size * 2 ||
+ hex2bin(v->salt, argv[9], v->salt_size)) {
+ ti->error = "Invalid salt";
+ r = -EINVAL;
+ goto bad;
+ }
+ }
+
+ v->hash_per_block_bits =
+ fls((1 << v->hash_dev_block_bits) / v->digest_size) - 1;
+
+ v->levels = 0;
+ if (v->data_blocks)
+ while (v->hash_per_block_bits * v->levels < 64 &&
+ (unsigned long long)(v->data_blocks - 1) >>
+ (v->hash_per_block_bits * v->levels))
+ v->levels++;
+
+ if (v->levels > DM_VERITY_MAX_LEVELS) {
+ ti->error = "Too many tree levels";
+ r = -E2BIG;
+ goto bad;
+ }
+
+ hash_position = v->hash_start;
+ for (i = v->levels - 1; i >= 0; i--) {
+ sector_t s;
+ v->hash_level_block[i] = hash_position;
+ s = verity_position_at_level(v, v->data_blocks, i);
+ s = (s >> v->hash_per_block_bits) +
+ !!(s & ((1 << v->hash_per_block_bits) - 1));
+ if (hash_position + s < hash_position) {
+ ti->error = "Hash device offset overflow";
+ r = -E2BIG;
+ goto bad;
+ }
+ hash_position += s;
+ }
+ v->hash_blocks = hash_position;
+
+ v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
+ 1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
+ dm_bufio_alloc_callback, NULL);
+ if (IS_ERR(v->bufio)) {
+ ti->error = "Cannot initialize dm-bufio";
+ r = PTR_ERR(v->bufio);
+ v->bufio = NULL;
+ goto bad;
+ }
+
+ if (dm_bufio_get_device_size(v->bufio) < v->hash_blocks) {
+ ti->error = "Hash device is too small";
+ r = -E2BIG;
+ goto bad;
+ }
+
+ v->io_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
+ sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2);
+ if (!v->io_mempool) {
+ ti->error = "Cannot allocate io mempool";
+ r = -ENOMEM;
+ goto bad;
+ }
+
+ v->vec_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
+ BIO_MAX_PAGES * sizeof(struct bio_vec));
+ if (!v->vec_mempool) {
+ ti->error = "Cannot allocate vector mempool";
+ r = -ENOMEM;
+ goto bad;
+ }
+
+ /* WQ_UNBOUND greatly improves performance when running on ramdisk */
+ v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
+ if (!v->verify_wq) {
+ ti->error = "Cannot allocate workqueue";
+ r = -ENOMEM;
+ goto bad;
+ }
+
+ return 0;
+
+bad:
+ verity_dtr(ti);
+
+ return r;
+}
+
+static struct target_type verity_target = {
+ .name = "verity",
+ .version = {1, 0, 0},
+ .module = THIS_MODULE,
+ .ctr = verity_ctr,
+ .dtr = verity_dtr,
+ .map = verity_map,
+ .status = verity_status,
+ .ioctl = verity_ioctl,
+ .merge = verity_merge,
+ .iterate_devices = verity_iterate_devices,
+ .io_hints = verity_io_hints,
+};
+
+static int __init dm_verity_init(void)
+{
+ int r;
+
+ r = dm_register_target(&verity_target);
+ if (r < 0)
+ DMERR("register failed %d", r);
+
+ return r;
+}
+
+static void __exit dm_verity_exit(void)
+{
+ dm_unregister_target(&verity_target);
+}
+
+module_init(dm_verity_init);
+module_exit(dm_verity_exit);
+
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_AUTHOR("Mandeep Baines <msb@chromium.org>");
+MODULE_AUTHOR("Will Drewry <wad@chromium.org>");
+MODULE_DESCRIPTION(DM_NAME " target for transparent disk integrity checking");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index b89c548ec3f8..e24143cc2040 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1016,6 +1016,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
/*
* Store bio_set for cleanup.
*/
+ clone->bi_end_io = NULL;
clone->bi_private = md->bs;
bio_put(clone);
free_tio(md, tio);
diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h
index d279c768f8f1..5709bfeab1e8 100644
--- a/drivers/md/persistent-data/dm-btree-internal.h
+++ b/drivers/md/persistent-data/dm-btree-internal.h
@@ -108,12 +108,9 @@ static inline void *value_base(struct node *n)
return &n->keys[le32_to_cpu(n->header.max_entries)];
}
-/*
- * FIXME: Now that value size is stored in node we don't need the third parm.
- */
-static inline void *value_ptr(struct node *n, uint32_t index, size_t value_size)
+static inline void *value_ptr(struct node *n, uint32_t index)
{
- BUG_ON(value_size != le32_to_cpu(n->header.value_size));
+ uint32_t value_size = le32_to_cpu(n->header.value_size);
return value_base(n) + (value_size * index);
}
diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
index 023fbc2d389e..aa71e2359a07 100644
--- a/drivers/md/persistent-data/dm-btree-remove.c
+++ b/drivers/md/persistent-data/dm-btree-remove.c
@@ -61,20 +61,20 @@ static void node_shift(struct node *n, int shift)
if (shift < 0) {
shift = -shift;
BUG_ON(shift > nr_entries);
- BUG_ON((void *) key_ptr(n, shift) >= value_ptr(n, shift, value_size));
+ BUG_ON((void *) key_ptr(n, shift) >= value_ptr(n, shift));
memmove(key_ptr(n, 0),
key_ptr(n, shift),
(nr_entries - shift) * sizeof(__le64));
- memmove(value_ptr(n, 0, value_size),
- value_ptr(n, shift, value_size),
+ memmove(value_ptr(n, 0),
+ value_ptr(n, shift),
(nr_entries - shift) * value_size);
} else {
BUG_ON(nr_entries + shift > le32_to_cpu(n->header.max_entries));
memmove(key_ptr(n, shift),
key_ptr(n, 0),
nr_entries * sizeof(__le64));
- memmove(value_ptr(n, shift, value_size),
- value_ptr(n, 0, value_size),
+ memmove(value_ptr(n, shift),
+ value_ptr(n, 0),
nr_entries * value_size);
}
}
@@ -91,16 +91,16 @@ static void node_copy(struct node *left, struct node *right, int shift)
memcpy(key_ptr(left, nr_left),
key_ptr(right, 0),
shift * sizeof(__le64));
- memcpy(value_ptr(left, nr_left, value_size),
- value_ptr(right, 0, value_size),
+ memcpy(value_ptr(left, nr_left),
+ value_ptr(right, 0),
shift * value_size);
} else {
BUG_ON(shift > le32_to_cpu(right->header.max_entries));
memcpy(key_ptr(right, 0),
key_ptr(left, nr_left - shift),
shift * sizeof(__le64));
- memcpy(value_ptr(right, 0, value_size),
- value_ptr(left, nr_left - shift, value_size),
+ memcpy(value_ptr(right, 0),
+ value_ptr(left, nr_left - shift),
shift * value_size);
}
}
@@ -120,26 +120,17 @@ static void delete_at(struct node *n, unsigned index)
key_ptr(n, index + 1),
nr_to_copy * sizeof(__le64));
- memmove(value_ptr(n, index, value_size),
- value_ptr(n, index + 1, value_size),
+ memmove(value_ptr(n, index),
+ value_ptr(n, index + 1),
nr_to_copy * value_size);
}
n->header.nr_entries = cpu_to_le32(nr_entries - 1);
}
-static unsigned del_threshold(struct node *n)
-{
- return le32_to_cpu(n->header.max_entries) / 3;
-}
-
static unsigned merge_threshold(struct node *n)
{
- /*
- * The extra one is because we know we're potentially going to
- * delete an entry.
- */
- return 2 * (le32_to_cpu(n->header.max_entries) / 3) + 1;
+ return le32_to_cpu(n->header.max_entries) / 3;
}
struct child {
@@ -175,7 +166,7 @@ static int init_child(struct dm_btree_info *info, struct node *parent,
if (inc)
inc_children(info->tm, result->n, &le64_type);
- *((__le64 *) value_ptr(parent, index, sizeof(__le64))) =
+ *((__le64 *) value_ptr(parent, index)) =
cpu_to_le64(dm_block_location(result->block));
return 0;
@@ -188,6 +179,15 @@ static int exit_child(struct dm_btree_info *info, struct child *c)
static void shift(struct node *left, struct node *right, int count)
{
+ uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
+ uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+ uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+ uint32_t r_max_entries = le32_to_cpu(right->header.max_entries);
+
+ BUG_ON(max_entries != r_max_entries);
+ BUG_ON(nr_left - count > max_entries);
+ BUG_ON(nr_right + count > max_entries);
+
if (!count)
return;
@@ -199,13 +199,8 @@ static void shift(struct node *left, struct node *right, int count)
node_shift(right, count);
}
- left->header.nr_entries =
- cpu_to_le32(le32_to_cpu(left->header.nr_entries) - count);
- BUG_ON(le32_to_cpu(left->header.nr_entries) > le32_to_cpu(left->header.max_entries));
-
- right->header.nr_entries =
- cpu_to_le32(le32_to_cpu(right->header.nr_entries) + count);
- BUG_ON(le32_to_cpu(right->header.nr_entries) > le32_to_cpu(right->header.max_entries));
+ left->header.nr_entries = cpu_to_le32(nr_left - count);
+ right->header.nr_entries = cpu_to_le32(nr_right + count);
}
static void __rebalance2(struct dm_btree_info *info, struct node *parent,
@@ -215,8 +210,9 @@ static void __rebalance2(struct dm_btree_info *info, struct node *parent,
struct node *right = r->n;
uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+ unsigned threshold = 2 * merge_threshold(left) + 1;
- if (nr_left + nr_right <= merge_threshold(left)) {
+ if (nr_left + nr_right < threshold) {
/*
* Merge
*/
@@ -234,9 +230,6 @@ static void __rebalance2(struct dm_btree_info *info, struct node *parent,
* Rebalance.
*/
unsigned target_left = (nr_left + nr_right) / 2;
- unsigned shift_ = nr_left - target_left;
- BUG_ON(le32_to_cpu(left->header.max_entries) <= nr_left - shift_);
- BUG_ON(le32_to_cpu(right->header.max_entries) <= nr_right + shift_);
shift(left, right, nr_left - target_left);
*key_ptr(parent, r->index) = right->keys[0];
}
@@ -272,6 +265,84 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info,
return exit_child(info, &right);
}
+/*
+ * We dump as many entries from center as possible into left, then the rest
+ * in right, then rebalance2. This wastes some cpu, but I want something
+ * simple atm.
+ */
+static void delete_center_node(struct dm_btree_info *info, struct node *parent,
+ struct child *l, struct child *c, struct child *r,
+ struct node *left, struct node *center, struct node *right,
+ uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+{
+ uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+ unsigned shift = min(max_entries - nr_left, nr_center);
+
+ BUG_ON(nr_left + shift > max_entries);
+ node_copy(left, center, -shift);
+ left->header.nr_entries = cpu_to_le32(nr_left + shift);
+
+ if (shift != nr_center) {
+ shift = nr_center - shift;
+ BUG_ON((nr_right + shift) > max_entries);
+ node_shift(right, shift);
+ node_copy(center, right, shift);
+ right->header.nr_entries = cpu_to_le32(nr_right + shift);
+ }
+ *key_ptr(parent, r->index) = right->keys[0];
+
+ delete_at(parent, c->index);
+ r->index--;
+
+ dm_tm_dec(info->tm, dm_block_location(c->block));
+ __rebalance2(info, parent, l, r);
+}
+
+/*
+ * Redistributes entries among 3 sibling nodes.
+ */
+static void redistribute3(struct dm_btree_info *info, struct node *parent,
+ struct child *l, struct child *c, struct child *r,
+ struct node *left, struct node *center, struct node *right,
+ uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+{
+ int s;
+ uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+ unsigned target = (nr_left + nr_center + nr_right) / 3;
+ BUG_ON(target > max_entries);
+
+ if (nr_left < nr_right) {
+ s = nr_left - target;
+
+ if (s < 0 && nr_center < -s) {
+ /* not enough in central node */
+ shift(left, center, nr_center);
+ s = nr_center - target;
+ shift(left, right, s);
+ nr_right += s;
+ } else
+ shift(left, center, s);
+
+ shift(center, right, target - nr_right);
+
+ } else {
+ s = target - nr_right;
+ if (s > 0 && nr_center < s) {
+ /* not enough in central node */
+ shift(center, right, nr_center);
+ s = target - nr_center;
+ shift(left, right, s);
+ nr_left -= s;
+ } else
+ shift(center, right, s);
+
+ shift(left, center, nr_left - target);
+ }
+
+ *key_ptr(parent, c->index) = center->keys[0];
+ *key_ptr(parent, r->index) = right->keys[0];
+}
+
static void __rebalance3(struct dm_btree_info *info, struct node *parent,
struct child *l, struct child *c, struct child *r)
{
@@ -282,62 +353,18 @@ static void __rebalance3(struct dm_btree_info *info, struct node *parent,
uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
uint32_t nr_center = le32_to_cpu(center->header.nr_entries);
uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
- uint32_t max_entries = le32_to_cpu(left->header.max_entries);
- unsigned target;
+ unsigned threshold = merge_threshold(left) * 4 + 1;
BUG_ON(left->header.max_entries != center->header.max_entries);
BUG_ON(center->header.max_entries != right->header.max_entries);
- if (((nr_left + nr_center + nr_right) / 2) < merge_threshold(center)) {
- /*
- * Delete center node:
- *
- * We dump as many entries from center as possible into
- * left, then the rest in right, then rebalance2. This
- * wastes some cpu, but I want something simple atm.
- */
- unsigned shift = min(max_entries - nr_left, nr_center);
-
- BUG_ON(nr_left + shift > max_entries);
- node_copy(left, center, -shift);
- left->header.nr_entries = cpu_to_le32(nr_left + shift);
-
- if (shift != nr_center) {
- shift = nr_center - shift;
- BUG_ON((nr_right + shift) >= max_entries);
- node_shift(right, shift);
- node_copy(center, right, shift);
- right->header.nr_entries = cpu_to_le32(nr_right + shift);
- }
- *key_ptr(parent, r->index) = right->keys[0];
-
- delete_at(parent, c->index);
- r->index--;
-
- dm_tm_dec(info->tm, dm_block_location(c->block));
- __rebalance2(info, parent, l, r);
-
- return;
- }
-
- /*
- * Rebalance
- */
- target = (nr_left + nr_center + nr_right) / 3;
- BUG_ON(target > max_entries);
-
- /*
- * Adjust the left node
- */
- shift(left, center, nr_left - target);
-
- /*
- * Adjust the right node
- */
- shift(center, right, target - nr_right);
- *key_ptr(parent, c->index) = center->keys[0];
- *key_ptr(parent, r->index) = right->keys[0];
+ if ((nr_left + nr_center + nr_right) < threshold)
+ delete_center_node(info, parent, l, c, r, left, center, right,
+ nr_left, nr_center, nr_right);
+ else
+ redistribute3(info, parent, l, c, r, left, center, right,
+ nr_left, nr_center, nr_right);
}
static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info,
@@ -441,9 +468,6 @@ static int rebalance_children(struct shadow_spine *s,
if (r)
return r;
- if (child_entries > del_threshold(n))
- return 0;
-
has_left_sibling = i > 0;
has_right_sibling = i < (le32_to_cpu(n->header.nr_entries) - 1);
@@ -496,7 +520,7 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
*/
if (shadow_has_parent(s)) {
__le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
- memcpy(value_ptr(dm_block_data(shadow_parent(s)), i, sizeof(__le64)),
+ memcpy(value_ptr(dm_block_data(shadow_parent(s)), i),
&location, sizeof(__le64));
}
@@ -553,7 +577,7 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
if (info->value_type.dec)
info->value_type.dec(info->value_type.context,
- value_ptr(n, index, info->value_type.size));
+ value_ptr(n, index));
delete_at(n, index);
}
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index bd1e7ffbe26c..d12b2cc51f1a 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -74,8 +74,7 @@ void inc_children(struct dm_transaction_manager *tm, struct node *n,
dm_tm_inc(tm, value64(n, i));
else if (vt->inc)
for (i = 0; i < nr_entries; i++)
- vt->inc(vt->context,
- value_ptr(n, i, vt->size));
+ vt->inc(vt->context, value_ptr(n, i));
}
static int insert_at(size_t value_size, struct node *node, unsigned index,
@@ -281,7 +280,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
for (i = 0; i < f->nr_children; i++)
info->value_type.dec(info->value_type.context,
- value_ptr(f->n, i, info->value_type.size));
+ value_ptr(f->n, i));
}
f->current_child = f->nr_children;
}
@@ -320,7 +319,7 @@ static int btree_lookup_raw(struct ro_spine *s, dm_block_t block, uint64_t key,
} while (!(flags & LEAF_NODE));
*result_key = le64_to_cpu(ro_node(s)->keys[i]);
- memcpy(v, value_ptr(ro_node(s), i, value_size), value_size);
+ memcpy(v, value_ptr(ro_node(s), i), value_size);
return 0;
}
@@ -432,7 +431,7 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root,
size = le32_to_cpu(ln->header.flags) & INTERNAL_NODE ?
sizeof(uint64_t) : s->info->value_type.size;
- memcpy(value_ptr(rn, 0, size), value_ptr(ln, nr_left, size),
+ memcpy(value_ptr(rn, 0), value_ptr(ln, nr_left),
size * nr_right);
/*
@@ -443,7 +442,7 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root,
pn = dm_block_data(parent);
location = cpu_to_le64(dm_block_location(left));
__dm_bless_for_disk(&location);
- memcpy_disk(value_ptr(pn, parent_index, sizeof(__le64)),
+ memcpy_disk(value_ptr(pn, parent_index),
&location, sizeof(__le64));
location = cpu_to_le64(dm_block_location(right));
@@ -529,8 +528,8 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
sizeof(__le64) : s->info->value_type.size;
- memcpy(value_ptr(ln, 0, size), value_ptr(pn, 0, size), nr_left * size);
- memcpy(value_ptr(rn, 0, size), value_ptr(pn, nr_left, size),
+ memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
+ memcpy(value_ptr(rn, 0), value_ptr(pn, nr_left),
nr_right * size);
/* new_parent should just point to l and r now */
@@ -545,12 +544,12 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
val = cpu_to_le64(dm_block_location(left));
__dm_bless_for_disk(&val);
pn->keys[0] = ln->keys[0];
- memcpy_disk(value_ptr(pn, 0, sizeof(__le64)), &val, sizeof(__le64));
+ memcpy_disk(value_ptr(pn, 0), &val, sizeof(__le64));
val = cpu_to_le64(dm_block_location(right));
__dm_bless_for_disk(&val);
pn->keys[1] = rn->keys[0];
- memcpy_disk(value_ptr(pn, 1, sizeof(__le64)), &val, sizeof(__le64));
+ memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64));
/*
* rejig the spine. This is ugly, since it knows too
@@ -595,7 +594,7 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
__le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
__dm_bless_for_disk(&location);
- memcpy_disk(value_ptr(dm_block_data(shadow_parent(s)), i, sizeof(uint64_t)),
+ memcpy_disk(value_ptr(dm_block_data(shadow_parent(s)), i),
&location, sizeof(__le64));
}
@@ -710,12 +709,12 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
(!info->value_type.equal ||
!info->value_type.equal(
info->value_type.context,
- value_ptr(n, index, info->value_type.size),
+ value_ptr(n, index),
value))) {
info->value_type.dec(info->value_type.context,
- value_ptr(n, index, info->value_type.size));
+ value_ptr(n, index));
}
- memcpy_disk(value_ptr(n, index, info->value_type.size),
+ memcpy_disk(value_ptr(n, index),
value, info->value_type.size);
}
diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c
index df2494c06cdc..ff3beed6ad2d 100644
--- a/drivers/md/persistent-data/dm-space-map-common.c
+++ b/drivers/md/persistent-data/dm-space-map-common.c
@@ -405,8 +405,6 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
if (r < 0)
return r;
-#if 0
- /* FIXME: dm_btree_remove doesn't handle this yet */
if (old > 2) {
r = dm_btree_remove(&ll->ref_count_info,
ll->ref_count_root,
@@ -414,7 +412,6 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
if (r)
return r;
}
-#endif
} else {
__le32 le_rc = cpu_to_le32(ref_count);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index e4b5c03ae516..73970cd97af1 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -29,7 +29,6 @@
#include <linux/ioctl.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include "dmxdev.h"
static int debug;
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 864b6274c729..e24ec539a5fd 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -20,7 +20,6 @@
#include <linux/workqueue.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <dvb_demux.h>
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 6ecbcf614878..4bd8bd56befc 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -53,7 +53,6 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <linux/dvb/frontend.h>
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 421cf73858d3..f6b52d549430 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -40,7 +40,6 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include <media/media-devnode.h>
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c
index d6488b79ae3b..bba299dbf396 100644
--- a/drivers/media/video/davinci/vpbe_osd.c
+++ b/drivers/media/video/davinci/vpbe_osd.c
@@ -28,7 +28,6 @@
#include <linux/clk.h>
#include <linux/slab.h>
-#include <mach/io.h>
#include <mach/cputype.h>
#include <mach/hardware.h>
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c
index 00e80f59d5d5..b21ecc8d134d 100644
--- a/drivers/media/video/davinci/vpbe_venc.c
+++ b/drivers/media/video/davinci/vpbe_venc.c
@@ -27,7 +27,6 @@
#include <mach/hardware.h>
#include <mach/mux.h>
-#include <mach/io.h>
#include <mach/i2c.h>
#include <linux/io.h>
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index f767df943954..2e220028aad2 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -54,7 +54,6 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <linux/dvb/video.h>
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 74522773e934..93c35ef5f0ad 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -286,7 +286,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
sg_dma_len(sg) = new_size;
- txd = ichan->dma_chan.device->device_prep_slave_sg(
+ txd = dmaengine_prep_slave_sg(
&ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!txd)
diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c
index 4ed1c7c28ae7..02194c056b00 100644
--- a/drivers/media/video/timblogiw.c
+++ b/drivers/media/video/timblogiw.c
@@ -564,7 +564,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
spin_unlock_irq(&fh->queue_lock);
- desc = fh->chan->device->device_prep_slave_sg(fh->chan,
+ desc = dmaengine_prep_slave_sg(fh->chan,
buf->sg, sg_elems, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
if (!desc) {
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 5c6100fb4072..1baec8393306 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -55,7 +55,6 @@
#include <linux/spi/spi.h>
#endif
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/div64.h>
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 041804b73ebd..70bec548d904 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -26,7 +26,6 @@
#include <linux/kmod.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index c8ed7b63fdf5..1d31d7284cbd 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -57,7 +57,6 @@
#include <linux/scatterlist.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <linux/atomic.h>
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 17dfe9bb6d27..87bd5ba38d5b 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -503,6 +503,101 @@ static void device_irq_exit(struct pm860x_chip *chip)
free_irq(chip->core_irq, chip);
}
+int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
+{
+ int ret = -EIO;
+ struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+ chip->client : chip->companion;
+
+ dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+ dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+ __func__, chip->osc_vote,
+ chip->osc_status);
+
+ mutex_lock(&chip->osc_lock);
+ /* Update voting status */
+ chip->osc_vote |= client;
+ /* If reference group is off - turn on*/
+ if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
+ chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+ /* Enable Reference group Vsys */
+ if (pm860x_set_bits(i2c, PM8606_VSYS,
+ PM8606_VSYS_EN, PM8606_VSYS_EN))
+ goto out;
+
+ /*Enable Internal Oscillator */
+ if (pm860x_set_bits(i2c, PM8606_MISC,
+ PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
+ goto out;
+ /* Update status (only if writes succeed) */
+ chip->osc_status = PM8606_REF_GP_OSC_ON;
+ }
+ mutex_unlock(&chip->osc_lock);
+
+ dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+ __func__, chip->osc_vote,
+ chip->osc_status, ret);
+ return 0;
+out:
+ mutex_unlock(&chip->osc_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_enable);
+
+int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
+{
+ int ret = -EIO;
+ struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+ chip->client : chip->companion;
+
+ dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+ dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+ __func__, chip->osc_vote,
+ chip->osc_status);
+
+ mutex_lock(&chip->osc_lock);
+ /*Update voting status */
+ chip->osc_vote &= ~(client);
+ /* If reference group is off and this is the last client to release
+ * - turn off */
+ if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
+ (chip->osc_vote == REF_GP_NO_CLIENTS)) {
+ chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+ /* Disable Reference group Vsys */
+ if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
+ goto out;
+ /* Disable Internal Oscillator */
+ if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
+ goto out;
+ chip->osc_status = PM8606_REF_GP_OSC_OFF;
+ }
+ mutex_unlock(&chip->osc_lock);
+
+ dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+ __func__, chip->osc_vote,
+ chip->osc_status, ret);
+ return 0;
+out:
+ mutex_unlock(&chip->osc_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_disable);
+
+static void __devinit device_osc_init(struct i2c_client *i2c)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+
+ mutex_init(&chip->osc_lock);
+ /* init portofino reference group voting and status */
+ /* Disable Reference group Vsys */
+ pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
+ /* Disable Internal Oscillator */
+ pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
+
+ chip->osc_vote = REF_GP_NO_CLIENTS;
+ chip->osc_status = PM8606_REF_GP_OSC_OFF;
+}
+
static void __devinit device_bk_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata)
{
@@ -767,6 +862,15 @@ out:
return;
}
+static void __devinit device_8606_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ device_osc_init(i2c);
+ device_bk_init(chip, pdata);
+ device_led_init(chip, pdata);
+}
+
int __devinit pm860x_device_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata)
{
@@ -774,8 +878,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
switch (chip->id) {
case CHIP_PM8606:
- device_bk_init(chip, pdata);
- device_led_init(chip, pdata);
+ device_8606_init(chip, chip->client, pdata);
break;
case CHIP_PM8607:
device_8607_init(chip, chip->client, pdata);
@@ -785,8 +888,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
if (chip->companion) {
switch (chip->id) {
case CHIP_PM8607:
- device_bk_init(chip, pdata);
- device_led_init(chip, pdata);
+ device_8606_init(chip, chip->companion, pdata);
break;
case CHIP_PM8606:
device_8607_init(chip, chip->companion, pdata);
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index f93dd9571c3c..b2cfdc458561 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -334,10 +334,35 @@ static int __devexit pm860x_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(dev) && chip->wakeup_flag)
+ enable_irq_wake(chip->core_irq);
+ return 0;
+}
+
+static int pm860x_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(dev) && chip->wakeup_flag)
+ disable_irq_wake(chip->core_irq);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
+
static struct i2c_driver pm860x_driver = {
.driver = {
.name = "88PM860x",
.owner = THIS_MODULE,
+ .pm = &pm860x_pm_ops,
},
.probe = pm860x_probe,
.remove = __devexit_p(pm860x_remove),
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 243e0c663c37..29f463cc09cb 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -143,6 +143,21 @@ config TPS6507X
This driver can also be built as a module. If so, the module
will be called tps6507x.
+config MFD_TPS65217
+ tristate "TPS65217 Power Management / White LED chips"
+ depends on I2C
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the TPS65217 series of
+ Power Management / White LED chips.
+ These include voltage regulators, lithium ion/polymer battery
+ charger, wled and other features that are often used in portable
+ devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called tps65217.
+
config MFD_TPS6586X
bool "TPS6586x Power Management chips"
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
@@ -162,6 +177,7 @@ config MFD_TPS65910
depends on I2C=y && GPIOLIB
select MFD_CORE
select GPIO_TPS65910
+ select REGMAP_I2C
help
if you say yes here you get support for the TPS65910 series of
Power Management chips.
@@ -171,7 +187,7 @@ config MFD_TPS65912
depends on GPIOLIB
config MFD_TPS65912_I2C
- bool "TPS95612 Power Management chip with I2C"
+ bool "TPS65912 Power Management chip with I2C"
select MFD_CORE
select MFD_TPS65912
depends on I2C=y && GPIOLIB
@@ -400,7 +416,7 @@ config MFD_MAX8997
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
help
- Say yes here to support for Maxim Semiconductor MAX8998/8966.
+ Say yes here to support for Maxim Semiconductor MAX8997/8966.
This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
MUIC controls on chip.
This driver provides common support for accessing the device;
@@ -812,6 +828,18 @@ config MFD_PM8XXX_IRQ
config TPS65911_COMPARATOR
tristate
+config MFD_TPS65090
+ bool "TPS65090 Power Management chips"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the TPS65090 series of
+ Power Management chips.
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config MFD_AAT2870_CORE
bool "Support for the AnalogicTech AAT2870"
select MFD_CORE
@@ -831,6 +859,28 @@ config MFD_INTEL_MSIC
Passage) chip. This chip embeds audio, battery, GPIO, etc.
devices used in Intel Medfield platforms.
+config MFD_RC5T583
+ bool "Ricoh RC5T583 Power Management system device"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Select this option to get support for the RICOH583 Power
+ Management system device.
+ This driver provides common support for accessing the device
+ through i2c interface. The device supports multiple sub-devices
+ like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey.
+ Additional drivers must be enabled in order to use the
+ different functionality of the device.
+
+config MFD_ANATOP
+ bool "Support for Freescale i.MX on-chip ANATOP controller"
+ depends on SOC_IMX6Q
+ help
+ Select this option to enable Freescale i.MX on-chip ANATOP
+ MFD controller. This controller embeds regulator and
+ thermal devices for Freescale i.MX platforms.
+
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b953bab934f7..05fa538c5efe 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o
obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_TPS6507X) += tps6507x.o
+obj-$(CONFIG_MFD_TPS65217) += tps65217.o
obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o
tps65912-objs := tps65912-core.o tps65912-irq.o
obj-$(CONFIG_MFD_TPS65912) += tps65912.o
@@ -109,6 +110,9 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
+obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
+obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index d295941c9a3d..1f08704f7ae8 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -32,6 +32,7 @@
#define AB8500_IT_SOURCE6_REG 0x05
#define AB8500_IT_SOURCE7_REG 0x06
#define AB8500_IT_SOURCE8_REG 0x07
+#define AB9540_IT_SOURCE13_REG 0x0C
#define AB8500_IT_SOURCE19_REG 0x12
#define AB8500_IT_SOURCE20_REG 0x13
#define AB8500_IT_SOURCE21_REG 0x14
@@ -53,6 +54,7 @@
#define AB8500_IT_LATCH9_REG 0x28
#define AB8500_IT_LATCH10_REG 0x29
#define AB8500_IT_LATCH12_REG 0x2B
+#define AB9540_IT_LATCH13_REG 0x2C
#define AB8500_IT_LATCH19_REG 0x32
#define AB8500_IT_LATCH20_REG 0x33
#define AB8500_IT_LATCH21_REG 0x34
@@ -90,21 +92,39 @@
#define AB8500_IT_MASK24_REG 0x57
#define AB8500_REV_REG 0x80
+#define AB8500_IC_NAME_REG 0x82
#define AB8500_SWITCH_OFF_STATUS 0x00
#define AB8500_TURN_ON_STATUS 0x00
+#define AB9540_MODEM_CTRL2_REG 0x23
+#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
+
/*
* Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
- * numbers are indexed into this array with (num / 8).
+ * numbers are indexed into this array with (num / 8). The interupts are
+ * defined in linux/mfd/ab8500.h
*
* This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
* offset 0.
*/
+/* AB8500 support */
static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
};
+/* AB9540 support */
+static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
+ 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
+};
+
+static const char ab8500_version_str[][7] = {
+ [AB8500_VERSION_AB8500] = "AB8500",
+ [AB8500_VERSION_AB8505] = "AB8505",
+ [AB8500_VERSION_AB9540] = "AB9540",
+ [AB8500_VERSION_AB8540] = "AB8540",
+};
+
static int ab8500_get_chip_id(struct device *dev)
{
struct ab8500 *ab8500;
@@ -127,9 +147,7 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
- ret = mutex_lock_interruptible(&ab8500->lock);
- if (ret)
- return ret;
+ mutex_lock(&ab8500->lock);
ret = ab8500->write(ab8500, addr, data);
if (ret < 0)
@@ -156,9 +174,7 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
* bank on higher 8 bits and reg in lower */
u16 addr = ((u16)bank) << 8 | reg;
- ret = mutex_lock_interruptible(&ab8500->lock);
- if (ret)
- return ret;
+ mutex_lock(&ab8500->lock);
ret = ab8500->read(ab8500, addr);
if (ret < 0)
@@ -185,31 +201,38 @@ static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
{
int ret;
- u8 data;
/* put the u8 bank and u8 reg together into a an u16.
* bank on higher 8 bits and reg in lower */
u16 addr = ((u16)bank) << 8 | reg;
- ret = mutex_lock_interruptible(&ab8500->lock);
- if (ret)
- return ret;
+ mutex_lock(&ab8500->lock);
- ret = ab8500->read(ab8500, addr);
- if (ret < 0) {
- dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
- addr, ret);
- goto out;
- }
+ if (ab8500->write_masked == NULL) {
+ u8 data;
- data = (u8)ret;
- data = (~bitmask & data) | (bitmask & bitvalues);
+ ret = ab8500->read(ab8500, addr);
+ if (ret < 0) {
+ dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
+ addr, ret);
+ goto out;
+ }
- ret = ab8500->write(ab8500, addr, data);
- if (ret < 0)
- dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
- addr, ret);
+ data = (u8)ret;
+ data = (~bitmask & data) | (bitmask & bitvalues);
+
+ ret = ab8500->write(ab8500, addr, data);
+ if (ret < 0)
+ dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
+ addr, ret);
- dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
+ dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
+ data);
+ goto out;
+ }
+ ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
+ if (ret < 0)
+ dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
+ ret);
out:
mutex_unlock(&ab8500->lock);
return ret;
@@ -248,7 +271,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
int i;
- for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+ for (i = 0; i < ab8500->mask_size; i++) {
u8 old = ab8500->oldmask[i];
u8 new = ab8500->mask[i];
int reg;
@@ -256,14 +279,17 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
if (new == old)
continue;
- /* Interrupt register 12 doesn't exist prior to version 2.0 */
- if (ab8500_irq_regoffset[i] == 11 &&
- ab8500->chip_id < AB8500_CUT2P0)
+ /*
+ * Interrupt register 12 doesn't exist prior to AB8500 version
+ * 2.0
+ */
+ if (ab8500->irq_reg_offset[i] == 11 &&
+ is_ab8500_1p1_or_earlier(ab8500))
continue;
ab8500->oldmask[i] = new;
- reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
+ reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
}
@@ -306,13 +332,16 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
dev_vdbg(ab8500->dev, "interrupt\n");
- for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
- int regoffset = ab8500_irq_regoffset[i];
+ for (i = 0; i < ab8500->mask_size; i++) {
+ int regoffset = ab8500->irq_reg_offset[i];
int status;
u8 value;
- /* Interrupt register 12 doesn't exist prior to version 2.0 */
- if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
+ /*
+ * Interrupt register 12 doesn't exist prior to AB8500 version
+ * 2.0
+ */
+ if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
continue;
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -336,8 +365,16 @@ static int ab8500_irq_init(struct ab8500 *ab8500)
{
int base = ab8500->irq_base;
int irq;
+ int num_irqs;
+
+ if (is_ab9540(ab8500))
+ num_irqs = AB9540_NR_IRQS;
+ else if (is_ab8505(ab8500))
+ num_irqs = AB8505_NR_IRQS;
+ else
+ num_irqs = AB8500_NR_IRQS;
- for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+ for (irq = base; irq < base + num_irqs; irq++) {
irq_set_chip_data(irq, ab8500);
irq_set_chip_and_handler(irq, &ab8500_irq_chip,
handle_simple_irq);
@@ -356,8 +393,16 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
{
int base = ab8500->irq_base;
int irq;
+ int num_irqs;
- for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+ if (is_ab9540(ab8500))
+ num_irqs = AB9540_NR_IRQS;
+ else if (is_ab8505(ab8500))
+ num_irqs = AB8505_NR_IRQS;
+ else
+ num_irqs = AB8500_NR_IRQS;
+
+ for (irq = base; irq < base + num_irqs; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
@@ -366,6 +411,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
}
}
+/* AB8500 GPIO Resources */
static struct resource __devinitdata ab8500_gpio_resources[] = {
{
.name = "GPIO_INT6",
@@ -375,6 +421,28 @@ static struct resource __devinitdata ab8500_gpio_resources[] = {
}
};
+/* AB9540 GPIO Resources */
+static struct resource __devinitdata ab9540_gpio_resources[] = {
+ {
+ .name = "GPIO_INT6",
+ .start = AB8500_INT_GPIO6R,
+ .end = AB8500_INT_GPIO41F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "GPIO_INT14",
+ .start = AB9540_INT_GPIO50R,
+ .end = AB9540_INT_GPIO54R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "GPIO_INT15",
+ .start = AB9540_INT_GPIO50F,
+ .end = AB9540_INT_GPIO54F,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
static struct resource __devinitdata ab8500_gpadc_resources[] = {
{
.name = "HW_CONV_END",
@@ -491,12 +559,6 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
.flags = IORESOURCE_IRQ,
},
{
- .name = "USB_CHARGE_DET_DONE",
- .start = AB8500_INT_USB_CHG_DET_DONE,
- .end = AB8500_INT_USB_CHG_DET_DONE,
- .flags = IORESOURCE_IRQ,
- },
- {
.name = "VBUS_OVV",
.start = AB8500_INT_VBUS_OVV,
.end = AB8500_INT_VBUS_OVV,
@@ -534,14 +596,8 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
},
{
.name = "USB_CHARGER_NOT_OKR",
- .start = AB8500_INT_USB_CHARGER_NOT_OK,
- .end = AB8500_INT_USB_CHARGER_NOT_OK,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB_CHARGER_NOT_OKF",
- .start = AB8500_INT_USB_CHARGER_NOT_OKF,
- .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .start = AB8500_INT_USB_CHARGER_NOT_OKR,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKR,
.flags = IORESOURCE_IRQ,
},
{
@@ -616,6 +672,12 @@ static struct resource __devinitdata ab8500_fg_resources[] = {
.end = AB8500_INT_CC_INT_CALIB,
.flags = IORESOURCE_IRQ,
},
+ {
+ .name = "CCEOC",
+ .start = AB8500_INT_CCEOC,
+ .end = AB8500_INT_CCEOC,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct resource __devinitdata ab8500_chargalg_resources[] = {};
@@ -630,8 +692,8 @@ static struct resource __devinitdata ab8500_debug_resources[] = {
},
{
.name = "IRQ_LAST",
- .start = AB8500_INT_USB_CHARGER_NOT_OKF,
- .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .start = AB8500_INT_XTAL32K_KO,
+ .end = AB8500_INT_XTAL32K_KO,
.flags = IORESOURCE_IRQ,
},
};
@@ -691,7 +753,7 @@ static struct resource __devinitdata ab8500_temp_resources[] = {
},
};
-static struct mfd_cell __devinitdata ab8500_devs[] = {
+static struct mfd_cell __devinitdata abx500_common_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
@@ -706,11 +768,6 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
.name = "ab8500-regulator",
},
{
- .name = "ab8500-gpio",
- .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
- .resources = ab8500_gpio_resources,
- },
- {
.name = "ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
.resources = ab8500_gpadc_resources,
@@ -748,11 +805,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
{
.name = "ab8500-codec",
},
- {
- .name = "ab8500-usb",
- .num_resources = ARRAY_SIZE(ab8500_usb_resources),
- .resources = ab8500_usb_resources,
- },
+
{
.name = "ab8500-poweron-key",
.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
@@ -781,6 +834,32 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
},
};
+static struct mfd_cell __devinitdata ab8500_devs[] = {
+ {
+ .name = "ab8500-gpio",
+ .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
+ .resources = ab8500_gpio_resources,
+ },
+ {
+ .name = "ab8500-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+};
+
+static struct mfd_cell __devinitdata ab9540_devs[] = {
+ {
+ .name = "ab8500-gpio",
+ .num_resources = ARRAY_SIZE(ab9540_gpio_resources),
+ .resources = ab9540_gpio_resources,
+ },
+ {
+ .name = "ab9540-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+};
+
static ssize_t show_chip_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -842,9 +921,64 @@ static ssize_t show_turn_on_status(struct device *dev,
return sprintf(buf, "%#x\n", value);
}
+static ssize_t show_ab9540_dbbrstn(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ab8500 *ab8500;
+ int ret;
+ u8 value;
+
+ ab8500 = dev_get_drvdata(dev);
+
+ ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
+ AB9540_MODEM_CTRL2_REG, &value);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n",
+ (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
+}
+
+static ssize_t store_ab9540_dbbrstn(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct ab8500 *ab8500;
+ int ret = count;
+ int err;
+ u8 bitvalues;
+
+ ab8500 = dev_get_drvdata(dev);
+
+ if (count > 0) {
+ switch (buf[0]) {
+ case '0':
+ bitvalues = 0;
+ break;
+ case '1':
+ bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
+ break;
+ default:
+ goto exit;
+ }
+
+ err = mask_and_set_register_interruptible(ab8500,
+ AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
+ AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
+ if (err)
+ dev_info(ab8500->dev,
+ "Failed to set DBBRSTN %c, err %#x\n",
+ buf[0], err);
+ }
+
+exit:
+ return ret;
+}
+
static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
+ show_ab9540_dbbrstn, store_ab9540_dbbrstn);
static struct attribute *ab8500_sysfs_entries[] = {
&dev_attr_chip_id.attr,
@@ -853,11 +987,23 @@ static struct attribute *ab8500_sysfs_entries[] = {
NULL,
};
+static struct attribute *ab9540_sysfs_entries[] = {
+ &dev_attr_chip_id.attr,
+ &dev_attr_switch_off_status.attr,
+ &dev_attr_turn_on_status.attr,
+ &dev_attr_dbbrstn.attr,
+ NULL,
+};
+
static struct attribute_group ab8500_attr_group = {
.attrs = ab8500_sysfs_entries,
};
-int __devinit ab8500_init(struct ab8500 *ab8500)
+static struct attribute_group ab9540_attr_group = {
+ .attrs = ab9540_sysfs_entries,
+};
+
+int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
{
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
int ret;
@@ -870,25 +1016,45 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
mutex_init(&ab8500->lock);
mutex_init(&ab8500->irq_lock);
+ if (version != AB8500_VERSION_UNDEFINED)
+ ab8500->version = version;
+ else {
+ ret = get_register_interruptible(ab8500, AB8500_MISC,
+ AB8500_IC_NAME_REG, &value);
+ if (ret < 0)
+ return ret;
+
+ ab8500->version = value;
+ }
+
ret = get_register_interruptible(ab8500, AB8500_MISC,
AB8500_REV_REG, &value);
if (ret < 0)
return ret;
- switch (value) {
- case AB8500_CUT1P0:
- case AB8500_CUT1P1:
- case AB8500_CUT2P0:
- case AB8500_CUT3P0:
- case AB8500_CUT3P3:
- dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
- break;
- default:
- dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
- return -EINVAL;
- }
ab8500->chip_id = value;
+ dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
+ ab8500_version_str[ab8500->version],
+ ab8500->chip_id >> 4,
+ ab8500->chip_id & 0x0F);
+
+ /* Configure AB8500 or AB9540 IRQ */
+ if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
+ ab8500->mask_size = AB9540_NUM_IRQ_REGS;
+ ab8500->irq_reg_offset = ab9540_irq_regoffset;
+ } else {
+ ab8500->mask_size = AB8500_NUM_IRQ_REGS;
+ ab8500->irq_reg_offset = ab8500_irq_regoffset;
+ }
+ ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+ if (!ab8500->mask)
+ return -ENOMEM;
+ ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+ if (!ab8500->oldmask) {
+ ret = -ENOMEM;
+ goto out_freemask;
+ }
/*
* ab8500 has switched off due to (SWITCH_OFF_STATUS):
* 0x01 Swoff bit programming
@@ -911,30 +1077,33 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
plat->init(ab8500);
/* Clear and mask all interrupts */
- for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
- /* Interrupt register 12 doesn't exist prior to version 2.0 */
- if (ab8500_irq_regoffset[i] == 11 &&
- ab8500->chip_id < AB8500_CUT2P0)
+ for (i = 0; i < ab8500->mask_size; i++) {
+ /*
+ * Interrupt register 12 doesn't exist prior to AB8500 version
+ * 2.0
+ */
+ if (ab8500->irq_reg_offset[i] == 11 &&
+ is_ab8500_1p1_or_earlier(ab8500))
continue;
get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+ AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
&value);
set_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
+ AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
}
ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
if (ret)
- return ret;
+ goto out_freeoldmask;
- for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
+ for (i = 0; i < ab8500->mask_size; i++)
ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
if (ab8500->irq_base) {
ret = ab8500_irq_init(ab8500);
if (ret)
- return ret;
+ goto out_freeoldmask;
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
IRQF_ONESHOT | IRQF_NO_SUSPEND,
@@ -943,17 +1112,34 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
goto out_removeirq;
}
- ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
- ARRAY_SIZE(ab8500_devs), NULL,
+ ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
+ ARRAY_SIZE(abx500_common_devs), NULL,
ab8500->irq_base);
+
if (ret)
goto out_freeirq;
- ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+ if (is_ab9540(ab8500))
+ ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
+ ARRAY_SIZE(ab9540_devs), NULL,
+ ab8500->irq_base);
+ else
+ ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
+ ARRAY_SIZE(ab9540_devs), NULL,
+ ab8500->irq_base);
if (ret)
- dev_err(ab8500->dev, "error creating sysfs entries\n");
+ goto out_freeirq;
- return ret;
+ if (is_ab9540(ab8500))
+ ret = sysfs_create_group(&ab8500->dev->kobj,
+ &ab9540_attr_group);
+ else
+ ret = sysfs_create_group(&ab8500->dev->kobj,
+ &ab8500_attr_group);
+ if (ret)
+ dev_err(ab8500->dev, "error creating sysfs entries\n");
+ else
+ return ret;
out_freeirq:
if (ab8500->irq_base)
@@ -961,18 +1147,27 @@ out_freeirq:
out_removeirq:
if (ab8500->irq_base)
ab8500_irq_remove(ab8500);
+out_freeoldmask:
+ kfree(ab8500->oldmask);
+out_freemask:
+ kfree(ab8500->mask);
return ret;
}
int __devexit ab8500_exit(struct ab8500 *ab8500)
{
- sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
+ if (is_ab9540(ab8500))
+ sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
+ else
+ sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
mfd_remove_devices(ab8500->dev);
if (ab8500->irq_base) {
free_irq(ab8500->irq, ab8500);
ab8500_irq_remove(ab8500);
}
+ kfree(ab8500->oldmask);
+ kfree(ab8500->mask);
return 0;
}
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c
index 087fecd71ce0..b83045f102be 100644
--- a/drivers/mfd/ab8500-i2c.c
+++ b/drivers/mfd/ab8500-i2c.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/dbx500-prcmu.h>
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
{
@@ -23,6 +23,18 @@ static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
return ret;
}
+static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
+ u8 data)
+{
+ int ret;
+
+ ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
+ &mask, 1);
+ if (ret < 0)
+ dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+ return ret;
+}
+
static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
{
int ret;
@@ -38,6 +50,7 @@ static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
static int __devinit ab8500_i2c_probe(struct platform_device *plf)
{
+ const struct platform_device_id *platid = platform_get_device_id(plf);
struct ab8500 *ab8500;
struct resource *resource;
int ret;
@@ -58,13 +71,15 @@ static int __devinit ab8500_i2c_probe(struct platform_device *plf)
ab8500->read = ab8500_i2c_read;
ab8500->write = ab8500_i2c_write;
+ ab8500->write_masked = ab8500_i2c_write_masked;
platform_set_drvdata(plf, ab8500);
- ret = ab8500_init(ab8500);
+ ret = ab8500_init(ab8500, platid->driver_data);
if (ret)
kfree(ab8500);
+
return ret;
}
@@ -78,13 +93,22 @@ static int __devexit ab8500_i2c_remove(struct platform_device *plf)
return 0;
}
+static const struct platform_device_id ab8500_id[] = {
+ { "ab8500-i2c", AB8500_VERSION_AB8500 },
+ { "ab8505-i2c", AB8500_VERSION_AB8505 },
+ { "ab9540-i2c", AB8500_VERSION_AB9540 },
+ { "ab8540-i2c", AB8500_VERSION_AB8540 },
+ { }
+};
+
static struct platform_driver ab8500_i2c_driver = {
.driver = {
.name = "ab8500-i2c",
.owner = THIS_MODULE,
},
.probe = ab8500_i2c_probe,
- .remove = __devexit_p(ab8500_i2c_remove)
+ .remove = __devexit_p(ab8500_i2c_remove),
+ .id_table = ab8500_id,
};
static int __init ab8500_i2c_init(void)
diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c
new file mode 100644
index 000000000000..2af42480635e
--- /dev/null
+++ b/drivers/mfd/anatop-mfd.c
@@ -0,0 +1,137 @@
+/*
+ * Anatop MFD driver
+ *
+ * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ * Copyright (C) 2012 Linaro
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/mfd/anatop.h>
+
+u32 anatop_get_bits(struct anatop *adata, u32 addr, int bit_shift,
+ int bit_width)
+{
+ u32 val, mask;
+
+ if (bit_width == 32)
+ mask = ~0;
+ else
+ mask = (1 << bit_width) - 1;
+
+ val = readl(adata->ioreg + addr);
+ val = (val >> bit_shift) & mask;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(anatop_get_bits);
+
+void anatop_set_bits(struct anatop *adata, u32 addr, int bit_shift,
+ int bit_width, u32 data)
+{
+ u32 val, mask;
+
+ if (bit_width == 32)
+ mask = ~0;
+ else
+ mask = (1 << bit_width) - 1;
+
+ spin_lock(&adata->reglock);
+ val = readl(adata->ioreg + addr) & ~(mask << bit_shift);
+ writel((data << bit_shift) | val, adata->ioreg + addr);
+ spin_unlock(&adata->reglock);
+}
+EXPORT_SYMBOL_GPL(anatop_set_bits);
+
+static const struct of_device_id of_anatop_match[] = {
+ { .compatible = "fsl,imx6q-anatop", },
+ { },
+};
+
+static int __devinit of_anatop_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ void *ioreg;
+ struct anatop *drvdata;
+
+ ioreg = of_iomap(np, 0);
+ if (!ioreg)
+ return -EADDRNOTAVAIL;
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+ drvdata->ioreg = ioreg;
+ spin_lock_init(&drvdata->reglock);
+ platform_set_drvdata(pdev, drvdata);
+ of_platform_populate(np, of_anatop_match, NULL, dev);
+
+ return 0;
+}
+
+static int __devexit of_anatop_remove(struct platform_device *pdev)
+{
+ struct anatop *drvdata;
+ drvdata = platform_get_drvdata(pdev);
+ iounmap(drvdata->ioreg);
+
+ return 0;
+}
+
+static struct platform_driver anatop_of_driver = {
+ .driver = {
+ .name = "anatop-mfd",
+ .owner = THIS_MODULE,
+ .of_match_table = of_anatop_match,
+ },
+ .probe = of_anatop_probe,
+ .remove = of_anatop_remove,
+};
+
+static int __init anatop_init(void)
+{
+ return platform_driver_register(&anatop_of_driver);
+}
+postcore_initcall(anatop_init);
+
+static void __exit anatop_exit(void)
+{
+ platform_driver_unregister(&anatop_of_driver);
+}
+module_exit(anatop_exit);
+
+MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_DESCRIPTION("ANATOP MFD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index b85bbd7f0d19..1895cf9fab8c 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -525,6 +525,11 @@ static void asic3_gpio_set(struct gpio_chip *chip,
return;
}
+static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return (offset < ASIC3_NUM_GPIOS) ? IRQ_BOARD_START + offset : -ENXIO;
+}
+
static __init int asic3_gpio_probe(struct platform_device *pdev,
u16 *gpio_config, int num)
{
@@ -976,6 +981,7 @@ static int __init asic3_probe(struct platform_device *pdev)
asic->gpio.set = asic3_gpio_set;
asic->gpio.direction_input = asic3_gpio_direction_input;
asic->gpio.direction_output = asic3_gpio_direction_output;
+ asic->gpio.to_irq = asic3_gpio_to_irq;
ret = asic3_gpio_probe(pdev,
pdata->gpio_config,
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
index 5ddde2a9176a..7ff313fe9fb1 100644
--- a/drivers/mfd/da9052-core.c
+++ b/drivers/mfd/da9052-core.c
@@ -16,7 +16,6 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -647,8 +646,6 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
struct irq_desc *desc;
int ret;
- mutex_init(&da9052->io_lock);
-
if (pdata && pdata->init != NULL)
pdata->init(da9052);
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index 44b97c70a61f..36b88e395499 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -74,24 +74,27 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
ret = da9052_i2c_enable_multiwrite(da9052);
if (ret < 0)
- goto err;
+ goto err_regmap;
ret = da9052_device_init(da9052, id->driver_data);
if (ret != 0)
- goto err;
+ goto err_regmap;
return 0;
+err_regmap:
+ regmap_exit(da9052->regmap);
err:
kfree(da9052);
return ret;
}
-static int da9052_i2c_remove(struct i2c_client *client)
+static int __devexit da9052_i2c_remove(struct i2c_client *client)
{
struct da9052 *da9052 = i2c_get_clientdata(client);
da9052_device_exit(da9052);
+ regmap_exit(da9052->regmap);
kfree(da9052);
return 0;
@@ -107,7 +110,7 @@ static struct i2c_device_id da9052_i2c_id[] = {
static struct i2c_driver da9052_i2c_driver = {
.probe = da9052_i2c_probe,
- .remove = da9052_i2c_remove,
+ .remove = __devexit_p(da9052_i2c_remove),
.id_table = da9052_i2c_id,
.driver = {
.name = "da9052",
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
index cdbc7cad326f..6faf149e8d94 100644
--- a/drivers/mfd/da9052-spi.c
+++ b/drivers/mfd/da9052-spi.c
@@ -21,7 +21,7 @@
#include <linux/mfd/da9052/da9052.h>
-static int da9052_spi_probe(struct spi_device *spi)
+static int __devinit da9052_spi_probe(struct spi_device *spi)
{
int ret;
const struct spi_device_id *id = spi_get_device_id(spi);
@@ -52,20 +52,23 @@ static int da9052_spi_probe(struct spi_device *spi)
ret = da9052_device_init(da9052, id->driver_data);
if (ret != 0)
- goto err;
+ goto err_regmap;
return 0;
+err_regmap:
+ regmap_exit(da9052->regmap);
err:
kfree(da9052);
return ret;
}
-static int da9052_spi_remove(struct spi_device *spi)
+static int __devexit da9052_spi_remove(struct spi_device *spi)
{
struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
da9052_device_exit(da9052);
+ regmap_exit(da9052->regmap);
kfree(da9052);
return 0;
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index af8e0efedbe4..ebc1e8658226 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -30,6 +30,7 @@
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
+#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/db8500-regs.h>
@@ -39,11 +40,6 @@
/* Offset for the firmware version within the TCPM */
#define PRCMU_FW_VERSION_OFFSET 0xA4
-/* PRCMU project numbers, defined by PRCMU FW */
-#define PRCMU_PROJECT_ID_8500V1_0 1
-#define PRCMU_PROJECT_ID_8500V2_0 2
-#define PRCMU_PROJECT_ID_8400V2_0 3
-
/* Index of different voltages to be used when accessing AVSData */
#define PRCM_AVS_BASE 0x2FC
#define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0)
@@ -137,6 +133,8 @@
#define PRCM_REQ_MB1_ARM_OPP (PRCM_REQ_MB1 + 0x0)
#define PRCM_REQ_MB1_APE_OPP (PRCM_REQ_MB1 + 0x1)
#define PRCM_REQ_MB1_PLL_ON_OFF (PRCM_REQ_MB1 + 0x4)
+#define PLL_SOC0_OFF 0x1
+#define PLL_SOC0_ON 0x2
#define PLL_SOC1_OFF 0x4
#define PLL_SOC1_ON 0x8
@@ -266,6 +264,11 @@
#define WAKEUP_BIT_GPIO7 BIT(30)
#define WAKEUP_BIT_GPIO8 BIT(31)
+static struct {
+ bool valid;
+ struct prcmu_fw_version version;
+} fw_info;
+
/*
* This vector maps irq numbers to the bits in the bit field used in
* communication with the PRCMU firmware.
@@ -341,11 +344,13 @@ static struct {
* mb1_transfer - state needed for mailbox 1 communication.
* @lock: The transaction lock.
* @work: The transaction completion structure.
+ * @ape_opp: The current APE OPP.
* @ack: Reply ("acknowledge") data.
*/
static struct {
struct mutex lock;
struct completion work;
+ u8 ape_opp;
struct {
u8 header;
u8 arm_opp;
@@ -413,79 +418,102 @@ static struct {
static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
/* Spinlocks */
+static DEFINE_SPINLOCK(prcmu_lock);
static DEFINE_SPINLOCK(clkout_lock);
-static DEFINE_SPINLOCK(gpiocr_lock);
/* Global var to runtime determine TCDM base for v2 or v1 */
static __iomem void *tcdm_base;
struct clk_mgt {
- unsigned int offset;
+ void __iomem *reg;
u32 pllsw;
+ int branch;
+ bool clk38div;
+};
+
+enum {
+ PLL_RAW,
+ PLL_FIX,
+ PLL_DIV
};
static DEFINE_SPINLOCK(clk_mgt_lock);
-#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT_OFF), 0 }
+#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
+ { (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
- CLK_MGT_ENTRY(SGACLK),
- CLK_MGT_ENTRY(UARTCLK),
- CLK_MGT_ENTRY(MSP02CLK),
- CLK_MGT_ENTRY(MSP1CLK),
- CLK_MGT_ENTRY(I2CCLK),
- CLK_MGT_ENTRY(SDMMCCLK),
- CLK_MGT_ENTRY(SLIMCLK),
- CLK_MGT_ENTRY(PER1CLK),
- CLK_MGT_ENTRY(PER2CLK),
- CLK_MGT_ENTRY(PER3CLK),
- CLK_MGT_ENTRY(PER5CLK),
- CLK_MGT_ENTRY(PER6CLK),
- CLK_MGT_ENTRY(PER7CLK),
- CLK_MGT_ENTRY(LCDCLK),
- CLK_MGT_ENTRY(BMLCLK),
- CLK_MGT_ENTRY(HSITXCLK),
- CLK_MGT_ENTRY(HSIRXCLK),
- CLK_MGT_ENTRY(HDMICLK),
- CLK_MGT_ENTRY(APEATCLK),
- CLK_MGT_ENTRY(APETRACECLK),
- CLK_MGT_ENTRY(MCDECLK),
- CLK_MGT_ENTRY(IPI2CCLK),
- CLK_MGT_ENTRY(DSIALTCLK),
- CLK_MGT_ENTRY(DMACLK),
- CLK_MGT_ENTRY(B2R2CLK),
- CLK_MGT_ENTRY(TVCLK),
- CLK_MGT_ENTRY(SSPCLK),
- CLK_MGT_ENTRY(RNGCLK),
- CLK_MGT_ENTRY(UICCCLK),
+ CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
+ CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false),
+ CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false),
+ CLK_MGT_ENTRY(DMACLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true),
+ CLK_MGT_ENTRY(TVCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false),
+};
+
+struct dsiclk {
+ u32 divsel_mask;
+ u32 divsel_shift;
+ u32 divsel;
+};
+
+static struct dsiclk dsiclk[2] = {
+ {
+ .divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK,
+ .divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT,
+ .divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+ },
+ {
+ .divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK,
+ .divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT,
+ .divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+ }
};
-static struct regulator *hwacc_regulator[NUM_HW_ACC];
-static struct regulator *hwacc_ret_regulator[NUM_HW_ACC];
-
-static bool hwacc_enabled[NUM_HW_ACC];
-static bool hwacc_ret_enabled[NUM_HW_ACC];
-
-static const char *hwacc_regulator_name[NUM_HW_ACC] = {
- [HW_ACC_SVAMMDSP] = "hwacc-sva-mmdsp",
- [HW_ACC_SVAPIPE] = "hwacc-sva-pipe",
- [HW_ACC_SIAMMDSP] = "hwacc-sia-mmdsp",
- [HW_ACC_SIAPIPE] = "hwacc-sia-pipe",
- [HW_ACC_SGA] = "hwacc-sga",
- [HW_ACC_B2R2] = "hwacc-b2r2",
- [HW_ACC_MCDE] = "hwacc-mcde",
- [HW_ACC_ESRAM1] = "hwacc-esram1",
- [HW_ACC_ESRAM2] = "hwacc-esram2",
- [HW_ACC_ESRAM3] = "hwacc-esram3",
- [HW_ACC_ESRAM4] = "hwacc-esram4",
+struct dsiescclk {
+ u32 en;
+ u32 div_mask;
+ u32 div_shift;
};
-static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
- [HW_ACC_SVAMMDSP] = "hwacc-sva-mmdsp-ret",
- [HW_ACC_SIAMMDSP] = "hwacc-sia-mmdsp-ret",
- [HW_ACC_ESRAM1] = "hwacc-esram1-ret",
- [HW_ACC_ESRAM2] = "hwacc-esram2-ret",
- [HW_ACC_ESRAM3] = "hwacc-esram3-ret",
- [HW_ACC_ESRAM4] = "hwacc-esram4-ret",
+static struct dsiescclk dsiescclk[3] = {
+ {
+ .en = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN,
+ .div_mask = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK,
+ .div_shift = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT,
+ },
+ {
+ .en = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN,
+ .div_mask = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK,
+ .div_shift = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT,
+ },
+ {
+ .en = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN,
+ .div_mask = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK,
+ .div_shift = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT,
+ }
};
/*
@@ -503,9 +531,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
/* PLLDIV=12, PLLSW=4 (PLLDDR) */
#define PRCMU_DSI_CLOCK_SETTING 0x0000008C
-/* PLLDIV=8, PLLSW=4 (PLLDDR) */
-#define PRCMU_DSI_CLOCK_SETTING_U8400 0x00000088
-
/* DPI 50000000 Hz */
#define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
(16 << PRCMU_CLK_PLL_DIV_SHIFT))
@@ -514,9 +539,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
/* D=101, N=1, R=4, SELDIV2=0 */
#define PRCMU_PLLDSI_FREQ_SETTING 0x00040165
-/* D=70, N=1, R=3, SELDIV2=0 */
-#define PRCMU_PLLDSI_FREQ_SETTING_U8400 0x00030146
-
#define PRCMU_ENABLE_PLLDSI 0x00000001
#define PRCMU_DISABLE_PLLDSI 0x00000000
#define PRCMU_RELEASE_RESET_DSS 0x0000400C
@@ -528,30 +550,17 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
-static struct {
- u8 project_number;
- u8 api_version;
- u8 func_version;
- u8 errata;
-} prcmu_version;
-
-
int db8500_prcmu_enable_dsipll(void)
{
int i;
- unsigned int plldsifreq;
/* Clear DSIPLL_RESETN */
writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
/* Unclamp DSIPLL in/out */
writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
- if (prcmu_is_u8400())
- plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
- else
- plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
/* Set DSI PLL FREQ */
- writel(plldsifreq, PRCM_PLLDSI_FREQ);
+ writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
/* Enable Escape clocks */
writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
@@ -583,12 +592,6 @@ int db8500_prcmu_disable_dsipll(void)
int db8500_prcmu_set_display_clocks(void)
{
unsigned long flags;
- unsigned int dsiclk;
-
- if (prcmu_is_u8400())
- dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
- else
- dsiclk = PRCMU_DSI_CLOCK_SETTING;
spin_lock_irqsave(&clk_mgt_lock, flags);
@@ -596,7 +599,7 @@ int db8500_prcmu_set_display_clocks(void)
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
- writel(dsiclk, PRCM_HDMICLK_MGT);
+ writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
@@ -608,43 +611,41 @@ int db8500_prcmu_set_display_clocks(void)
return 0;
}
-/**
- * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_enable_spi2(void)
+u32 db8500_prcmu_read(unsigned int reg)
+{
+ return readl(_PRCMU_BASE + reg);
+}
+
+void db8500_prcmu_write(unsigned int reg, u32 value)
{
- u32 reg;
unsigned long flags;
- spin_lock_irqsave(&gpiocr_lock, flags);
- reg = readl(PRCM_GPIOCR);
- writel(reg | PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
- spin_unlock_irqrestore(&gpiocr_lock, flags);
+ spin_lock_irqsave(&prcmu_lock, flags);
+ writel(value, (_PRCMU_BASE + reg));
+ spin_unlock_irqrestore(&prcmu_lock, flags);
}
-/**
- * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_disable_spi2(void)
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
{
- u32 reg;
+ u32 val;
unsigned long flags;
- spin_lock_irqsave(&gpiocr_lock, flags);
- reg = readl(PRCM_GPIOCR);
- writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
- spin_unlock_irqrestore(&gpiocr_lock, flags);
+ spin_lock_irqsave(&prcmu_lock, flags);
+ val = readl(_PRCMU_BASE + reg);
+ val = ((val & ~mask) | (value & mask));
+ writel(val, (_PRCMU_BASE + reg));
+ spin_unlock_irqrestore(&prcmu_lock, flags);
}
-bool prcmu_has_arm_maxopp(void)
+struct prcmu_fw_version *prcmu_get_fw_version(void)
{
- return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
- PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
+ return fw_info.valid ? &fw_info.version : NULL;
}
-bool prcmu_is_u8400(void)
+bool prcmu_has_arm_maxopp(void)
{
- return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
+ return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
+ PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
}
/**
@@ -787,6 +788,124 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
return 0;
}
+u8 db8500_prcmu_get_power_state_result(void)
+{
+ return readb(tcdm_base + PRCM_ACK_MB0_AP_PWRSTTR_STATUS);
+}
+
+/* This function decouple the gic from the prcmu */
+int db8500_prcmu_gic_decouple(void)
+{
+ u32 val = readl(PRCM_A9_MASK_REQ);
+
+ /* Set bit 0 register value to 1 */
+ writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ,
+ PRCM_A9_MASK_REQ);
+
+ /* Make sure the register is updated */
+ readl(PRCM_A9_MASK_REQ);
+
+ /* Wait a few cycles for the gic mask completion */
+ udelay(1);
+
+ return 0;
+}
+
+/* This function recouple the gic with the prcmu */
+int db8500_prcmu_gic_recouple(void)
+{
+ u32 val = readl(PRCM_A9_MASK_REQ);
+
+ /* Set bit 0 register value to 0 */
+ writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ);
+
+ return 0;
+}
+
+#define PRCMU_GIC_NUMBER_REGS 5
+
+/*
+ * This function checks if there are pending irq on the gic. It only
+ * makes sense if the gic has been decoupled before with the
+ * db8500_prcmu_gic_decouple function. Disabling an interrupt only
+ * disables the forwarding of the interrupt to any CPU interface. It
+ * does not prevent the interrupt from changing state, for example
+ * becoming pending, or active and pending if it is already
+ * active. Hence, we have to check the interrupt is pending *and* is
+ * active.
+ */
+bool db8500_prcmu_gic_pending_irq(void)
+{
+ u32 pr; /* Pending register */
+ u32 er; /* Enable register */
+ void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+ int i;
+
+ /* 5 registers. STI & PPI not skipped */
+ for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
+
+ pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
+ er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ if (pr & er)
+ return true; /* There is a pending interrupt */
+ }
+
+ return false;
+}
+
+/*
+ * This function checks if there are pending interrupt on the
+ * prcmu which has been delegated to monitor the irqs with the
+ * db8500_prcmu_copy_gic_settings function.
+ */
+bool db8500_prcmu_pending_irq(void)
+{
+ u32 it, im;
+ int i;
+
+ for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+ it = readl(PRCM_ARMITVAL31TO0 + i * 4);
+ im = readl(PRCM_ARMITMSK31TO0 + i * 4);
+ if (it & im)
+ return true; /* There is a pending interrupt */
+ }
+
+ return false;
+}
+
+/*
+ * This function checks if the specified cpu is in in WFI. It's usage
+ * makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
+ * function. Of course passing smp_processor_id() to this function will
+ * always return false...
+ */
+bool db8500_prcmu_is_cpu_in_wfi(int cpu)
+{
+ return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
+ PRCM_ARM_WFI_STANDBY_WFI0;
+}
+
+/*
+ * This function copies the gic SPI settings to the prcmu in order to
+ * monitor them and abort/finish the retention/off sequence or state.
+ */
+int db8500_prcmu_copy_gic_settings(void)
+{
+ u32 er; /* Enable register */
+ void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+ int i;
+
+ /* We skip the STI and PPI */
+ for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+ er = readl_relaxed(dist_base +
+ GIC_DIST_ENABLE_SET + (i + 1) * 4);
+ writel(er, PRCM_ARMITMSK31TO0 + i * 4);
+ }
+
+ return 0;
+}
+
/* This function should only be called while mb0_transfer.lock is held. */
static void config_wakeups(void)
{
@@ -909,23 +1028,23 @@ int db8500_prcmu_get_arm_opp(void)
}
/**
- * prcmu_get_ddr_opp - get the current DDR OPP
+ * db8500_prcmu_get_ddr_opp - get the current DDR OPP
*
* Returns: the current DDR OPP
*/
-int prcmu_get_ddr_opp(void)
+int db8500_prcmu_get_ddr_opp(void)
{
return readb(PRCM_DDR_SUBSYS_APE_MINBW);
}
/**
- * set_ddr_opp - set the appropriate DDR OPP
+ * db8500_set_ddr_opp - set the appropriate DDR OPP
* @opp: The new DDR operating point to which transition is to be made
* Returns: 0 on success, non-zero on failure
*
* This function sets the operating point of the DDR.
*/
-int prcmu_set_ddr_opp(u8 opp)
+int db8500_prcmu_set_ddr_opp(u8 opp)
{
if (opp < DDR_100_OPP || opp > DDR_25_OPP)
return -EINVAL;
@@ -935,25 +1054,82 @@ int prcmu_set_ddr_opp(u8 opp)
return 0;
}
+
+/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
+static void request_even_slower_clocks(bool enable)
+{
+ void __iomem *clock_reg[] = {
+ PRCM_ACLK_MGT,
+ PRCM_DMACLK_MGT
+ };
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&clk_mgt_lock, flags);
+
+ /* Grab the HW semaphore. */
+ while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+ cpu_relax();
+
+ for (i = 0; i < ARRAY_SIZE(clock_reg); i++) {
+ u32 val;
+ u32 div;
+
+ val = readl(clock_reg[i]);
+ div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK);
+ if (enable) {
+ if ((div <= 1) || (div > 15)) {
+ pr_err("prcmu: Bad clock divider %d in %s\n",
+ div, __func__);
+ goto unlock_and_return;
+ }
+ div <<= 1;
+ } else {
+ if (div <= 2)
+ goto unlock_and_return;
+ div >>= 1;
+ }
+ val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) |
+ (div & PRCM_CLK_MGT_CLKPLLDIV_MASK));
+ writel(val, clock_reg[i]);
+ }
+
+unlock_and_return:
+ /* Release the HW semaphore. */
+ writel(0, PRCM_SEM);
+
+ spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
/**
- * set_ape_opp - set the appropriate APE OPP
+ * db8500_set_ape_opp - set the appropriate APE OPP
* @opp: The new APE operating point to which transition is to be made
* Returns: 0 on success, non-zero on failure
*
* This function sets the operating point of the APE.
*/
-int prcmu_set_ape_opp(u8 opp)
+int db8500_prcmu_set_ape_opp(u8 opp)
{
int r = 0;
+ if (opp == mb1_transfer.ape_opp)
+ return 0;
+
mutex_lock(&mb1_transfer.lock);
+ if (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)
+ request_even_slower_clocks(false);
+
+ if ((opp != APE_100_OPP) && (mb1_transfer.ape_opp != APE_100_OPP))
+ goto skip_message;
+
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
- writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+ writeb(((opp == APE_50_PARTLY_25_OPP) ? APE_50_OPP : opp),
+ (tcdm_base + PRCM_REQ_MB1_APE_OPP));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
wait_for_completion(&mb1_transfer.work);
@@ -962,17 +1138,24 @@ int prcmu_set_ape_opp(u8 opp)
(mb1_transfer.ack.ape_opp != opp))
r = -EIO;
+skip_message:
+ if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
+ (r && (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)))
+ request_even_slower_clocks(true);
+ if (!r)
+ mb1_transfer.ape_opp = opp;
+
mutex_unlock(&mb1_transfer.lock);
return r;
}
/**
- * prcmu_get_ape_opp - get the current APE OPP
+ * db8500_prcmu_get_ape_opp - get the current APE OPP
*
* Returns: the current APE OPP
*/
-int prcmu_get_ape_opp(void)
+int db8500_prcmu_get_ape_opp(void)
{
return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
}
@@ -1056,7 +1239,9 @@ static int request_pll(u8 clock, bool enable)
{
int r = 0;
- if (clock == PRCMU_PLLSOC1)
+ if (clock == PRCMU_PLLSOC0)
+ clock = (enable ? PLL_SOC0_ON : PLL_SOC0_OFF);
+ else if (clock == PRCMU_PLLSOC1)
clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
else
return -EINVAL;
@@ -1081,132 +1266,6 @@ static int request_pll(u8 clock, bool enable)
}
/**
- * prcmu_set_hwacc - set the power state of a h/w accelerator
- * @hwacc_dev: The hardware accelerator (enum hw_acc_dev).
- * @state: The new power state (enum hw_acc_state).
- *
- * This function sets the power state of a hardware accelerator.
- * This function should not be called from interrupt context.
- *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator framework API.
- */
-int prcmu_set_hwacc(u16 hwacc_dev, u8 state)
-{
- int r = 0;
- bool ram_retention = false;
- bool enable, enable_ret;
-
- /* check argument */
- BUG_ON(hwacc_dev >= NUM_HW_ACC);
-
- /* get state of switches */
- enable = hwacc_enabled[hwacc_dev];
- enable_ret = hwacc_ret_enabled[hwacc_dev];
-
- /* set flag if retention is possible */
- switch (hwacc_dev) {
- case HW_ACC_SVAMMDSP:
- case HW_ACC_SIAMMDSP:
- case HW_ACC_ESRAM1:
- case HW_ACC_ESRAM2:
- case HW_ACC_ESRAM3:
- case HW_ACC_ESRAM4:
- ram_retention = true;
- break;
- }
-
- /* check argument */
- BUG_ON(state > HW_ON);
- BUG_ON(state == HW_OFF_RAMRET && !ram_retention);
-
- /* modify enable flags */
- switch (state) {
- case HW_OFF:
- enable_ret = false;
- enable = false;
- break;
- case HW_ON:
- enable = true;
- break;
- case HW_OFF_RAMRET:
- enable_ret = true;
- enable = false;
- break;
- }
-
- /* get regulator (lazy) */
- if (hwacc_regulator[hwacc_dev] == NULL) {
- hwacc_regulator[hwacc_dev] = regulator_get(NULL,
- hwacc_regulator_name[hwacc_dev]);
- if (IS_ERR(hwacc_regulator[hwacc_dev])) {
- pr_err("prcmu: failed to get supply %s\n",
- hwacc_regulator_name[hwacc_dev]);
- r = PTR_ERR(hwacc_regulator[hwacc_dev]);
- goto out;
- }
- }
-
- if (ram_retention) {
- if (hwacc_ret_regulator[hwacc_dev] == NULL) {
- hwacc_ret_regulator[hwacc_dev] = regulator_get(NULL,
- hwacc_ret_regulator_name[hwacc_dev]);
- if (IS_ERR(hwacc_ret_regulator[hwacc_dev])) {
- pr_err("prcmu: failed to get supply %s\n",
- hwacc_ret_regulator_name[hwacc_dev]);
- r = PTR_ERR(hwacc_ret_regulator[hwacc_dev]);
- goto out;
- }
- }
- }
-
- /* set regulators */
- if (ram_retention) {
- if (enable_ret && !hwacc_ret_enabled[hwacc_dev]) {
- r = regulator_enable(hwacc_ret_regulator[hwacc_dev]);
- if (r < 0) {
- pr_err("prcmu_set_hwacc: ret enable failed\n");
- goto out;
- }
- hwacc_ret_enabled[hwacc_dev] = true;
- }
- }
-
- if (enable && !hwacc_enabled[hwacc_dev]) {
- r = regulator_enable(hwacc_regulator[hwacc_dev]);
- if (r < 0) {
- pr_err("prcmu_set_hwacc: enable failed\n");
- goto out;
- }
- hwacc_enabled[hwacc_dev] = true;
- }
-
- if (!enable && hwacc_enabled[hwacc_dev]) {
- r = regulator_disable(hwacc_regulator[hwacc_dev]);
- if (r < 0) {
- pr_err("prcmu_set_hwacc: disable failed\n");
- goto out;
- }
- hwacc_enabled[hwacc_dev] = false;
- }
-
- if (ram_retention) {
- if (!enable_ret && hwacc_ret_enabled[hwacc_dev]) {
- r = regulator_disable(hwacc_ret_regulator[hwacc_dev]);
- if (r < 0) {
- pr_err("prcmu_set_hwacc: ret disable failed\n");
- goto out;
- }
- hwacc_ret_enabled[hwacc_dev] = false;
- }
- }
-
-out:
- return r;
-}
-EXPORT_SYMBOL(prcmu_set_hwacc);
-
-/**
* db8500_prcmu_set_epod - set the state of a EPOD (power domain)
* @epod_id: The EPOD to set
* @epod_state: The new EPOD state
@@ -1375,7 +1434,7 @@ static int request_timclk(bool enable)
return 0;
}
-static int request_reg_clock(u8 clock, bool enable)
+static int request_clock(u8 clock, bool enable)
{
u32 val;
unsigned long flags;
@@ -1386,14 +1445,14 @@ static int request_reg_clock(u8 clock, bool enable)
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
- val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+ val = readl(clk_mgt[clock].reg);
if (enable) {
val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
} else {
clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
}
- writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+ writel(val, clk_mgt[clock].reg);
/* Release the HW semaphore. */
writel(0, PRCM_SEM);
@@ -1413,7 +1472,7 @@ static int request_sga_clock(u8 clock, bool enable)
writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
}
- ret = request_reg_clock(clock, enable);
+ ret = request_clock(clock, enable);
if (!ret && !enable) {
val = readl(PRCM_CGATING_BYPASS);
@@ -1423,6 +1482,78 @@ static int request_sga_clock(u8 clock, bool enable)
return ret;
}
+static inline bool plldsi_locked(void)
+{
+ return (readl(PRCM_PLLDSI_LOCKP) &
+ (PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+ PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3)) ==
+ (PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+ PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3);
+}
+
+static int request_plldsi(bool enable)
+{
+ int r = 0;
+ u32 val;
+
+ writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+ PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI), (enable ?
+ PRCM_MMIP_LS_CLAMP_CLR : PRCM_MMIP_LS_CLAMP_SET));
+
+ val = readl(PRCM_PLLDSI_ENABLE);
+ if (enable)
+ val |= PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+ else
+ val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+ writel(val, PRCM_PLLDSI_ENABLE);
+
+ if (enable) {
+ unsigned int i;
+ bool locked = plldsi_locked();
+
+ for (i = 10; !locked && (i > 0); --i) {
+ udelay(100);
+ locked = plldsi_locked();
+ }
+ if (locked) {
+ writel(PRCM_APE_RESETN_DSIPLL_RESETN,
+ PRCM_APE_RESETN_SET);
+ } else {
+ writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+ PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI),
+ PRCM_MMIP_LS_CLAMP_SET);
+ val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+ writel(val, PRCM_PLLDSI_ENABLE);
+ r = -EAGAIN;
+ }
+ } else {
+ writel(PRCM_APE_RESETN_DSIPLL_RESETN, PRCM_APE_RESETN_CLR);
+ }
+ return r;
+}
+
+static int request_dsiclk(u8 n, bool enable)
+{
+ u32 val;
+
+ val = readl(PRCM_DSI_PLLOUT_SEL);
+ val &= ~dsiclk[n].divsel_mask;
+ val |= ((enable ? dsiclk[n].divsel : PRCM_DSI_PLLOUT_SEL_OFF) <<
+ dsiclk[n].divsel_shift);
+ writel(val, PRCM_DSI_PLLOUT_SEL);
+ return 0;
+}
+
+static int request_dsiescclk(u8 n, bool enable)
+{
+ u32 val;
+
+ val = readl(PRCM_DSITVCLK_DIV);
+ enable ? (val |= dsiescclk[n].en) : (val &= ~dsiescclk[n].en);
+ writel(val, PRCM_DSITVCLK_DIV);
+ return 0;
+}
+
/**
* db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
* @clock: The clock for which the request is made.
@@ -1433,21 +1564,435 @@ static int request_sga_clock(u8 clock, bool enable)
*/
int db8500_prcmu_request_clock(u8 clock, bool enable)
{
- switch(clock) {
- case PRCMU_SGACLK:
+ if (clock == PRCMU_SGACLK)
return request_sga_clock(clock, enable);
- case PRCMU_TIMCLK:
+ else if (clock < PRCMU_NUM_REG_CLOCKS)
+ return request_clock(clock, enable);
+ else if (clock == PRCMU_TIMCLK)
return request_timclk(enable);
- case PRCMU_SYSCLK:
+ else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+ return request_dsiclk((clock - PRCMU_DSI0CLK), enable);
+ else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+ return request_dsiescclk((clock - PRCMU_DSI0ESCCLK), enable);
+ else if (clock == PRCMU_PLLDSI)
+ return request_plldsi(enable);
+ else if (clock == PRCMU_SYSCLK)
return request_sysclk(enable);
- case PRCMU_PLLSOC1:
+ else if ((clock == PRCMU_PLLSOC0) || (clock == PRCMU_PLLSOC1))
return request_pll(clock, enable);
+ else
+ return -EINVAL;
+}
+
+static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
+ int branch)
+{
+ u64 rate;
+ u32 val;
+ u32 d;
+ u32 div = 1;
+
+ val = readl(reg);
+
+ rate = src_rate;
+ rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT);
+
+ d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT);
+ if (d > 1)
+ div *= d;
+
+ d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT);
+ if (d > 1)
+ div *= d;
+
+ if (val & PRCM_PLL_FREQ_SELDIV2)
+ div *= 2;
+
+ if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
+ (val & PRCM_PLL_FREQ_DIV2EN) &&
+ ((reg == PRCM_PLLSOC0_FREQ) ||
+ (reg == PRCM_PLLDDR_FREQ))))
+ div *= 2;
+
+ (void)do_div(rate, div);
+
+ return (unsigned long)rate;
+}
+
+#define ROOT_CLOCK_RATE 38400000
+
+static unsigned long clock_rate(u8 clock)
+{
+ u32 val;
+ u32 pllsw;
+ unsigned long rate = ROOT_CLOCK_RATE;
+
+ val = readl(clk_mgt[clock].reg);
+
+ if (val & PRCM_CLK_MGT_CLK38) {
+ if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV))
+ rate /= 2;
+ return rate;
+ }
+
+ val |= clk_mgt[clock].pllsw;
+ pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+
+ if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+ rate = pll_rate(PRCM_PLLSOC0_FREQ, rate, clk_mgt[clock].branch);
+ else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+ rate = pll_rate(PRCM_PLLSOC1_FREQ, rate, clk_mgt[clock].branch);
+ else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_DDR)
+ rate = pll_rate(PRCM_PLLDDR_FREQ, rate, clk_mgt[clock].branch);
+ else
+ return 0;
+
+ if ((clock == PRCMU_SGACLK) &&
+ (val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) {
+ u64 r = (rate * 10);
+
+ (void)do_div(r, 25);
+ return (unsigned long)r;
+ }
+ val &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
+ if (val)
+ return rate / val;
+ else
+ return 0;
+}
+
+static unsigned long dsiclk_rate(u8 n)
+{
+ u32 divsel;
+ u32 div = 1;
+
+ divsel = readl(PRCM_DSI_PLLOUT_SEL);
+ divsel = ((divsel & dsiclk[n].divsel_mask) >> dsiclk[n].divsel_shift);
+
+ if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
+ divsel = dsiclk[n].divsel;
+
+ switch (divsel) {
+ case PRCM_DSI_PLLOUT_SEL_PHI_4:
+ div *= 2;
+ case PRCM_DSI_PLLOUT_SEL_PHI_2:
+ div *= 2;
+ case PRCM_DSI_PLLOUT_SEL_PHI:
+ return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+ PLL_RAW) / div;
default:
- break;
+ return 0;
+ }
+}
+
+static unsigned long dsiescclk_rate(u8 n)
+{
+ u32 div;
+
+ div = readl(PRCM_DSITVCLK_DIV);
+ div = ((div & dsiescclk[n].div_mask) >> (dsiescclk[n].div_shift));
+ return clock_rate(PRCMU_TVCLK) / max((u32)1, div);
+}
+
+unsigned long prcmu_clock_rate(u8 clock)
+{
+ if (clock < PRCMU_NUM_REG_CLOCKS)
+ return clock_rate(clock);
+ else if (clock == PRCMU_TIMCLK)
+ return ROOT_CLOCK_RATE / 16;
+ else if (clock == PRCMU_SYSCLK)
+ return ROOT_CLOCK_RATE;
+ else if (clock == PRCMU_PLLSOC0)
+ return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+ else if (clock == PRCMU_PLLSOC1)
+ return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+ else if (clock == PRCMU_PLLDDR)
+ return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+ else if (clock == PRCMU_PLLDSI)
+ return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+ PLL_RAW);
+ else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+ return dsiclk_rate(clock - PRCMU_DSI0CLK);
+ else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+ return dsiescclk_rate(clock - PRCMU_DSI0ESCCLK);
+ else
+ return 0;
+}
+
+static unsigned long clock_source_rate(u32 clk_mgt_val, int branch)
+{
+ if (clk_mgt_val & PRCM_CLK_MGT_CLK38)
+ return ROOT_CLOCK_RATE;
+ clk_mgt_val &= PRCM_CLK_MGT_CLKPLLSW_MASK;
+ if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+ return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, branch);
+ else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+ return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, branch);
+ else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_DDR)
+ return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, branch);
+ else
+ return 0;
+}
+
+static u32 clock_divider(unsigned long src_rate, unsigned long rate)
+{
+ u32 div;
+
+ div = (src_rate / rate);
+ if (div == 0)
+ return 1;
+ if (rate < (src_rate / div))
+ div++;
+ return div;
+}
+
+static long round_clock_rate(u8 clock, unsigned long rate)
+{
+ u32 val;
+ u32 div;
+ unsigned long src_rate;
+ long rounded_rate;
+
+ val = readl(clk_mgt[clock].reg);
+ src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+ clk_mgt[clock].branch);
+ div = clock_divider(src_rate, rate);
+ if (val & PRCM_CLK_MGT_CLK38) {
+ if (clk_mgt[clock].clk38div) {
+ if (div > 2)
+ div = 2;
+ } else {
+ div = 1;
+ }
+ } else if ((clock == PRCMU_SGACLK) && (div == 3)) {
+ u64 r = (src_rate * 10);
+
+ (void)do_div(r, 25);
+ if (r <= rate)
+ return (unsigned long)r;
+ }
+ rounded_rate = (src_rate / min(div, (u32)31));
+
+ return rounded_rate;
+}
+
+#define MIN_PLL_VCO_RATE 600000000ULL
+#define MAX_PLL_VCO_RATE 1680640000ULL
+
+static long round_plldsi_rate(unsigned long rate)
+{
+ long rounded_rate = 0;
+ unsigned long src_rate;
+ unsigned long rem;
+ u32 r;
+
+ src_rate = clock_rate(PRCMU_HDMICLK);
+ rem = rate;
+
+ for (r = 7; (rem > 0) && (r > 0); r--) {
+ u64 d;
+
+ d = (r * rate);
+ (void)do_div(d, src_rate);
+ if (d < 6)
+ d = 6;
+ else if (d > 255)
+ d = 255;
+ d *= src_rate;
+ if (((2 * d) < (r * MIN_PLL_VCO_RATE)) ||
+ ((r * MAX_PLL_VCO_RATE) < (2 * d)))
+ continue;
+ (void)do_div(d, r);
+ if (rate < d) {
+ if (rounded_rate == 0)
+ rounded_rate = (long)d;
+ break;
+ }
+ if ((rate - d) < rem) {
+ rem = (rate - d);
+ rounded_rate = (long)d;
+ }
+ }
+ return rounded_rate;
+}
+
+static long round_dsiclk_rate(unsigned long rate)
+{
+ u32 div;
+ unsigned long src_rate;
+ long rounded_rate;
+
+ src_rate = pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+ PLL_RAW);
+ div = clock_divider(src_rate, rate);
+ rounded_rate = (src_rate / ((div > 2) ? 4 : div));
+
+ return rounded_rate;
+}
+
+static long round_dsiescclk_rate(unsigned long rate)
+{
+ u32 div;
+ unsigned long src_rate;
+ long rounded_rate;
+
+ src_rate = clock_rate(PRCMU_TVCLK);
+ div = clock_divider(src_rate, rate);
+ rounded_rate = (src_rate / min(div, (u32)255));
+
+ return rounded_rate;
+}
+
+long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+ if (clock < PRCMU_NUM_REG_CLOCKS)
+ return round_clock_rate(clock, rate);
+ else if (clock == PRCMU_PLLDSI)
+ return round_plldsi_rate(rate);
+ else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+ return round_dsiclk_rate(rate);
+ else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+ return round_dsiescclk_rate(rate);
+ else
+ return (long)prcmu_clock_rate(clock);
+}
+
+static void set_clock_rate(u8 clock, unsigned long rate)
+{
+ u32 val;
+ u32 div;
+ unsigned long src_rate;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clk_mgt_lock, flags);
+
+ /* Grab the HW semaphore. */
+ while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+ cpu_relax();
+
+ val = readl(clk_mgt[clock].reg);
+ src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+ clk_mgt[clock].branch);
+ div = clock_divider(src_rate, rate);
+ if (val & PRCM_CLK_MGT_CLK38) {
+ if (clk_mgt[clock].clk38div) {
+ if (div > 1)
+ val |= PRCM_CLK_MGT_CLK38DIV;
+ else
+ val &= ~PRCM_CLK_MGT_CLK38DIV;
+ }
+ } else if (clock == PRCMU_SGACLK) {
+ val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK |
+ PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN);
+ if (div == 3) {
+ u64 r = (src_rate * 10);
+
+ (void)do_div(r, 25);
+ if (r <= rate) {
+ val |= PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN;
+ div = 0;
+ }
+ }
+ val |= min(div, (u32)31);
+ } else {
+ val &= ~PRCM_CLK_MGT_CLKPLLDIV_MASK;
+ val |= min(div, (u32)31);
+ }
+ writel(val, clk_mgt[clock].reg);
+
+ /* Release the HW semaphore. */
+ writel(0, PRCM_SEM);
+
+ spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
+static int set_plldsi_rate(unsigned long rate)
+{
+ unsigned long src_rate;
+ unsigned long rem;
+ u32 pll_freq = 0;
+ u32 r;
+
+ src_rate = clock_rate(PRCMU_HDMICLK);
+ rem = rate;
+
+ for (r = 7; (rem > 0) && (r > 0); r--) {
+ u64 d;
+ u64 hwrate;
+
+ d = (r * rate);
+ (void)do_div(d, src_rate);
+ if (d < 6)
+ d = 6;
+ else if (d > 255)
+ d = 255;
+ hwrate = (d * src_rate);
+ if (((2 * hwrate) < (r * MIN_PLL_VCO_RATE)) ||
+ ((r * MAX_PLL_VCO_RATE) < (2 * hwrate)))
+ continue;
+ (void)do_div(hwrate, r);
+ if (rate < hwrate) {
+ if (pll_freq == 0)
+ pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+ (r << PRCM_PLL_FREQ_R_SHIFT));
+ break;
+ }
+ if ((rate - hwrate) < rem) {
+ rem = (rate - hwrate);
+ pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+ (r << PRCM_PLL_FREQ_R_SHIFT));
+ }
}
+ if (pll_freq == 0)
+ return -EINVAL;
+
+ pll_freq |= (1 << PRCM_PLL_FREQ_N_SHIFT);
+ writel(pll_freq, PRCM_PLLDSI_FREQ);
+
+ return 0;
+}
+
+static void set_dsiclk_rate(u8 n, unsigned long rate)
+{
+ u32 val;
+ u32 div;
+
+ div = clock_divider(pll_rate(PRCM_PLLDSI_FREQ,
+ clock_rate(PRCMU_HDMICLK), PLL_RAW), rate);
+
+ dsiclk[n].divsel = (div == 1) ? PRCM_DSI_PLLOUT_SEL_PHI :
+ (div == 2) ? PRCM_DSI_PLLOUT_SEL_PHI_2 :
+ /* else */ PRCM_DSI_PLLOUT_SEL_PHI_4;
+
+ val = readl(PRCM_DSI_PLLOUT_SEL);
+ val &= ~dsiclk[n].divsel_mask;
+ val |= (dsiclk[n].divsel << dsiclk[n].divsel_shift);
+ writel(val, PRCM_DSI_PLLOUT_SEL);
+}
+
+static void set_dsiescclk_rate(u8 n, unsigned long rate)
+{
+ u32 val;
+ u32 div;
+
+ div = clock_divider(clock_rate(PRCMU_TVCLK), rate);
+ val = readl(PRCM_DSITVCLK_DIV);
+ val &= ~dsiescclk[n].div_mask;
+ val |= (min(div, (u32)255) << dsiescclk[n].div_shift);
+ writel(val, PRCM_DSITVCLK_DIV);
+}
+
+int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
if (clock < PRCMU_NUM_REG_CLOCKS)
- return request_reg_clock(clock, enable);
- return -EINVAL;
+ set_clock_rate(clock, rate);
+ else if (clock == PRCMU_PLLDSI)
+ return set_plldsi_rate(rate);
+ else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+ set_dsiclk_rate((clock - PRCMU_DSI0CLK), rate);
+ else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+ set_dsiescclk_rate((clock - PRCMU_DSI0ESCCLK), rate);
+ return 0;
}
int db8500_prcmu_config_esram0_deep_sleep(u8 state)
@@ -1476,7 +2021,7 @@ int db8500_prcmu_config_esram0_deep_sleep(u8 state)
return 0;
}
-int prcmu_config_hotdog(u8 threshold)
+int db8500_prcmu_config_hotdog(u8 threshold)
{
mutex_lock(&mb4_transfer.lock);
@@ -1494,7 +2039,7 @@ int prcmu_config_hotdog(u8 threshold)
return 0;
}
-int prcmu_config_hotmon(u8 low, u8 high)
+int db8500_prcmu_config_hotmon(u8 low, u8 high)
{
mutex_lock(&mb4_transfer.lock);
@@ -1533,7 +2078,7 @@ static int config_hot_period(u16 val)
return 0;
}
-int prcmu_start_temp_sense(u16 cycles32k)
+int db8500_prcmu_start_temp_sense(u16 cycles32k)
{
if (cycles32k == 0xFFFF)
return -EINVAL;
@@ -1541,7 +2086,7 @@ int prcmu_start_temp_sense(u16 cycles32k)
return config_hot_period(cycles32k);
}
-int prcmu_stop_temp_sense(void)
+int db8500_prcmu_stop_temp_sense(void)
{
return config_hot_period(0xFFFF);
}
@@ -1570,7 +2115,7 @@ static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
}
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
{
BUG_ON(num == 0 || num > 0xf);
return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
@@ -1578,17 +2123,17 @@ int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
A9WDOG_AUTO_OFF_DIS);
}
-int prcmu_enable_a9wdog(u8 id)
+int db8500_prcmu_enable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
}
-int prcmu_disable_a9wdog(u8 id)
+int db8500_prcmu_disable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
}
-int prcmu_kick_a9wdog(u8 id)
+int db8500_prcmu_kick_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
}
@@ -1596,16 +2141,8 @@ int prcmu_kick_a9wdog(u8 id)
/*
* timeout is 28 bit, in ms.
*/
-#define MAX_WATCHDOG_TIMEOUT 131000
-int prcmu_load_a9wdog(u8 id, u32 timeout)
+int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
{
- if (timeout > MAX_WATCHDOG_TIMEOUT)
- /*
- * Due to calculation bug in prcmu fw, timeouts
- * can't be bigger than 131 seconds.
- */
- return -EINVAL;
-
return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
(id & A9WDOG_ID_MASK) |
/*
@@ -1619,41 +2156,6 @@ int prcmu_load_a9wdog(u8 id, u32 timeout)
}
/**
- * prcmu_set_clock_divider() - Configure the clock divider.
- * @clock: The clock for which the request is made.
- * @divider: The clock divider. (< 32)
- *
- * This function should only be used by the clock implementation.
- * Do not use it from any other place!
- */
-int prcmu_set_clock_divider(u8 clock, u8 divider)
-{
- u32 val;
- unsigned long flags;
-
- if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
- return -EINVAL;
-
- spin_lock_irqsave(&clk_mgt_lock, flags);
-
- /* Grab the HW semaphore. */
- while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
- cpu_relax();
-
- val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
- val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
- val |= (u32)divider;
- writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
-
- /* Release the HW semaphore. */
- writel(0, PRCM_SEM);
-
- spin_unlock_irqrestore(&clk_mgt_lock, flags);
-
- return 0;
-}
-
-/**
* prcmu_abb_read() - Read register value(s) from the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
@@ -1675,6 +2177,7 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
+ writeb(0, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1700,16 +2203,19 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
}
/**
- * prcmu_abb_write() - Write register value(s) to the ABB.
+ * prcmu_abb_write_masked() - Write masked register value(s) to the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
* @value: The value(s) to write.
+ * @mask: The mask(s) to use.
* @size: The number of registers to write.
*
- * Reads register value(s) from the ABB.
+ * Writes masked register value(s) to the ABB.
+ * For each @value, only the bits set to 1 in the corresponding @mask
+ * will be written. The other bits are not changed.
* @size has to be 1 for the current firmware version.
*/
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size)
{
int r;
@@ -1721,6 +2227,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
+ writeb(~*mask, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1743,6 +2250,23 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
}
/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The value(s) to write.
+ * @size: The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ u8 mask = ~0;
+
+ return prcmu_abb_write_masked(slave, reg, value, &mask, size);
+}
+
+/**
* prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
*/
void prcmu_ac_wake_req(void)
@@ -1850,9 +2374,9 @@ u16 db8500_prcmu_get_reset_code(void)
}
/**
- * prcmu_reset_modem - ask the PRCMU to reset modem
+ * db8500_prcmu_reset_modem - ask the PRCMU to reset modem
*/
-void prcmu_modem_reset(void)
+void db8500_prcmu_modem_reset(void)
{
mutex_lock(&mb1_transfer.lock);
@@ -2099,6 +2623,26 @@ static struct irq_chip prcmu_irq_chip = {
.irq_unmask = prcmu_irq_unmask,
};
+static char *fw_project_name(u8 project)
+{
+ switch (project) {
+ case PRCMU_FW_PROJECT_U8500:
+ return "U8500";
+ case PRCMU_FW_PROJECT_U8500_C2:
+ return "U8500 C2";
+ case PRCMU_FW_PROJECT_U9500:
+ return "U9500";
+ case PRCMU_FW_PROJECT_U9500_C2:
+ return "U9500 C2";
+ case PRCMU_FW_PROJECT_U8520:
+ return "U8520";
+ case PRCMU_FW_PROJECT_U8420:
+ return "U8420";
+ default:
+ return "Unknown";
+ }
+}
+
void __init db8500_prcmu_early_init(void)
{
unsigned int i;
@@ -2108,11 +2652,13 @@ void __init db8500_prcmu_early_init(void)
if (tcpm_base != NULL) {
u32 version;
version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
- prcmu_version.project_number = version & 0xFF;
- prcmu_version.api_version = (version >> 8) & 0xFF;
- prcmu_version.func_version = (version >> 16) & 0xFF;
- prcmu_version.errata = (version >> 24) & 0xFF;
- pr_info("PRCMU firmware version %d.%d.%d\n",
+ fw_info.version.project = version & 0xFF;
+ fw_info.version.api_version = (version >> 8) & 0xFF;
+ fw_info.version.func_version = (version >> 16) & 0xFF;
+ fw_info.version.errata = (version >> 24) & 0xFF;
+ fw_info.valid = true;
+ pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
+ fw_project_name(fw_info.version.project),
(version >> 8) & 0xFF, (version >> 16) & 0xFF,
(version >> 24) & 0xFF);
iounmap(tcpm_base);
@@ -2130,6 +2676,7 @@ void __init db8500_prcmu_early_init(void)
init_completion(&mb0_transfer.ac_wake_work);
mutex_init(&mb1_transfer.lock);
init_completion(&mb1_transfer.work);
+ mb1_transfer.ape_opp = APE_NO_CHANGE;
mutex_init(&mb2_transfer.lock);
init_completion(&mb2_transfer.work);
spin_lock_init(&mb2_transfer.auto_pm_lock);
@@ -2154,7 +2701,7 @@ void __init db8500_prcmu_early_init(void)
}
}
-static void __init db8500_prcmu_init_clkforce(void)
+static void __init init_prcm_registers(void)
{
u32 val;
@@ -2186,19 +2733,17 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = {
REGULATOR_SUPPLY("vcore", "uart1"),
REGULATOR_SUPPLY("vcore", "uart2"),
REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+ REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
};
static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
- /* CG2900 and CW1200 power to off-chip peripherals */
- REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
- REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
/* AV8100 regulator */
REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
};
static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
- REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+ REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
REGULATOR_SUPPLY("vsupply", "mcde"),
};
@@ -2235,6 +2780,7 @@ static struct regulator_consumer_supply db8500_esram12_consumers[] = {
static struct regulator_consumer_supply db8500_esram34_consumers[] = {
REGULATOR_SUPPLY("v-esram34", "mcde"),
REGULATOR_SUPPLY("esram34", "cm_control"),
+ REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
};
static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
@@ -2291,7 +2837,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
- .supply_regulator = "db8500-vape",
+ /* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sva-mmdsp",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2307,7 +2853,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
- .supply_regulator = "db8500-vape",
+ /* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sva-pipe",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2316,7 +2862,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
.num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
},
[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
- .supply_regulator = "db8500-vape",
+ /* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sia-mmdsp",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2331,7 +2877,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
- .supply_regulator = "db8500-vape",
+ /* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sia-pipe",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2359,7 +2905,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
.num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
},
[DB8500_REGULATOR_SWITCH_ESRAM12] = {
- .supply_regulator = "db8500-vape",
+ /*
+ * esram12 is set in retention and supplied by Vsafe when Vape is off,
+ * no need to hold Vape
+ */
.constraints = {
.name = "db8500-esram12",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2374,7 +2923,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_ESRAM34] = {
- .supply_regulator = "db8500-vape",
+ /*
+ * esram34 is set in retention and supplied by Vsafe when Vape is off,
+ * no need to hold Vape
+ */
.constraints = {
.name = "db8500-esram34",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2412,7 +2964,7 @@ static int __init db8500_prcmu_probe(struct platform_device *pdev)
if (ux500_is_svp())
return -ENODEV;
- db8500_prcmu_init_clkforce();
+ init_prcm_registers();
/* Clean up the mailbox interrupts after pre-kernel code. */
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h
index ec22e9f15d32..3a0bf91d7780 100644
--- a/drivers/mfd/dbx500-prcmu-regs.h
+++ b/drivers/mfd/dbx500-prcmu-regs.h
@@ -17,41 +17,41 @@
#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
-#define PRCM_SVACLK_MGT_OFF 0x008
-#define PRCM_SIACLK_MGT_OFF 0x00C
-#define PRCM_SGACLK_MGT_OFF 0x014
-#define PRCM_UARTCLK_MGT_OFF 0x018
-#define PRCM_MSP02CLK_MGT_OFF 0x01C
-#define PRCM_I2CCLK_MGT_OFF 0x020
-#define PRCM_SDMMCCLK_MGT_OFF 0x024
-#define PRCM_SLIMCLK_MGT_OFF 0x028
-#define PRCM_PER1CLK_MGT_OFF 0x02C
-#define PRCM_PER2CLK_MGT_OFF 0x030
-#define PRCM_PER3CLK_MGT_OFF 0x034
-#define PRCM_PER5CLK_MGT_OFF 0x038
-#define PRCM_PER6CLK_MGT_OFF 0x03C
-#define PRCM_PER7CLK_MGT_OFF 0x040
-#define PRCM_PWMCLK_MGT_OFF 0x044 /* for DB5500 */
-#define PRCM_IRDACLK_MGT_OFF 0x048 /* for DB5500 */
-#define PRCM_IRRCCLK_MGT_OFF 0x04C /* for DB5500 */
-#define PRCM_LCDCLK_MGT_OFF 0x044
-#define PRCM_BMLCLK_MGT_OFF 0x04C
-#define PRCM_HSITXCLK_MGT_OFF 0x050
-#define PRCM_HSIRXCLK_MGT_OFF 0x054
-#define PRCM_HDMICLK_MGT_OFF 0x058
-#define PRCM_APEATCLK_MGT_OFF 0x05C
-#define PRCM_APETRACECLK_MGT_OFF 0x060
-#define PRCM_MCDECLK_MGT_OFF 0x064
-#define PRCM_IPI2CCLK_MGT_OFF 0x068
-#define PRCM_DSIALTCLK_MGT_OFF 0x06C
-#define PRCM_DMACLK_MGT_OFF 0x074
-#define PRCM_B2R2CLK_MGT_OFF 0x078
-#define PRCM_TVCLK_MGT_OFF 0x07C
-#define PRCM_UNIPROCLK_MGT_OFF 0x278
-#define PRCM_SSPCLK_MGT_OFF 0x280
-#define PRCM_RNGCLK_MGT_OFF 0x284
-#define PRCM_UICCCLK_MGT_OFF 0x27C
-#define PRCM_MSP1CLK_MGT_OFF 0x288
+#define PRCM_CLK_MGT(_offset) (void __iomem *)(IO_ADDRESS(U8500_PRCMU_BASE) \
+ + _offset)
+#define PRCM_ACLK_MGT PRCM_CLK_MGT(0x004)
+#define PRCM_SVACLK_MGT PRCM_CLK_MGT(0x008)
+#define PRCM_SIACLK_MGT PRCM_CLK_MGT(0x00C)
+#define PRCM_SGACLK_MGT PRCM_CLK_MGT(0x014)
+#define PRCM_UARTCLK_MGT PRCM_CLK_MGT(0x018)
+#define PRCM_MSP02CLK_MGT PRCM_CLK_MGT(0x01C)
+#define PRCM_I2CCLK_MGT PRCM_CLK_MGT(0x020)
+#define PRCM_SDMMCCLK_MGT PRCM_CLK_MGT(0x024)
+#define PRCM_SLIMCLK_MGT PRCM_CLK_MGT(0x028)
+#define PRCM_PER1CLK_MGT PRCM_CLK_MGT(0x02C)
+#define PRCM_PER2CLK_MGT PRCM_CLK_MGT(0x030)
+#define PRCM_PER3CLK_MGT PRCM_CLK_MGT(0x034)
+#define PRCM_PER5CLK_MGT PRCM_CLK_MGT(0x038)
+#define PRCM_PER6CLK_MGT PRCM_CLK_MGT(0x03C)
+#define PRCM_PER7CLK_MGT PRCM_CLK_MGT(0x040)
+#define PRCM_LCDCLK_MGT PRCM_CLK_MGT(0x044)
+#define PRCM_BMLCLK_MGT PRCM_CLK_MGT(0x04C)
+#define PRCM_HSITXCLK_MGT PRCM_CLK_MGT(0x050)
+#define PRCM_HSIRXCLK_MGT PRCM_CLK_MGT(0x054)
+#define PRCM_HDMICLK_MGT PRCM_CLK_MGT(0x058)
+#define PRCM_APEATCLK_MGT PRCM_CLK_MGT(0x05C)
+#define PRCM_APETRACECLK_MGT PRCM_CLK_MGT(0x060)
+#define PRCM_MCDECLK_MGT PRCM_CLK_MGT(0x064)
+#define PRCM_IPI2CCLK_MGT PRCM_CLK_MGT(0x068)
+#define PRCM_DSIALTCLK_MGT PRCM_CLK_MGT(0x06C)
+#define PRCM_DMACLK_MGT PRCM_CLK_MGT(0x074)
+#define PRCM_B2R2CLK_MGT PRCM_CLK_MGT(0x078)
+#define PRCM_TVCLK_MGT PRCM_CLK_MGT(0x07C)
+#define PRCM_UNIPROCLK_MGT PRCM_CLK_MGT(0x278)
+#define PRCM_SSPCLK_MGT PRCM_CLK_MGT(0x280)
+#define PRCM_RNGCLK_MGT PRCM_CLK_MGT(0x284)
+#define PRCM_UICCCLK_MGT PRCM_CLK_MGT(0x27C)
+#define PRCM_MSP1CLK_MGT PRCM_CLK_MGT(0x288)
#define PRCM_ARM_PLLDIVPS (_PRCMU_BASE + 0x118)
#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE 0x3f
@@ -79,6 +79,8 @@
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130)
+#define PRCM_ARM_WFI_STANDBY_WFI0 0x08
+#define PRCM_ARM_WFI_STANDBY_WFI1 0x10
#define PRCM_IOCR (_PRCMU_BASE + 0x310)
#define PRCM_IOCR_IOFORCE 0x1
@@ -131,20 +133,58 @@
#define PRCM_MMIP_LS_CLAMP_SET (_PRCMU_BASE + 0x420)
#define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424)
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP BIT(11)
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI BIT(22)
+
/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080)
+#define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084)
+#define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C)
+#define PRCM_PLL_FREQ_D_SHIFT 0
+#define PRCM_PLL_FREQ_D_MASK BITS(0, 7)
+#define PRCM_PLL_FREQ_N_SHIFT 8
+#define PRCM_PLL_FREQ_N_MASK BITS(8, 13)
+#define PRCM_PLL_FREQ_R_SHIFT 16
+#define PRCM_PLL_FREQ_R_MASK BITS(16, 18)
+#define PRCM_PLL_FREQ_SELDIV2 BIT(24)
+#define PRCM_PLL_FREQ_DIV2EN BIT(25)
+
#define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500)
#define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504)
#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
-#define PRCM_LCDCLK_MGT (_PRCMU_BASE + PRCM_LCDCLK_MGT_OFF)
-#define PRCM_MCDECLK_MGT (_PRCMU_BASE + PRCM_MCDECLK_MGT_OFF)
-#define PRCM_HDMICLK_MGT (_PRCMU_BASE + PRCM_HDMICLK_MGT_OFF)
-#define PRCM_TVCLK_MGT (_PRCMU_BASE + PRCM_TVCLK_MGT_OFF)
#define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530)
#define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C)
#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
#define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4)
#define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8)
+#define PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE BIT(0)
+
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 BIT(0)
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3 BIT(1)
+
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT 0
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK BITS(0, 2)
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT 8
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK BITS(8, 10)
+
+#define PRCM_DSI_PLLOUT_SEL_OFF 0
+#define PRCM_DSI_PLLOUT_SEL_PHI 1
+#define PRCM_DSI_PLLOUT_SEL_PHI_2 2
+#define PRCM_DSI_PLLOUT_SEL_PHI_4 3
+
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT 0
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK BITS(0, 7)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT 8
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK BITS(8, 15)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT 16
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK BITS(16, 23)
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN BIT(24)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN BIT(25)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN BIT(26)
+
+#define PRCM_APE_RESETN_DSIPLL_RESETN BIT(14)
+
#define PRCM_CLKOCR (_PRCMU_BASE + 0x1CC)
#define PRCM_CLKOCR_CLKOUT0_REF_CLK (1 << 0)
#define PRCM_CLKOCR_CLKOUT0_MASK BITS(0, 13)
@@ -183,9 +223,15 @@
#define PRCM_CLKOCR_CLKOSEL1_MASK BITS(22, 24)
#define PRCM_CLKOCR_CLK1TYPE BIT(28)
-#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4)
-#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7)
-#define PRCM_CLK_MGT_CLKEN BIT(8)
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC0 BIT(5)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC1 BIT(6)
+#define PRCM_CLK_MGT_CLKPLLSW_DDR BIT(7)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN BIT(8)
+#define PRCM_CLK_MGT_CLK38 BIT(9)
+#define PRCM_CLK_MGT_CLK38DIV BIT(11)
+#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN BIT(12)
/* GPIOCR register */
#define PRCM_GPIOCR_SPI2_SELECT BIT(23)
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 7122386b4e3c..9fd4f63c45cc 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -560,6 +560,8 @@ EXPORT_SYMBOL(mc13xxx_get_flags);
#define MC13XXX_ADC1_CHAN0_SHIFT 5
#define MC13XXX_ADC1_CHAN1_SHIFT 8
+#define MC13783_ADC1_ATO_SHIFT 11
+#define MC13783_ADC1_ATOX (1 << 19)
struct mc13xxx_adcdone_data {
struct mc13xxx *mc13xxx;
@@ -580,7 +582,8 @@ static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
#define MC13XXX_ADC_WORKING (1 << 0)
int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
- unsigned int channel, unsigned int *sample)
+ unsigned int channel, u8 ato, bool atox,
+ unsigned int *sample)
{
u32 adc0, adc1, old_adc0;
int i, ret;
@@ -631,6 +634,9 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
return -EINVAL;
}
+ adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
+ if (atox)
+ adc1 |= MC13783_ADC1_ATOX;
dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
mc13xxx_handler_adcdone, __func__, &adcdone_data);
@@ -813,7 +819,8 @@ err_revision:
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
- mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+ mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
+ &pdata->touch, sizeof(pdata->touch));
if (pdata) {
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 6acf2e03f2ba..62e5e3617eb0 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -19,8 +19,6 @@
#include <linux/string.h>
#include <linux/mfd/mcp.h>
-#include <asm/system.h>
-
#define to_mcp(d) container_of(d, struct mcp, attached_device)
#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 1c0ceacaa1f6..c54e244ca0cf 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -24,7 +24,6 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <asm/system.h>
#include <mach/mcp.h>
#define DRIVER_NAME "sa11x0-mcp"
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 411f523d4878..ffc3d48676ae 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -162,7 +162,7 @@ int mfd_add_devices(struct device *parent, int id,
atomic_t *cnts;
/* initialize reference counting for all cells */
- cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
+ cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL);
if (!cnts)
return -ENOMEM;
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 68ac2c55d5ae..95a2e546a489 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -170,7 +170,7 @@ struct usbhs_hcd_omap {
/*-------------------------------------------------------------------------*/
const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
-static u64 usbhs_dmamask = ~(u32)0;
+static u64 usbhs_dmamask = DMA_BIT_MASK(32);
/*-------------------------------------------------------------------------*/
@@ -223,7 +223,7 @@ static struct platform_device *omap_usbhs_alloc_child(const char *name,
}
child->dev.dma_mask = &usbhs_dmamask;
- child->dev.coherent_dma_mask = 0xffffffff;
+ dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
child->dev.parent = dev;
ret = platform_device_add(child);
@@ -799,14 +799,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, omap);
+ omap_usbhs_init(dev);
ret = omap_usbhs_alloc_children(pdev);
if (ret) {
dev_err(dev, "omap_usbhs_alloc_children failed\n");
goto err_alloc;
}
- omap_usbhs_init(dev);
-
goto end_probe;
err_alloc:
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index ff1a7e741ecd..189c2f07b83f 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -46,13 +46,7 @@ EXPORT_SYMBOL_GPL(pcf50633_read_block);
int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
int nr_regs, u8 *data)
{
- int ret;
-
- ret = regmap_raw_write(pcf->regmap, reg, data, nr_regs);
- if (ret != 0)
- return ret;
-
- return nr_regs;
+ return regmap_raw_write(pcf->regmap, reg, data, nr_regs);
}
EXPORT_SYMBOL_GPL(pcf50633_write_block);
diff --git a/drivers/mfd/pcf50633-gpio.c b/drivers/mfd/pcf50633-gpio.c
index 9ab19a8f669d..d02ddf2ebd63 100644
--- a/drivers/mfd/pcf50633-gpio.c
+++ b/drivers/mfd/pcf50633-gpio.c
@@ -19,32 +19,7 @@
#include <linux/mfd/pcf50633/core.h>
#include <linux/mfd/pcf50633/gpio.h>
-
-enum pcf50633_regulator_id {
- PCF50633_REGULATOR_AUTO,
- PCF50633_REGULATOR_DOWN1,
- PCF50633_REGULATOR_DOWN2,
- PCF50633_REGULATOR_LDO1,
- PCF50633_REGULATOR_LDO2,
- PCF50633_REGULATOR_LDO3,
- PCF50633_REGULATOR_LDO4,
- PCF50633_REGULATOR_LDO5,
- PCF50633_REGULATOR_LDO6,
- PCF50633_REGULATOR_HCLDO,
- PCF50633_REGULATOR_MEMLDO,
-};
-
-#define PCF50633_REG_AUTOOUT 0x1a
-#define PCF50633_REG_DOWN1OUT 0x1e
-#define PCF50633_REG_DOWN2OUT 0x22
-#define PCF50633_REG_MEMLDOOUT 0x26
-#define PCF50633_REG_LDO1OUT 0x2d
-#define PCF50633_REG_LDO2OUT 0x2f
-#define PCF50633_REG_LDO3OUT 0x31
-#define PCF50633_REG_LDO4OUT 0x33
-#define PCF50633_REG_LDO5OUT 0x35
-#define PCF50633_REG_LDO6OUT 0x37
-#define PCF50633_REG_HCLDOOUT 0x39
+#include <linux/mfd/pcf50633/pmic.h>
static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
[PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT,
diff --git a/drivers/mfd/pcf50633-irq.c b/drivers/mfd/pcf50633-irq.c
index 048a3b903b01..498286cbb530 100644
--- a/drivers/mfd/pcf50633-irq.c
+++ b/drivers/mfd/pcf50633-irq.c
@@ -19,12 +19,7 @@
#include <linux/slab.h>
#include <linux/mfd/pcf50633/core.h>
-
-/* Two MBCS registers used during cold start */
-#define PCF50633_REG_MBCS1 0x4b
-#define PCF50633_REG_MBCS2 0x4c
-#define PCF50633_MBCS1_USBPRES 0x01
-#define PCF50633_MBCS1_ADAPTPRES 0x01
+#include <linux/mfd/pcf50633/mbc.h>
int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
void (*handler) (int, void *), void *data)
diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c
new file mode 100644
index 000000000000..fa6f80fad5f1
--- /dev/null
+++ b/drivers/mfd/rc5t583-irq.c
@@ -0,0 +1,408 @@
+/*
+ * Interrupt driver for RICOH583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * based on code
+ * Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mfd/rc5t583.h>
+
+enum int_type {
+ SYS_INT = 0x1,
+ DCDC_INT = 0x2,
+ RTC_INT = 0x4,
+ ADC_INT = 0x8,
+ GPIO_INT = 0x10,
+};
+
+static int gpedge_add[] = {
+ RC5T583_GPIO_GPEDGE2,
+ RC5T583_GPIO_GPEDGE2
+};
+
+static int irq_en_add[] = {
+ RC5T583_INT_EN_SYS1,
+ RC5T583_INT_EN_SYS2,
+ RC5T583_INT_EN_DCDC,
+ RC5T583_INT_EN_RTC,
+ RC5T583_INT_EN_ADC1,
+ RC5T583_INT_EN_ADC2,
+ RC5T583_INT_EN_ADC3,
+ RC5T583_GPIO_EN_INT
+};
+
+static int irq_mon_add[] = {
+ RC5T583_INT_MON_SYS1,
+ RC5T583_INT_MON_SYS2,
+ RC5T583_INT_MON_DCDC,
+ RC5T583_INT_MON_RTC,
+ RC5T583_INT_IR_ADCL,
+ RC5T583_INT_IR_ADCH,
+ RC5T583_INT_IR_ADCEND,
+ RC5T583_INT_IR_GPIOF,
+ RC5T583_INT_IR_GPIOR
+};
+
+static int irq_clr_add[] = {
+ RC5T583_INT_IR_SYS1,
+ RC5T583_INT_IR_SYS2,
+ RC5T583_INT_IR_DCDC,
+ RC5T583_INT_IR_RTC,
+ RC5T583_INT_IR_ADCL,
+ RC5T583_INT_IR_ADCH,
+ RC5T583_INT_IR_ADCEND,
+ RC5T583_INT_IR_GPIOF,
+ RC5T583_INT_IR_GPIOR
+};
+
+static int main_int_type[] = {
+ SYS_INT,
+ SYS_INT,
+ DCDC_INT,
+ RTC_INT,
+ ADC_INT,
+ ADC_INT,
+ ADC_INT,
+ GPIO_INT,
+ GPIO_INT,
+};
+
+struct rc5t583_irq_data {
+ u8 int_type;
+ u8 master_bit;
+ u8 int_en_bit;
+ u8 mask_reg_index;
+ int grp_index;
+};
+
+#define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
+ _int_bit, _mask_ind) \
+ { \
+ .int_type = _int_type, \
+ .master_bit = _master_bit, \
+ .grp_index = _grp_index, \
+ .int_en_bit = _int_bit, \
+ .mask_reg_index = _mask_ind, \
+ }
+
+static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
+ [RC5T583_IRQ_ONKEY] = RC5T583_IRQ(SYS_INT, 0, 0, 0, 0),
+ [RC5T583_IRQ_ACOK] = RC5T583_IRQ(SYS_INT, 0, 1, 1, 0),
+ [RC5T583_IRQ_LIDOPEN] = RC5T583_IRQ(SYS_INT, 0, 2, 2, 0),
+ [RC5T583_IRQ_PREOT] = RC5T583_IRQ(SYS_INT, 0, 3, 3, 0),
+ [RC5T583_IRQ_CLKSTP] = RC5T583_IRQ(SYS_INT, 0, 4, 4, 0),
+ [RC5T583_IRQ_ONKEY_OFF] = RC5T583_IRQ(SYS_INT, 0, 5, 5, 0),
+ [RC5T583_IRQ_WD] = RC5T583_IRQ(SYS_INT, 0, 7, 7, 0),
+ [RC5T583_IRQ_EN_PWRREQ1] = RC5T583_IRQ(SYS_INT, 0, 8, 0, 1),
+ [RC5T583_IRQ_EN_PWRREQ2] = RC5T583_IRQ(SYS_INT, 0, 9, 1, 1),
+ [RC5T583_IRQ_PRE_VINDET] = RC5T583_IRQ(SYS_INT, 0, 10, 2, 1),
+
+ [RC5T583_IRQ_DC0LIM] = RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
+ [RC5T583_IRQ_DC1LIM] = RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
+ [RC5T583_IRQ_DC2LIM] = RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
+ [RC5T583_IRQ_DC3LIM] = RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
+
+ [RC5T583_IRQ_CTC] = RC5T583_IRQ(RTC_INT, 2, 0, 0, 3),
+ [RC5T583_IRQ_YALE] = RC5T583_IRQ(RTC_INT, 2, 5, 5, 3),
+ [RC5T583_IRQ_DALE] = RC5T583_IRQ(RTC_INT, 2, 6, 6, 3),
+ [RC5T583_IRQ_WALE] = RC5T583_IRQ(RTC_INT, 2, 7, 7, 3),
+
+ [RC5T583_IRQ_AIN1L] = RC5T583_IRQ(ADC_INT, 3, 0, 0, 4),
+ [RC5T583_IRQ_AIN2L] = RC5T583_IRQ(ADC_INT, 3, 1, 1, 4),
+ [RC5T583_IRQ_AIN3L] = RC5T583_IRQ(ADC_INT, 3, 2, 2, 4),
+ [RC5T583_IRQ_VBATL] = RC5T583_IRQ(ADC_INT, 3, 3, 3, 4),
+ [RC5T583_IRQ_VIN3L] = RC5T583_IRQ(ADC_INT, 3, 4, 4, 4),
+ [RC5T583_IRQ_VIN8L] = RC5T583_IRQ(ADC_INT, 3, 5, 5, 4),
+ [RC5T583_IRQ_AIN1H] = RC5T583_IRQ(ADC_INT, 3, 6, 0, 5),
+ [RC5T583_IRQ_AIN2H] = RC5T583_IRQ(ADC_INT, 3, 7, 1, 5),
+ [RC5T583_IRQ_AIN3H] = RC5T583_IRQ(ADC_INT, 3, 8, 2, 5),
+ [RC5T583_IRQ_VBATH] = RC5T583_IRQ(ADC_INT, 3, 9, 3, 5),
+ [RC5T583_IRQ_VIN3H] = RC5T583_IRQ(ADC_INT, 3, 10, 4, 5),
+ [RC5T583_IRQ_VIN8H] = RC5T583_IRQ(ADC_INT, 3, 11, 5, 5),
+ [RC5T583_IRQ_ADCEND] = RC5T583_IRQ(ADC_INT, 3, 12, 0, 6),
+
+ [RC5T583_IRQ_GPIO0] = RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
+ [RC5T583_IRQ_GPIO1] = RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
+ [RC5T583_IRQ_GPIO2] = RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
+ [RC5T583_IRQ_GPIO3] = RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
+ [RC5T583_IRQ_GPIO4] = RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
+ [RC5T583_IRQ_GPIO5] = RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
+ [RC5T583_IRQ_GPIO6] = RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
+ [RC5T583_IRQ_GPIO7] = RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
+};
+
+static void rc5t583_irq_lock(struct irq_data *irq_data)
+{
+ struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+ mutex_lock(&rc5t583->irq_lock);
+}
+
+static void rc5t583_irq_unmask(struct irq_data *irq_data)
+{
+ struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+ const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+ rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
+ rc5t583->intc_inten_reg |= 1 << data->master_bit;
+ rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
+}
+
+static void rc5t583_irq_mask(struct irq_data *irq_data)
+{
+ struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+ const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+ rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
+ if (!rc5t583->group_irq_en[data->grp_index])
+ rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
+
+ rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
+}
+
+static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
+{
+ struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+ const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+ int val = 0;
+ int gpedge_index;
+ int gpedge_bit_pos;
+
+ /* Supporting only trigger level inetrrupt */
+ if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
+ gpedge_index = data->int_en_bit / 4;
+ gpedge_bit_pos = data->int_en_bit % 4;
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ val |= 0x2;
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ val |= 0x1;
+
+ rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
+ rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
+ rc5t583_irq_unmask(irq_data);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
+{
+ struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+ int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
+ ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+ rc5t583->gpedge_reg[i]);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ gpedge_add[i], ret);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
+ ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+ rc5t583->irq_en_reg[i]);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ irq_en_add[i], ret);
+ }
+
+ ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
+ rc5t583->intc_inten_reg);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ RC5T583_INTC_INTEN, ret);
+
+ mutex_unlock(&rc5t583->irq_lock);
+}
+#ifdef CONFIG_PM_SLEEP
+static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
+{
+ struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+ return irq_set_irq_wake(rc5t583->chip_irq, on);
+}
+#else
+#define rc5t583_irq_set_wake NULL
+#endif
+
+static irqreturn_t rc5t583_irq(int irq, void *data)
+{
+ struct rc5t583 *rc5t583 = data;
+ uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
+ uint8_t master_int;
+ int i;
+ int ret;
+ unsigned int rtc_int_sts = 0;
+
+ /* Clear the status */
+ for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
+ int_sts[i] = 0;
+
+ ret = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
+ if (ret < 0) {
+ dev_err(rc5t583->dev,
+ "Error in reading reg 0x%02x error: %d\n",
+ RC5T583_INTC_INTMON, ret);
+ return IRQ_HANDLED;
+ }
+
+ for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
+ if (!(master_int & main_int_type[i]))
+ continue;
+
+ ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
+ if (ret < 0) {
+ dev_warn(rc5t583->dev,
+ "Error in reading reg 0x%02x error: %d\n",
+ irq_mon_add[i], ret);
+ int_sts[i] = 0;
+ continue;
+ }
+
+ if (main_int_type[i] & RTC_INT) {
+ rtc_int_sts = 0;
+ if (int_sts[i] & 0x1)
+ rtc_int_sts |= BIT(6);
+ if (int_sts[i] & 0x2)
+ rtc_int_sts |= BIT(7);
+ if (int_sts[i] & 0x4)
+ rtc_int_sts |= BIT(0);
+ if (int_sts[i] & 0x8)
+ rtc_int_sts |= BIT(5);
+ }
+
+ ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
+ ~int_sts[i]);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in reading reg 0x%02x error: %d\n",
+ irq_clr_add[i], ret);
+
+ if (main_int_type[i] & RTC_INT)
+ int_sts[i] = rtc_int_sts;
+ }
+
+ /* Merge gpio interrupts for rising and falling case*/
+ int_sts[7] |= int_sts[8];
+
+ /* Call interrupt handler if enabled */
+ for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
+ const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
+ if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
+ (rc5t583->group_irq_en[data->master_bit] &
+ (1 << data->grp_index)))
+ handle_nested_irq(rc5t583->irq_base + i);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct irq_chip rc5t583_irq_chip = {
+ .name = "rc5t583-irq",
+ .irq_mask = rc5t583_irq_mask,
+ .irq_unmask = rc5t583_irq_unmask,
+ .irq_bus_lock = rc5t583_irq_lock,
+ .irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
+ .irq_set_type = rc5t583_irq_set_type,
+ .irq_set_wake = rc5t583_irq_set_wake,
+};
+
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
+{
+ int i, ret;
+
+ if (!irq_base) {
+ dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&rc5t583->irq_lock);
+
+ /* Initailize all int register to 0 */
+ for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) {
+ ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+ rc5t583->irq_en_reg[i]);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ irq_en_add[i], ret);
+ }
+
+ for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++) {
+ ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+ rc5t583->gpedge_reg[i]);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ gpedge_add[i], ret);
+ }
+
+ ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ RC5T583_INTC_INTEN, ret);
+
+ /* Clear all interrupts in case they woke up active. */
+ for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) {
+ ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ irq_clr_add[i], ret);
+ }
+
+ rc5t583->irq_base = irq_base;
+ rc5t583->chip_irq = irq;
+
+ for (i = 0; i < RC5T583_MAX_IRQS; i++) {
+ int __irq = i + rc5t583->irq_base;
+ irq_set_chip_data(__irq, rc5t583);
+ irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
+ handle_simple_irq);
+ irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(__irq, IRQF_VALID);
+#endif
+ }
+
+ ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
+ "rc5t583", rc5t583);
+ if (ret < 0)
+ dev_err(rc5t583->dev,
+ "Error in registering interrupt error: %d\n", ret);
+ return ret;
+}
+
+int rc5t583_irq_exit(struct rc5t583 *rc5t583)
+{
+ if (rc5t583->chip_irq)
+ free_irq(rc5t583->chip_irq, rc5t583);
+ return 0;
+}
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c
new file mode 100644
index 000000000000..99ef944c621d
--- /dev/null
+++ b/drivers/mfd/rc5t583.c
@@ -0,0 +1,386 @@
+/*
+ * Core driver access RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ * Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rc5t583.h>
+#include <linux/regmap.h>
+
+#define RICOH_ONOFFSEL_REG 0x10
+#define RICOH_SWCTL_REG 0x5E
+
+struct deepsleep_control_data {
+ u8 reg_add;
+ u8 ds_pos_bit;
+};
+
+#define DEEPSLEEP_INIT(_id, _reg, _pos) \
+ { \
+ .reg_add = RC5T583_##_reg, \
+ .ds_pos_bit = _pos, \
+ }
+
+static struct deepsleep_control_data deepsleep_data[] = {
+ DEEPSLEEP_INIT(DC0, SLPSEQ1, 0),
+ DEEPSLEEP_INIT(DC1, SLPSEQ1, 4),
+ DEEPSLEEP_INIT(DC2, SLPSEQ2, 0),
+ DEEPSLEEP_INIT(DC3, SLPSEQ2, 4),
+ DEEPSLEEP_INIT(LDO0, SLPSEQ3, 0),
+ DEEPSLEEP_INIT(LDO1, SLPSEQ3, 4),
+ DEEPSLEEP_INIT(LDO2, SLPSEQ4, 0),
+ DEEPSLEEP_INIT(LDO3, SLPSEQ4, 4),
+ DEEPSLEEP_INIT(LDO4, SLPSEQ5, 0),
+ DEEPSLEEP_INIT(LDO5, SLPSEQ5, 4),
+ DEEPSLEEP_INIT(LDO6, SLPSEQ6, 0),
+ DEEPSLEEP_INIT(LDO7, SLPSEQ6, 4),
+ DEEPSLEEP_INIT(LDO8, SLPSEQ7, 0),
+ DEEPSLEEP_INIT(LDO9, SLPSEQ7, 4),
+ DEEPSLEEP_INIT(PSO0, SLPSEQ8, 0),
+ DEEPSLEEP_INIT(PSO1, SLPSEQ8, 4),
+ DEEPSLEEP_INIT(PSO2, SLPSEQ9, 0),
+ DEEPSLEEP_INIT(PSO3, SLPSEQ9, 4),
+ DEEPSLEEP_INIT(PSO4, SLPSEQ10, 0),
+ DEEPSLEEP_INIT(PSO5, SLPSEQ10, 4),
+ DEEPSLEEP_INIT(PSO6, SLPSEQ11, 0),
+ DEEPSLEEP_INIT(PSO7, SLPSEQ11, 4),
+};
+
+#define EXT_PWR_REQ \
+ (RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
+
+static struct mfd_cell rc5t583_subdevs[] = {
+ {.name = "rc5t583-regulator",},
+ {.name = "rc5t583-rtc", },
+ {.name = "rc5t583-key", }
+};
+
+int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+ return regmap_write(rc5t583->regmap, reg, val);
+}
+
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+ unsigned int ival;
+ int ret;
+ ret = regmap_read(rc5t583->regmap, reg, &ival);
+ if (!ret)
+ *val = (uint8_t)ival;
+ return ret;
+}
+
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+ unsigned int bit_mask)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+ return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
+}
+
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+ unsigned int bit_mask)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+ return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
+}
+
+int rc5t583_update(struct device *dev, unsigned int reg,
+ unsigned int val, unsigned int mask)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+ return regmap_update_bits(rc5t583->regmap, reg, mask, val);
+}
+
+static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
+ int id, int ext_pwr, int slots)
+{
+ int ret;
+ uint8_t sleepseq_val;
+ unsigned int en_bit;
+ unsigned int slot_bit;
+
+ if (id == RC5T583_DS_DC0) {
+ dev_err(dev, "PWRREQ1 is invalid control for rail %d\n", id);
+ return -EINVAL;
+ }
+
+ en_bit = deepsleep_data[id].ds_pos_bit;
+ slot_bit = en_bit + 1;
+ ret = rc5t583_read(dev, deepsleep_data[id].reg_add, &sleepseq_val);
+ if (ret < 0) {
+ dev_err(dev, "Error in reading reg 0x%x\n",
+ deepsleep_data[id].reg_add);
+ return ret;
+ }
+
+ sleepseq_val &= ~(0xF << en_bit);
+ sleepseq_val |= BIT(en_bit);
+ sleepseq_val |= ((slots & 0x7) << slot_bit);
+ ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(1));
+ if (ret < 0) {
+ dev_err(dev, "Error in updating the 0x%02x register\n",
+ RICOH_ONOFFSEL_REG);
+ return ret;
+ }
+
+ ret = rc5t583_write(dev, deepsleep_data[id].reg_add, sleepseq_val);
+ if (ret < 0) {
+ dev_err(dev, "Error in writing reg 0x%x\n",
+ deepsleep_data[id].reg_add);
+ return ret;
+ }
+
+ if (id == RC5T583_DS_LDO4) {
+ ret = rc5t583_write(dev, RICOH_SWCTL_REG, 0x1);
+ if (ret < 0)
+ dev_err(dev, "Error in writing reg 0x%x\n",
+ RICOH_SWCTL_REG);
+ }
+ return ret;
+}
+
+static int __rc5t583_set_ext_pwrreq2_control(struct device *dev,
+ int id, int ext_pwr)
+{
+ int ret;
+
+ if (id != RC5T583_DS_DC0) {
+ dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
+ return -EINVAL;
+ }
+
+ ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(2));
+ if (ret < 0)
+ dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
+ return ret;
+}
+
+int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
+ int ext_pwr_req, int deepsleep_slot_nr)
+{
+ if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
+ return -EINVAL;
+
+ if (ext_pwr_req & RC5T583_EXT_PWRREQ1_CONTROL)
+ return __rc5t583_set_ext_pwrreq1_control(dev, ds_id,
+ ext_pwr_req, deepsleep_slot_nr);
+
+ if (ext_pwr_req & RC5T583_EXT_PWRREQ2_CONTROL)
+ return __rc5t583_set_ext_pwrreq2_control(dev,
+ ds_id, ext_pwr_req);
+ return 0;
+}
+
+static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
+ struct rc5t583_platform_data *pdata)
+{
+ int ret;
+ int i;
+ uint8_t on_off_val = 0;
+
+ /* Clear ONOFFSEL register */
+ if (pdata->enable_shutdown)
+ on_off_val = 0x1;
+
+ ret = rc5t583_write(rc5t583->dev, RICOH_ONOFFSEL_REG, on_off_val);
+ if (ret < 0)
+ dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+ RICOH_ONOFFSEL_REG, ret);
+
+ ret = rc5t583_write(rc5t583->dev, RICOH_SWCTL_REG, 0x0);
+ if (ret < 0)
+ dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+ RICOH_SWCTL_REG, ret);
+
+ /* Clear sleep sequence register */
+ for (i = RC5T583_SLPSEQ1; i <= RC5T583_SLPSEQ11; ++i) {
+ ret = rc5t583_write(rc5t583->dev, i, 0x0);
+ if (ret < 0)
+ dev_warn(rc5t583->dev,
+ "Error in writing reg 0x%02x error: %d\n",
+ i, ret);
+ }
+ return 0;
+}
+
+static bool volatile_reg(struct device *dev, unsigned int reg)
+{
+ /* Enable caching in interrupt registers */
+ switch (reg) {
+ case RC5T583_INT_EN_SYS1:
+ case RC5T583_INT_EN_SYS2:
+ case RC5T583_INT_EN_DCDC:
+ case RC5T583_INT_EN_RTC:
+ case RC5T583_INT_EN_ADC1:
+ case RC5T583_INT_EN_ADC2:
+ case RC5T583_INT_EN_ADC3:
+ case RC5T583_GPIO_GPEDGE1:
+ case RC5T583_GPIO_GPEDGE2:
+ case RC5T583_GPIO_EN_INT:
+ return false;
+
+ case RC5T583_GPIO_MON_IOIN:
+ /* This is gpio input register */
+ return true;
+
+ default:
+ /* Enable caching in gpio registers */
+ if ((reg >= RC5T583_GPIO_IOSEL) &&
+ (reg <= RC5T583_GPIO_GPOFUNC))
+ return false;
+
+ /* Enable caching in sleep seq registers */
+ if ((reg >= RC5T583_SLPSEQ1) && (reg <= RC5T583_SLPSEQ11))
+ return false;
+
+ /* Enable caching of regulator registers */
+ if ((reg >= RC5T583_REG_DC0CTL) && (reg <= RC5T583_REG_SR3CTL))
+ return false;
+ if ((reg >= RC5T583_REG_LDOEN1) &&
+ (reg <= RC5T583_REG_LDO9DAC_DS))
+ return false;
+
+ break;
+ }
+
+ return true;
+}
+
+static const struct regmap_config rc5t583_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = volatile_reg,
+ .max_register = RC5T583_MAX_REGS,
+ .num_reg_defaults_raw = RC5T583_MAX_REGS,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rc5t583 *rc5t583;
+ struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
+ int ret;
+ bool irq_init_success = false;
+
+ if (!pdata) {
+ dev_err(&i2c->dev, "Err: Platform data not found\n");
+ return -EINVAL;
+ }
+
+ rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL);
+ if (!rc5t583) {
+ dev_err(&i2c->dev, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ rc5t583->dev = &i2c->dev;
+ i2c_set_clientdata(i2c, rc5t583);
+
+ rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+ if (IS_ERR(rc5t583->regmap)) {
+ ret = PTR_ERR(rc5t583->regmap);
+ dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
+ if (ret < 0)
+ goto err_irq_init;
+
+ if (i2c->irq) {
+ ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
+ /* Still continue with waring if irq init fails */
+ if (ret)
+ dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
+ else
+ irq_init_success = true;
+ }
+
+ ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
+ ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
+ if (ret) {
+ dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
+ goto err_add_devs;
+ }
+
+ return 0;
+
+err_add_devs:
+ if (irq_init_success)
+ rc5t583_irq_exit(rc5t583);
+err_irq_init:
+ regmap_exit(rc5t583->regmap);
+ return ret;
+}
+
+static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
+{
+ struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(rc5t583->dev);
+ rc5t583_irq_exit(rc5t583);
+ regmap_exit(rc5t583->regmap);
+ return 0;
+}
+
+static const struct i2c_device_id rc5t583_i2c_id[] = {
+ {.name = "rc5t583", .driver_data = 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, rc5t583_i2c_id);
+
+static struct i2c_driver rc5t583_i2c_driver = {
+ .driver = {
+ .name = "rc5t583",
+ .owner = THIS_MODULE,
+ },
+ .probe = rc5t583_i2c_probe,
+ .remove = __devexit_p(rc5t583_i2c_remove),
+ .id_table = rc5t583_i2c_id,
+};
+
+static int __init rc5t583_i2c_init(void)
+{
+ return i2c_add_driver(&rc5t583_i2c_driver);
+}
+subsys_initcall(rc5t583_i2c_init);
+
+static void __exit rc5t583_i2c_exit(void)
+{
+ i2c_del_driver(&rc5t583_i2c_driver);
+}
+
+module_exit(rc5t583_i2c_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("RICOH RC5T583 power management system device driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
index caadabeed8e9..48949d998d10 100644
--- a/drivers/mfd/s5m-core.c
+++ b/drivers/mfd/s5m-core.c
@@ -26,7 +26,27 @@
#include <linux/mfd/s5m87xx/s5m-rtc.h>
#include <linux/regmap.h>
-static struct mfd_cell s5m87xx_devs[] = {
+static struct mfd_cell s5m8751_devs[] = {
+ {
+ .name = "s5m8751-pmic",
+ }, {
+ .name = "s5m-charger",
+ }, {
+ .name = "s5m8751-codec",
+ },
+};
+
+static struct mfd_cell s5m8763_devs[] = {
+ {
+ .name = "s5m8763-pmic",
+ }, {
+ .name = "s5m-rtc",
+ }, {
+ .name = "s5m-charger",
+ },
+};
+
+static struct mfd_cell s5m8767_devs[] = {
{
.name = "s5m8767-pmic",
}, {
@@ -42,7 +62,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_read);
int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
{
- return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
+ return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
}
EXPORT_SYMBOL_GPL(s5m_bulk_read);
@@ -54,7 +74,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_write);
int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
{
- return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+ return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
}
EXPORT_SYMBOL_GPL(s5m_bulk_write);
@@ -74,10 +94,10 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
{
struct s5m_platform_data *pdata = i2c->dev.platform_data;
struct s5m87xx_dev *s5m87xx;
- int ret = 0;
- int error;
+ int ret;
- s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+ s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
+ GFP_KERNEL);
if (s5m87xx == NULL)
return -ENOMEM;
@@ -96,9 +116,9 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
if (IS_ERR(s5m87xx->regmap)) {
- error = PTR_ERR(s5m87xx->regmap);
+ ret = PTR_ERR(s5m87xx->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
- error);
+ ret);
goto err;
}
@@ -112,9 +132,23 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
pm_runtime_set_active(s5m87xx->dev);
- ret = mfd_add_devices(s5m87xx->dev, -1,
- s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
- NULL, 0);
+ switch (s5m87xx->device_type) {
+ case S5M8751X:
+ ret = mfd_add_devices(s5m87xx->dev, -1, s5m8751_devs,
+ ARRAY_SIZE(s5m8751_devs), NULL, 0);
+ break;
+ case S5M8763X:
+ ret = mfd_add_devices(s5m87xx->dev, -1, s5m8763_devs,
+ ARRAY_SIZE(s5m8763_devs), NULL, 0);
+ break;
+ case S5M8767X:
+ ret = mfd_add_devices(s5m87xx->dev, -1, s5m8767_devs,
+ ARRAY_SIZE(s5m8767_devs), NULL, 0);
+ break;
+ default:
+ /* If this happens the probe function is problem */
+ BUG();
+ }
if (ret < 0)
goto err;
@@ -126,7 +160,6 @@ err:
s5m_irq_exit(s5m87xx);
i2c_unregister_device(s5m87xx->rtc);
regmap_exit(s5m87xx->regmap);
- kfree(s5m87xx);
return ret;
}
@@ -138,7 +171,6 @@ static int s5m87xx_i2c_remove(struct i2c_client *i2c)
s5m_irq_exit(s5m87xx);
i2c_unregister_device(s5m87xx->rtc);
regmap_exit(s5m87xx->regmap);
- kfree(s5m87xx);
return 0;
}
diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c
index de76dfb6f0ad..0236676085cf 100644
--- a/drivers/mfd/s5m-irq.c
+++ b/drivers/mfd/s5m-irq.c
@@ -342,7 +342,10 @@ int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
break;
default:
- break;
+ dev_err(s5m87xx->dev,
+ "Unknown device type %d\n",
+ s5m87xx->device_type);
+ return -EINVAL;
}
}
@@ -444,7 +447,9 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
}
break;
default:
- break;
+ dev_err(s5m87xx->dev,
+ "Unknown device type %d\n", s5m87xx->device_type);
+ return -EINVAL;
}
if (!s5m87xx->ono)
@@ -467,12 +472,15 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
break;
default:
+ ret = -EINVAL;
break;
}
- if (ret)
+ if (ret) {
dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
s5m87xx->ono, ret);
+ return ret;
+ }
return 0;
}
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index f4d86117f44a..d927dd49acb3 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -387,14 +387,6 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
EXPORT_SYMBOL_GPL(sm501_unit_power);
-
-/* Perform a rounded division. */
-static long sm501fb_round_div(long num, long denom)
-{
- /* n / d + 1 / 2 = (2n + d) / 2d */
- return (2 * num + denom) / (2 * denom);
-}
-
/* clock value structure. */
struct sm501_clock {
unsigned long mclk;
@@ -428,7 +420,7 @@ static int sm501_calc_clock(unsigned long freq,
/* try all 8 shift values.*/
for (shift = 0; shift < 8; shift++) {
/* Calculate difference to requested clock */
- diff = sm501fb_round_div(mclk, divider << shift) - freq;
+ diff = DIV_ROUND_CLOSEST(mclk, divider << shift) - freq;
if (diff < 0)
diff = -diff;
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index e07947e56b2a..2dd8d49cb30b 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -298,6 +298,11 @@ static struct mfd_cell stmpe_gpio_cell = {
.num_resources = ARRAY_SIZE(stmpe_gpio_resources),
};
+static struct mfd_cell stmpe_gpio_cell_noirq = {
+ .name = "stmpe-gpio",
+ /* gpio cell resources consist of an irq only so no resources here */
+};
+
/*
* Keypad (1601, 2401, 2403)
*/
@@ -346,6 +351,13 @@ static struct stmpe_variant_block stmpe801_blocks[] = {
},
};
+static struct stmpe_variant_block stmpe801_blocks_noirq[] = {
+ {
+ .cell = &stmpe_gpio_cell_noirq,
+ .block = STMPE_BLOCK_GPIO,
+ },
+};
+
static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
bool enable)
{
@@ -367,6 +379,17 @@ static struct stmpe_variant_info stmpe801 = {
.enable = stmpe801_enable,
};
+static struct stmpe_variant_info stmpe801_noirq = {
+ .name = "stmpe801",
+ .id_val = STMPE801_ID,
+ .id_mask = 0xffff,
+ .num_gpios = 8,
+ .regs = stmpe801_regs,
+ .blocks = stmpe801_blocks_noirq,
+ .num_blocks = ARRAY_SIZE(stmpe801_blocks_noirq),
+ .enable = stmpe801_enable,
+};
+
/*
* Touchscreen (STMPE811 or STMPE610)
*/
@@ -712,7 +735,7 @@ static struct stmpe_variant_info stmpe2403 = {
.enable_autosleep = stmpe1601_autosleep, /* same as stmpe1601 */
};
-static struct stmpe_variant_info *stmpe_variant_info[] = {
+static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
[STMPE610] = &stmpe610,
[STMPE801] = &stmpe801,
[STMPE811] = &stmpe811,
@@ -721,6 +744,16 @@ static struct stmpe_variant_info *stmpe_variant_info[] = {
[STMPE2403] = &stmpe2403,
};
+/*
+ * These devices can be connected in a 'no-irq' configuration - the irq pin
+ * is not used and the device cannot interrupt the CPU. Here we only list
+ * devices which support this configuration - the driver will fail probing
+ * for any devices not listed here which are configured in this way.
+ */
+static struct stmpe_variant_info *stmpe_noirq_variant_info[STMPE_NBR_PARTS] = {
+ [STMPE801] = &stmpe801_noirq,
+};
+
static irqreturn_t stmpe_irq(int irq, void *data)
{
struct stmpe *stmpe = data;
@@ -864,7 +897,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
unsigned int irq_trigger = stmpe->pdata->irq_trigger;
int autosleep_timeout = stmpe->pdata->autosleep_timeout;
struct stmpe_variant_info *variant = stmpe->variant;
- u8 icr;
+ u8 icr = 0;
unsigned int id;
u8 data[2];
int ret;
@@ -887,31 +920,33 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
if (ret)
return ret;
- if (id == STMPE801_ID)
- icr = STMPE801_REG_SYS_CTRL_INT_EN;
- else
- icr = STMPE_ICR_LSB_GIM;
-
- /* STMPE801 doesn't support Edge interrupts */
- if (id != STMPE801_ID) {
- if (irq_trigger == IRQF_TRIGGER_FALLING ||
- irq_trigger == IRQF_TRIGGER_RISING)
- icr |= STMPE_ICR_LSB_EDGE;
- }
-
- if (irq_trigger == IRQF_TRIGGER_RISING ||
- irq_trigger == IRQF_TRIGGER_HIGH) {
+ if (stmpe->irq >= 0) {
if (id == STMPE801_ID)
- icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+ icr = STMPE801_REG_SYS_CTRL_INT_EN;
else
- icr |= STMPE_ICR_LSB_HIGH;
- }
+ icr = STMPE_ICR_LSB_GIM;
- if (stmpe->pdata->irq_invert_polarity) {
- if (id == STMPE801_ID)
- icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
- else
- icr ^= STMPE_ICR_LSB_HIGH;
+ /* STMPE801 doesn't support Edge interrupts */
+ if (id != STMPE801_ID) {
+ if (irq_trigger == IRQF_TRIGGER_FALLING ||
+ irq_trigger == IRQF_TRIGGER_RISING)
+ icr |= STMPE_ICR_LSB_EDGE;
+ }
+
+ if (irq_trigger == IRQF_TRIGGER_RISING ||
+ irq_trigger == IRQF_TRIGGER_HIGH) {
+ if (id == STMPE801_ID)
+ icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+ else
+ icr |= STMPE_ICR_LSB_HIGH;
+ }
+
+ if (stmpe->pdata->irq_invert_polarity) {
+ if (id == STMPE801_ID)
+ icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+ else
+ icr ^= STMPE_ICR_LSB_HIGH;
+ }
}
if (stmpe->pdata->autosleep) {
@@ -1001,19 +1036,38 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
stmpe->irq = ci->irq;
}
+ if (stmpe->irq < 0) {
+ /* use alternate variant info for no-irq mode, if supported */
+ dev_info(stmpe->dev,
+ "%s configured in no-irq mode by platform data\n",
+ stmpe->variant->name);
+ if (!stmpe_noirq_variant_info[stmpe->partnum]) {
+ dev_err(stmpe->dev,
+ "%s does not support no-irq mode!\n",
+ stmpe->variant->name);
+ ret = -ENODEV;
+ goto free_gpio;
+ }
+ stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
+ }
+
ret = stmpe_chip_init(stmpe);
if (ret)
goto free_gpio;
- ret = stmpe_irq_init(stmpe);
- if (ret)
- goto free_gpio;
+ if (stmpe->irq >= 0) {
+ ret = stmpe_irq_init(stmpe);
+ if (ret)
+ goto free_gpio;
- ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
- pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
- if (ret) {
- dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
- goto out_removeirq;
+ ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+ pdata->irq_trigger | IRQF_ONESHOT,
+ "stmpe", stmpe);
+ if (ret) {
+ dev_err(stmpe->dev, "failed to request IRQ: %d\n",
+ ret);
+ goto out_removeirq;
+ }
}
ret = stmpe_devices_init(stmpe);
@@ -1026,9 +1080,11 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
out_removedevs:
mfd_remove_devices(stmpe->dev);
- free_irq(stmpe->irq, stmpe);
+ if (stmpe->irq >= 0)
+ free_irq(stmpe->irq, stmpe);
out_removeirq:
- stmpe_irq_remove(stmpe);
+ if (stmpe->irq >= 0)
+ stmpe_irq_remove(stmpe);
free_gpio:
if (pdata->irq_over_gpio)
gpio_free(pdata->irq_gpio);
@@ -1041,8 +1097,10 @@ int stmpe_remove(struct stmpe *stmpe)
{
mfd_remove_devices(stmpe->dev);
- free_irq(stmpe->irq, stmpe);
- stmpe_irq_remove(stmpe);
+ if (stmpe->irq >= 0) {
+ free_irq(stmpe->irq, stmpe);
+ stmpe_irq_remove(stmpe);
+ }
if (stmpe->pdata->irq_over_gpio)
gpio_free(stmpe->pdata->irq_gpio);
@@ -1057,7 +1115,7 @@ static int stmpe_suspend(struct device *dev)
{
struct stmpe *stmpe = dev_get_drvdata(dev);
- if (device_may_wakeup(dev))
+ if (stmpe->irq >= 0 && device_may_wakeup(dev))
enable_irq_wake(stmpe->irq);
return 0;
@@ -1067,7 +1125,7 @@ static int stmpe_resume(struct device *dev)
{
struct stmpe *stmpe = dev_get_drvdata(dev);
- if (device_may_wakeup(dev))
+ if (stmpe->irq >= 0 && device_may_wakeup(dev))
disable_irq_wake(stmpe->irq);
return 0;
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
new file mode 100644
index 000000000000..a66d4df51293
--- /dev/null
+++ b/drivers/mfd/tps65090.c
@@ -0,0 +1,387 @@
+/*
+ * Core driver for TI TPS65090 PMIC family
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65090.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#define NUM_INT_REG 2
+#define TOTAL_NUM_REG 0x18
+
+/* interrupt status registers */
+#define TPS65090_INT_STS 0x0
+#define TPS65090_INT_STS2 0x1
+
+/* interrupt mask registers */
+#define TPS65090_INT_MSK 0x2
+#define TPS65090_INT_MSK2 0x3
+
+struct tps65090_irq_data {
+ u8 mask_reg;
+ u8 mask_pos;
+};
+
+#define TPS65090_IRQ(_reg, _mask_pos) \
+ { \
+ .mask_reg = (_reg), \
+ .mask_pos = (_mask_pos), \
+ }
+
+static const struct tps65090_irq_data tps65090_irqs[] = {
+ [0] = TPS65090_IRQ(0, 0),
+ [1] = TPS65090_IRQ(0, 1),
+ [2] = TPS65090_IRQ(0, 2),
+ [3] = TPS65090_IRQ(0, 3),
+ [4] = TPS65090_IRQ(0, 4),
+ [5] = TPS65090_IRQ(0, 5),
+ [6] = TPS65090_IRQ(0, 6),
+ [7] = TPS65090_IRQ(0, 7),
+ [8] = TPS65090_IRQ(1, 0),
+ [9] = TPS65090_IRQ(1, 1),
+ [10] = TPS65090_IRQ(1, 2),
+ [11] = TPS65090_IRQ(1, 3),
+ [12] = TPS65090_IRQ(1, 4),
+ [13] = TPS65090_IRQ(1, 5),
+ [14] = TPS65090_IRQ(1, 6),
+ [15] = TPS65090_IRQ(1, 7),
+};
+
+static struct mfd_cell tps65090s[] = {
+ {
+ .name = "tps65910-pmic",
+ },
+ {
+ .name = "tps65910-regulator",
+ },
+};
+
+struct tps65090 {
+ struct mutex lock;
+ struct device *dev;
+ struct i2c_client *client;
+ struct regmap *rmap;
+ struct irq_chip irq_chip;
+ struct mutex irq_lock;
+ int irq_base;
+ unsigned int id;
+};
+
+int tps65090_write(struct device *dev, int reg, uint8_t val)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+ return regmap_write(tps->rmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65090_write);
+
+int tps65090_read(struct device *dev, int reg, uint8_t *val)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+ unsigned int temp_val;
+ int ret;
+ ret = regmap_read(tps->rmap, reg, &temp_val);
+ if (!ret)
+ *val = temp_val;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tps65090_read);
+
+int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+ return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_set_bits);
+
+int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+ return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_clr_bits);
+
+static void tps65090_irq_lock(struct irq_data *data)
+{
+ struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&tps65090->irq_lock);
+}
+
+static void tps65090_irq_mask(struct irq_data *irq_data)
+{
+ struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->hwirq;
+ const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+ tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+ data->mask_pos);
+}
+
+static void tps65090_irq_unmask(struct irq_data *irq_data)
+{
+ struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - tps65090->irq_base;
+ const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+ tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+ data->mask_pos);
+}
+
+static void tps65090_irq_sync_unlock(struct irq_data *data)
+{
+ struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+ mutex_unlock(&tps65090->irq_lock);
+}
+
+static irqreturn_t tps65090_irq(int irq, void *data)
+{
+ struct tps65090 *tps65090 = data;
+ int ret = 0;
+ u8 status, mask;
+ unsigned long int acks = 0;
+ int i;
+
+ for (i = 0; i < NUM_INT_REG; i++) {
+ ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask);
+ if (ret < 0) {
+ dev_err(tps65090->dev,
+ "failed to read mask reg [addr:%d]\n",
+ TPS65090_INT_MSK + i);
+ return IRQ_NONE;
+ }
+ ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i,
+ &status);
+ if (ret < 0) {
+ dev_err(tps65090->dev,
+ "failed to read status reg [addr:%d]\n",
+ TPS65090_INT_STS + i);
+ return IRQ_NONE;
+ }
+ if (status) {
+ /* Ack only those interrupts which are not masked */
+ status &= (~mask);
+ ret = tps65090_write(tps65090->dev,
+ TPS65090_INT_STS + i, status);
+ if (ret < 0) {
+ dev_err(tps65090->dev,
+ "failed to write interrupt status\n");
+ return IRQ_NONE;
+ }
+ acks |= (status << (i * 8));
+ }
+ }
+
+ for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs))
+ handle_nested_irq(tps65090->irq_base + i);
+ return acks ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
+ int irq_base)
+{
+ int i, ret;
+
+ if (!irq_base) {
+ dev_err(tps65090->dev, "IRQ base not set\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&tps65090->irq_lock);
+
+ for (i = 0; i < NUM_INT_REG; i++)
+ tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF);
+
+ for (i = 0; i < NUM_INT_REG; i++)
+ tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff);
+
+ tps65090->irq_base = irq_base;
+ tps65090->irq_chip.name = "tps65090";
+ tps65090->irq_chip.irq_mask = tps65090_irq_mask;
+ tps65090->irq_chip.irq_unmask = tps65090_irq_unmask;
+ tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock;
+ tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock;
+
+ for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
+ int __irq = i + tps65090->irq_base;
+ irq_set_chip_data(__irq, tps65090);
+ irq_set_chip_and_handler(__irq, &tps65090->irq_chip,
+ handle_simple_irq);
+ irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(__irq, IRQF_VALID);
+#endif
+ }
+
+ ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT,
+ "tps65090", tps65090);
+ if (!ret) {
+ device_init_wakeup(tps65090->dev, 1);
+ enable_irq_wake(irq);
+ }
+
+ return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
+ return true;
+ else
+ return false;
+}
+
+static const struct regmap_config tps65090_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = TOTAL_NUM_REG,
+ .num_reg_defaults_raw = TOTAL_NUM_REG,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = is_volatile_reg,
+};
+
+static int __devinit tps65090_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tps65090_platform_data *pdata = client->dev.platform_data;
+ struct tps65090 *tps65090;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&client->dev, "tps65090 requires platform data\n");
+ return -EINVAL;
+ }
+
+ tps65090 = devm_kzalloc(&client->dev, sizeof(struct tps65090),
+ GFP_KERNEL);
+ if (tps65090 == NULL)
+ return -ENOMEM;
+
+ tps65090->client = client;
+ tps65090->dev = &client->dev;
+ i2c_set_clientdata(client, tps65090);
+
+ mutex_init(&tps65090->lock);
+
+ if (client->irq) {
+ ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base);
+ if (ret) {
+ dev_err(&client->dev, "IRQ init failed with err: %d\n",
+ ret);
+ goto err_exit;
+ }
+ }
+
+ tps65090->rmap = regmap_init_i2c(tps65090->client,
+ &tps65090_regmap_config);
+ if (IS_ERR(tps65090->rmap)) {
+ dev_err(&client->dev, "regmap_init failed with err: %ld\n",
+ PTR_ERR(tps65090->rmap));
+ goto err_irq_exit;
+ };
+
+ ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
+ ARRAY_SIZE(tps65090s), NULL, 0);
+ if (ret) {
+ dev_err(&client->dev, "add mfd devices failed with err: %d\n",
+ ret);
+ goto err_regmap_exit;
+ }
+
+ return 0;
+
+err_regmap_exit:
+ regmap_exit(tps65090->rmap);
+
+err_irq_exit:
+ if (client->irq)
+ free_irq(client->irq, tps65090);
+err_exit:
+ return ret;
+}
+
+static int __devexit tps65090_i2c_remove(struct i2c_client *client)
+{
+ struct tps65090 *tps65090 = i2c_get_clientdata(client);
+
+ mfd_remove_devices(tps65090->dev);
+ regmap_exit(tps65090->rmap);
+ if (client->irq)
+ free_irq(client->irq, tps65090);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tps65090_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+ if (client->irq)
+ disable_irq(client->irq);
+ return 0;
+}
+
+static int tps65090_i2c_resume(struct i2c_client *client)
+{
+ if (client->irq)
+ enable_irq(client->irq);
+ return 0;
+}
+#endif
+
+static const struct i2c_device_id tps65090_id_table[] = {
+ { "tps65090", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, tps65090_id_table);
+
+static struct i2c_driver tps65090_driver = {
+ .driver = {
+ .name = "tps65090",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps65090_i2c_probe,
+ .remove = __devexit_p(tps65090_i2c_remove),
+#ifdef CONFIG_PM
+ .suspend = tps65090_i2c_suspend,
+ .resume = tps65090_i2c_resume,
+#endif
+ .id_table = tps65090_id_table,
+};
+
+static int __init tps65090_init(void)
+{
+ return i2c_add_driver(&tps65090_driver);
+}
+subsys_initcall(tps65090_init);
+
+static void __exit tps65090_exit(void)
+{
+ i2c_del_driver(&tps65090_driver);
+}
+module_exit(tps65090_exit);
+
+MODULE_DESCRIPTION("TPS65090 core driver");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
new file mode 100644
index 000000000000..f7d854e4cc62
--- /dev/null
+++ b/drivers/mfd/tps65217.c
@@ -0,0 +1,242 @@
+/*
+ * tps65217.c
+ *
+ * TPS65217 chip family multi-function driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65217.h>
+
+/**
+ * tps65217_reg_read: Read a single tps65217 register.
+ *
+ * @tps: Device to read from.
+ * @reg: Register to read.
+ * @val: Contians the value
+ */
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+ unsigned int *val)
+{
+ return regmap_read(tps->regmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_read);
+
+/**
+ * tps65217_reg_write: Write a single tps65217 register.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+ unsigned int val, unsigned int level)
+{
+ int ret;
+ unsigned int xor_reg_val;
+
+ switch (level) {
+ case TPS65217_PROTECT_NONE:
+ return regmap_write(tps->regmap, reg, val);
+ case TPS65217_PROTECT_L1:
+ xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+ ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+ xor_reg_val);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(tps->regmap, reg, val);
+ case TPS65217_PROTECT_L2:
+ xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+ ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+ xor_reg_val);
+ if (ret < 0)
+ return ret;
+ ret = regmap_write(tps->regmap, reg, val);
+ if (ret < 0)
+ return ret;
+ ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+ xor_reg_val);
+ if (ret < 0)
+ return ret;
+ return regmap_write(tps->regmap, reg, val);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_write);
+
+/**
+ * tps65217_update_bits: Modify bits w.r.t mask, val and level.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to read-write to.
+ * @mask: Mask.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
+ unsigned int mask, unsigned int val, unsigned int level)
+{
+ int ret;
+ unsigned int data;
+
+ ret = tps65217_reg_read(tps, reg, &data);
+ if (ret) {
+ dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
+ return ret;
+ }
+
+ data &= ~mask;
+ data |= val & mask;
+
+ ret = tps65217_reg_write(tps, reg, data, level);
+ if (ret)
+ dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
+
+ return ret;
+}
+
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+ unsigned int mask, unsigned int val, unsigned int level)
+{
+ return tps65217_update_bits(tps, reg, mask, val, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_set_bits);
+
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+ unsigned int mask, unsigned int level)
+{
+ return tps65217_update_bits(tps, reg, mask, 0, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_clear_bits);
+
+static struct regmap_config tps65217_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int __devinit tps65217_probe(struct i2c_client *client,
+ const struct i2c_device_id *ids)
+{
+ struct tps65217 *tps;
+ struct tps65217_board *pdata = client->dev.platform_data;
+ int i, ret;
+ unsigned int version;
+
+ tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+ if (!tps)
+ return -ENOMEM;
+
+ tps->pdata = pdata;
+ tps->regmap = regmap_init_i2c(client, &tps65217_regmap_config);
+ if (IS_ERR(tps->regmap)) {
+ ret = PTR_ERR(tps->regmap);
+ dev_err(tps->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ i2c_set_clientdata(client, tps);
+ tps->dev = &client->dev;
+
+ ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
+ if (ret < 0) {
+ dev_err(tps->dev, "Failed to read revision"
+ " register: %d\n", ret);
+ goto err_regmap;
+ }
+
+ dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
+ (version & TPS65217_CHIPID_CHIP_MASK) >> 4,
+ version & TPS65217_CHIPID_REV_MASK);
+
+ for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("tps65217-pmic", i);
+ if (!pdev) {
+ dev_err(tps->dev, "Cannot create regulator %d\n", i);
+ continue;
+ }
+
+ pdev->dev.parent = tps->dev;
+ platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
+ sizeof(pdata->tps65217_init_data[i]));
+ tps->regulator_pdev[i] = pdev;
+
+ platform_device_add(pdev);
+ }
+
+ return 0;
+
+err_regmap:
+ regmap_exit(tps->regmap);
+
+ return ret;
+}
+
+static int __devexit tps65217_remove(struct i2c_client *client)
+{
+ struct tps65217 *tps = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
+ platform_device_unregister(tps->regulator_pdev[i]);
+
+ regmap_exit(tps->regmap);
+
+ return 0;
+}
+
+static const struct i2c_device_id tps65217_id_table[] = {
+ {"tps65217", 0xF0},
+ {/* end of list */}
+};
+MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
+
+static struct i2c_driver tps65217_driver = {
+ .driver = {
+ .name = "tps65217",
+ },
+ .id_table = tps65217_id_table,
+ .probe = tps65217_probe,
+ .remove = __devexit_p(tps65217_remove),
+};
+
+static int __init tps65217_init(void)
+{
+ return i2c_add_driver(&tps65217_driver);
+}
+subsys_initcall(tps65217_init);
+
+static void __exit tps65217_exit(void)
+{
+ i2c_del_driver(&tps65217_driver);
+}
+module_exit(tps65217_exit);
+
+MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
+MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
index 95c0d7978bec..c9ed5c00a621 100644
--- a/drivers/mfd/tps65910-irq.c
+++ b/drivers/mfd/tps65910-irq.c
@@ -145,12 +145,23 @@ static void tps65910_irq_disable(struct irq_data *data)
tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
}
+#ifdef CONFIG_PM_SLEEP
+static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
+{
+ struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+ return irq_set_irq_wake(tps65910->chip_irq, enable);
+}
+#else
+#define tps65910_irq_set_wake NULL
+#endif
+
static struct irq_chip tps65910_irq_chip = {
.name = "tps65910",
.irq_bus_lock = tps65910_irq_lock,
.irq_bus_sync_unlock = tps65910_irq_sync_unlock,
.irq_disable = tps65910_irq_disable,
.irq_enable = tps65910_irq_enable,
+ .irq_set_wake = tps65910_irq_set_wake,
};
int tps65910_irq_init(struct tps65910 *tps65910, int irq,
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 4392f6bca156..bf2b25ebf2ca 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -16,10 +16,12 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/mfd/core.h>
+#include <linux/regmap.h>
#include <linux/mfd/tps65910.h>
static struct mfd_cell tps65910s[] = {
@@ -38,99 +40,56 @@ static struct mfd_cell tps65910s[] = {
static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
int bytes, void *dest)
{
- struct i2c_client *i2c = tps65910->i2c_client;
- struct i2c_msg xfer[2];
- int ret;
-
- /* Write register */
- xfer[0].addr = i2c->addr;
- xfer[0].flags = 0;
- xfer[0].len = 1;
- xfer[0].buf = &reg;
-
- /* Read data */
- xfer[1].addr = i2c->addr;
- xfer[1].flags = I2C_M_RD;
- xfer[1].len = bytes;
- xfer[1].buf = dest;
-
- ret = i2c_transfer(i2c->adapter, xfer, 2);
- if (ret == 2)
- ret = 0;
- else if (ret >= 0)
- ret = -EIO;
-
- return ret;
+ return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
}
static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
- int bytes, void *src)
+ int bytes, void *src)
{
- struct i2c_client *i2c = tps65910->i2c_client;
- /* we add 1 byte for device register */
- u8 msg[TPS65910_MAX_REGISTER + 1];
- int ret;
-
- if (bytes > TPS65910_MAX_REGISTER)
- return -EINVAL;
-
- msg[0] = reg;
- memcpy(&msg[1], src, bytes);
-
- ret = i2c_master_send(i2c, msg, bytes + 1);
- if (ret < 0)
- return ret;
- if (ret != bytes + 1)
- return -EIO;
- return 0;
+ return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
}
int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
{
- u8 data;
- int err;
-
- mutex_lock(&tps65910->io_mutex);
- err = tps65910_i2c_read(tps65910, reg, 1, &data);
- if (err) {
- dev_err(tps65910->dev, "read from reg %x failed\n", reg);
- goto out;
- }
-
- data |= mask;
- err = tps65910_i2c_write(tps65910, reg, 1, &data);
- if (err)
- dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
- mutex_unlock(&tps65910->io_mutex);
- return err;
+ return regmap_update_bits(tps65910->regmap, reg, mask, mask);
}
EXPORT_SYMBOL_GPL(tps65910_set_bits);
int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
{
- u8 data;
- int err;
-
- mutex_lock(&tps65910->io_mutex);
- err = tps65910_i2c_read(tps65910, reg, 1, &data);
- if (err) {
- dev_err(tps65910->dev, "read from reg %x failed\n", reg);
- goto out;
- }
-
- data &= ~mask;
- err = tps65910_i2c_write(tps65910, reg, 1, &data);
- if (err)
- dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
- mutex_unlock(&tps65910->io_mutex);
- return err;
+ return regmap_update_bits(tps65910->regmap, reg, mask, 0);
}
EXPORT_SYMBOL_GPL(tps65910_clear_bits);
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ struct tps65910 *tps65910 = dev_get_drvdata(dev);
+
+ /*
+ * Caching all regulator registers.
+ * All regualator register address range is same for
+ * TPS65910 and TPS65911
+ */
+ if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
+ /* Check for non-existing register */
+ if (tps65910_chip_id(tps65910) == TPS65910)
+ if ((reg == TPS65911_VDDCTRL_OP) ||
+ (reg == TPS65911_VDDCTRL_SR))
+ return true;
+ return false;
+ }
+ return true;
+}
+
+static const struct regmap_config tps65910_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = is_volatile_reg,
+ .max_register = TPS65910_MAX_REGISTER,
+ .num_reg_defaults_raw = TPS65910_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static int tps65910_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -161,6 +120,13 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
tps65910->write = tps65910_i2c_write;
mutex_init(&tps65910->io_mutex);
+ tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config);
+ if (IS_ERR(tps65910->regmap)) {
+ ret = PTR_ERR(tps65910->regmap);
+ dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+ goto regmap_err;
+ }
+
ret = mfd_add_devices(tps65910->dev, -1,
tps65910s, ARRAY_SIZE(tps65910s),
NULL, 0);
@@ -178,6 +144,8 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
return ret;
err:
+ regmap_exit(tps65910->regmap);
+regmap_err:
kfree(tps65910);
kfree(init_data);
return ret;
@@ -189,6 +157,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
tps65910_irq_exit(tps65910);
mfd_remove_devices(tps65910->dev);
+ regmap_exit(tps65910->regmap);
kfree(tps65910);
return 0;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 806680d1bbb4..7c2267e71f8b 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -46,9 +46,7 @@
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <plat/cpu.h>
-#endif
+#include "twl-core.h"
/*
* The TWL4030 "Triton 2" is one of a family of a multi-function "Power
@@ -116,8 +114,8 @@
#define twl_has_watchdog() false
#endif
-#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\
- defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
+#if defined(CONFIG_MFD_TWL4030_AUDIO) || \
+ defined(CONFIG_MFD_TWL4030_AUDIO_MODULE)
#define twl_has_codec() true
#else
#define twl_has_codec() false
@@ -147,12 +145,10 @@
#define SUB_CHIP_ID1 1
#define SUB_CHIP_ID2 2
#define SUB_CHIP_ID3 3
+#define SUB_CHIP_ID_INVAL 0xff
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
-#define TWL4030_NR_IRQS 34 /* core:8, power:8, gpio: 18 */
-#define TWL6030_NR_IRQS 20
-
/* Base Address defns for twl4030_map[] */
/* subchip/slave 0 - USB ID */
@@ -314,7 +310,7 @@ static struct twl_mapping twl6030_map[] = {
* so they continue to match the order in this table.
*/
{ SUB_CHIP_ID1, TWL6030_BASEADD_USB },
- { SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
+ { SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
{ SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
{ SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
@@ -376,6 +372,11 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
return -EPERM;
}
sid = twl_map[mod_no].sid;
+ if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+ pr_err("%s: module %d is not part of the pmic\n",
+ DRIVER_NAME, mod_no);
+ return -EINVAL;
+ }
twl = &twl_modules[sid];
mutex_lock(&twl->xfer_lock);
@@ -433,6 +434,11 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
return -EPERM;
}
sid = twl_map[mod_no].sid;
+ if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+ pr_err("%s: module %d is not part of the pmic\n",
+ DRIVER_NAME, mod_no);
+ return -EINVAL;
+ }
twl = &twl_modules[sid];
mutex_lock(&twl->xfer_lock);
@@ -663,7 +669,8 @@ add_regulator(int num, struct regulator_init_data *pdata,
*/
static int
-add_children(struct twl4030_platform_data *pdata, unsigned long features)
+add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
+ unsigned long features)
{
struct device *child;
unsigned sub_chip_id;
@@ -671,7 +678,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_gpio() && pdata->gpio) {
child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
pdata->gpio, sizeof(*pdata->gpio),
- false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
+ false, irq_base + GPIO_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
@@ -679,7 +686,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_keypad() && pdata->keypad) {
child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
pdata->keypad, sizeof(*pdata->keypad),
- true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
+ true, irq_base + KEYPAD_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
@@ -687,7 +694,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_madc() && pdata->madc) {
child = add_child(2, "twl4030_madc",
pdata->madc, sizeof(*pdata->madc),
- true, pdata->irq_base + MADC_INTR_OFFSET, 0);
+ true, irq_base + MADC_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
@@ -703,7 +710,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
child = add_child(sub_chip_id, "twl_rtc",
NULL, 0,
- true, pdata->irq_base + RTC_INTR_OFFSET, 0);
+ true, irq_base + RTC_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
@@ -756,8 +763,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
pdata->usb, sizeof(*pdata->usb),
true,
/* irq0 = USB_PRES, irq1 = USB */
- pdata->irq_base + USB_PRES_INTR_OFFSET,
- pdata->irq_base + USB_INTR_OFFSET);
+ irq_base + USB_PRES_INTR_OFFSET,
+ irq_base + USB_INTR_OFFSET);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -805,8 +812,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
pdata->usb, sizeof(*pdata->usb),
true,
/* irq1 = VBUS_PRES, irq0 = USB ID */
- pdata->irq_base + USBOTG_INTR_OFFSET,
- pdata->irq_base + USB_PRES_INTR_OFFSET);
+ irq_base + USBOTG_INTR_OFFSET,
+ irq_base + USB_PRES_INTR_OFFSET);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -833,7 +840,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_pwrbutton() && twl_class_is_4030()) {
child = add_child(1, "twl4030_pwrbutton",
- NULL, 0, true, pdata->irq_base + 8 + 0, 0);
+ NULL, 0, true, irq_base + 8 + 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
@@ -847,15 +854,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
- 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",
- pdata->audio, sizeof(*pdata->audio),
- false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
/* twl4030 regulators */
if (twl_has_regulator() && twl_class_is_4030()) {
child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
@@ -1092,8 +1090,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
child = add_child(3, "twl4030_bci",
pdata->bci, sizeof(*pdata->bci), false,
/* irq0 = CHG_PRES, irq1 = BCI */
- pdata->irq_base + BCI_PRES_INTR_OFFSET,
- pdata->irq_base + BCI_INTR_OFFSET);
+ irq_base + BCI_PRES_INTR_OFFSET,
+ irq_base + BCI_INTR_OFFSET);
if (IS_ERR(child))
return PTR_ERR(child);
}
@@ -1193,26 +1191,24 @@ static void clocks_init(struct device *dev,
/*----------------------------------------------------------------------*/
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl4030_exit_irq(void);
-int twl4030_init_chip_irq(const char *chip);
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl6030_exit_irq(void);
static int twl_remove(struct i2c_client *client)
{
- unsigned i;
+ unsigned i, num_slaves;
int status;
- if (twl_class_is_4030())
+ if (twl_class_is_4030()) {
status = twl4030_exit_irq();
- else
+ num_slaves = TWL_NUM_SLAVES;
+ } else {
status = twl6030_exit_irq();
+ num_slaves = TWL_NUM_SLAVES - 1;
+ }
if (status < 0)
return status;
- for (i = 0; i < TWL_NUM_SLAVES; i++) {
+ for (i = 0; i < num_slaves; i++) {
struct twl_client *twl = &twl_modules[i];
if (twl->client && twl->client != client)
@@ -1223,20 +1219,15 @@ static int twl_remove(struct i2c_client *client)
return 0;
}
-/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
+/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
static int __devinit
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- int status;
- unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
struct device_node *node = client->dev.of_node;
- u8 temp;
- int ret = 0;
- int nr_irqs = TWL4030_NR_IRQS;
-
- if ((id->driver_data) & TWL6030_CLASS)
- nr_irqs = TWL6030_NR_IRQS;
+ int irq_base = 0;
+ int status;
+ unsigned i, num_slaves;
if (node && !pdata) {
/*
@@ -1255,17 +1246,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -EINVAL;
}
- status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
- if (IS_ERR_VALUE(status)) {
- dev_err(&client->dev, "Fail to allocate IRQ descs\n");
- return status;
- }
-
- pdata->irq_base = status;
- pdata->irq_end = pdata->irq_base + nr_irqs;
- irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
- &irq_domain_simple_ops, NULL);
-
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
return -EIO;
@@ -1276,13 +1256,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -EBUSY;
}
- for (i = 0; i < TWL_NUM_SLAVES; i++) {
- struct twl_client *twl = &twl_modules[i];
+ if ((id->driver_data) & TWL6030_CLASS) {
+ twl_id = TWL6030_CLASS_ID;
+ twl_map = &twl6030_map[0];
+ num_slaves = TWL_NUM_SLAVES - 1;
+ } else {
+ twl_id = TWL4030_CLASS_ID;
+ twl_map = &twl4030_map[0];
+ num_slaves = TWL_NUM_SLAVES;
+ }
+
+ for (i = 0; i < num_slaves; i++) {
+ struct twl_client *twl = &twl_modules[i];
twl->address = client->addr + i;
- if (i == 0)
+ if (i == 0) {
twl->client = client;
- else {
+ } else {
twl->client = i2c_new_dummy(client->adapter,
twl->address);
if (!twl->client) {
@@ -1294,22 +1284,16 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
mutex_init(&twl->xfer_lock);
}
+
inuse = true;
- if ((id->driver_data) & TWL6030_CLASS) {
- twl_id = TWL6030_CLASS_ID;
- twl_map = &twl6030_map[0];
- } else {
- twl_id = TWL4030_CLASS_ID;
- twl_map = &twl4030_map[0];
- }
/* setup clock framework */
clocks_init(&client->dev, pdata->clock);
/* read TWL IDCODE Register */
if (twl_id == TWL4030_CLASS_ID) {
- ret = twl_read_idcode_register();
- WARN(ret < 0, "Error: reading twl_idcode register value\n");
+ status = twl_read_idcode_register();
+ WARN(status < 0, "Error: reading twl_idcode register value\n");
}
/* load power event scripts */
@@ -1317,31 +1301,31 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl4030_power_init(pdata->power);
/* Maybe init the T2 Interrupt subsystem */
- if (client->irq
- && pdata->irq_base
- && pdata->irq_end > pdata->irq_base) {
+ if (client->irq) {
if (twl_class_is_4030()) {
twl4030_init_chip_irq(id->name);
- status = twl4030_init_irq(client->irq, pdata->irq_base,
- pdata->irq_end);
+ irq_base = twl4030_init_irq(&client->dev, client->irq);
} else {
- status = twl6030_init_irq(client->irq, pdata->irq_base,
- pdata->irq_end);
+ irq_base = twl6030_init_irq(&client->dev, client->irq);
}
- if (status < 0)
+ if (irq_base < 0) {
+ status = irq_base;
goto fail;
+ }
}
- /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
+ /*
+ * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
* Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
* SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
*/
-
if (twl_class_is_4030()) {
+ u8 temp;
+
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
- I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+ I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
@@ -1349,11 +1333,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (node)
status = of_platform_populate(node, NULL, NULL, &client->dev);
if (status)
- status = add_children(pdata, id->driver_data);
+ status = add_children(pdata, irq_base, id->driver_data);
fail:
if (status < 0)
twl_remove(client);
+
return status;
}
diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h
index 8c50a556e986..6ff99dce714f 100644
--- a/drivers/mfd/twl-core.h
+++ b/drivers/mfd/twl-core.h
@@ -1,9 +1,9 @@
#ifndef __TWL_CORE_H__
#define __TWL_CORE_H__
-extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl6030_init_irq(struct device *dev, int irq_num);
extern int twl6030_exit_irq(void);
-extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl4030_init_irq(struct device *dev, int irq_num);
extern int twl4030_exit_irq(void);
extern int twl4030_init_chip_irq(const char *chip);
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index b69bb517b102..5d656e814358 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -28,10 +28,12 @@
*/
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
-
+#include <linux/of.h>
+#include <linux/irqdomain.h>
#include <linux/i2c/twl.h>
#include "twl-core.h"
@@ -53,13 +55,14 @@
* base + 8 .. base + 15 SIH for PWR_INT
* base + 16 .. base + 33 SIH for GPIO
*/
+#define TWL4030_CORE_NR_IRQS 8
+#define TWL4030_PWR_NR_IRQS 8
/* PIH register offsets */
#define REG_PIH_ISR_P1 0x01
#define REG_PIH_ISR_P2 0x02
#define REG_PIH_SIR 0x03 /* for testing */
-
/* Linux could (eventually) use either IRQ line */
static int irq_line;
@@ -111,7 +114,8 @@ static int nr_sih_modules;
#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT
-/* Order in this table matches order in PIH_ISR. That is,
+/*
+ * Order in this table matches order in PIH_ISR. That is,
* BIT(n) in PIH_ISR is sih_modules[n].
*/
/* sih_modules_twl4030 is used both in twl4030 and twl5030 */
@@ -288,7 +292,6 @@ static unsigned twl4030_irq_base;
*/
static irqreturn_t handle_twl4030_pih(int irq, void *devid)
{
- int module_irq;
irqreturn_t ret;
u8 pih_isr;
@@ -299,16 +302,18 @@ static irqreturn_t handle_twl4030_pih(int irq, void *devid)
return IRQ_NONE;
}
- /* these handlers deal with the relevant SIH irq status */
- for (module_irq = twl4030_irq_base;
- pih_isr;
- pih_isr >>= 1, module_irq++) {
- if (pih_isr & 0x1)
- handle_nested_irq(module_irq);
+ while (pih_isr) {
+ unsigned long pending = __ffs(pih_isr);
+ unsigned int irq;
+
+ pih_isr &= ~BIT(pending);
+ irq = pending + twl4030_irq_base;
+ handle_nested_irq(irq);
}
return IRQ_HANDLED;
}
+
/*----------------------------------------------------------------------*/
/*
@@ -337,7 +342,6 @@ static int twl4030_init_sih_modules(unsigned line)
memset(buf, 0xff, sizeof buf);
sih = sih_modules;
for (i = 0; i < nr_sih_modules; i++, sih++) {
-
/* skip USB -- it's funky */
if (!sih->bytes_ixr)
continue;
@@ -352,7 +356,8 @@ static int twl4030_init_sih_modules(unsigned line)
pr_err("twl4030: err %d initializing %s %s\n",
status, sih->name, "IMR");
- /* Maybe disable "exclusive" mode; buffer second pending irq;
+ /*
+ * Maybe disable "exclusive" mode; buffer second pending irq;
* set Clear-On-Read (COR) bit.
*
* NOTE that sometimes COR polarity is documented as being
@@ -382,7 +387,8 @@ static int twl4030_init_sih_modules(unsigned line)
if (sih->irq_lines <= line)
continue;
- /* Clear pending interrupt status. Either the read was
+ /*
+ * Clear pending interrupt status. Either the read was
* enough, or we need to write those bits. Repeat, in
* case an IRQ is pending (PENDDIS=0) ... that's not
* uncommon with PWR_INT.PWRON.
@@ -398,7 +404,8 @@ static int twl4030_init_sih_modules(unsigned line)
status = twl_i2c_write(sih->module, buf,
sih->mask[line].isr_offset,
sih->bytes_ixr);
- /* else COR=1 means read sufficed.
+ /*
+ * else COR=1 means read sufficed.
* (for most SIH modules...)
*/
}
@@ -410,7 +417,8 @@ static int twl4030_init_sih_modules(unsigned line)
static inline void activate_irq(int irq)
{
#ifdef CONFIG_ARM
- /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+ /*
+ * ARM requires an extra step to clear IRQ_NOREQUEST, which it
* sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
*/
set_irq_flags(irq, IRQF_VALID);
@@ -620,33 +628,24 @@ static irqreturn_t handle_twl4030_sih(int irq, void *data)
return IRQ_HANDLED;
}
-static unsigned twl4030_irq_next;
-
-/* returns the first IRQ used by this SIH bank,
- * or negative errno
- */
-int twl4030_sih_setup(int module)
+/* returns the first IRQ used by this SIH bank, or negative errno */
+int twl4030_sih_setup(struct device *dev, int module, int irq_base)
{
int sih_mod;
const struct sih *sih = NULL;
struct sih_agent *agent;
int i, irq;
int status = -EINVAL;
- unsigned irq_base = twl4030_irq_next;
/* only support modules with standard clear-on-read for now */
- for (sih_mod = 0, sih = sih_modules;
- sih_mod < nr_sih_modules;
+ for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;
sih_mod++, sih++) {
if (sih->module == module && sih->set_cor) {
- if (!WARN((irq_base + sih->bits) > NR_IRQS,
- "irq %d for %s too big\n",
- irq_base + sih->bits,
- sih->name))
- status = 0;
+ status = 0;
break;
}
}
+
if (status < 0)
return status;
@@ -654,8 +653,6 @@ int twl4030_sih_setup(int module)
if (!agent)
return -ENOMEM;
- status = 0;
-
agent->irq_base = irq_base;
agent->sih = sih;
agent->imr = ~0;
@@ -671,8 +668,6 @@ int twl4030_sih_setup(int module)
activate_irq(irq);
}
- twl4030_irq_next += i;
-
/* replace generic PIH handler (handle_simple_irq) */
irq = sih_mod + twl4030_irq_base;
irq_set_handler_data(irq, agent);
@@ -680,26 +675,43 @@ int twl4030_sih_setup(int module)
status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
agent->irq_name ?: sih->name, NULL);
- pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
- irq, irq_base, twl4030_irq_next - 1);
+ dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
+ irq, irq_base, irq_base + i - 1);
return status < 0 ? status : irq_base;
}
/* FIXME need a call to reverse twl4030_sih_setup() ... */
-
/*----------------------------------------------------------------------*/
/* FIXME pass in which interrupt line we'll use ... */
#define twl_irq_line 0
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl4030_init_irq(struct device *dev, int irq_num)
{
static struct irq_chip twl4030_irq_chip;
+ int status, i;
+ int irq_base, irq_end, nr_irqs;
+ struct device_node *node = dev->of_node;
- int status;
- int i;
+ /*
+ * TWL core and pwr interrupts must be contiguous because
+ * the hwirqs numbers are defined contiguously from 1 to 15.
+ * Create only one domain for both.
+ */
+ nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+ if (IS_ERR_VALUE(irq_base)) {
+ dev_err(dev, "Fail to allocate IRQ descs\n");
+ return irq_base;
+ }
+
+ irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+ &irq_domain_simple_ops, NULL);
+
+ irq_end = irq_base + TWL4030_CORE_NR_IRQS;
/*
* Mask and clear all TWL4030 interrupts since initially we do
@@ -711,7 +723,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
twl4030_irq_base = irq_base;
- /* install an irq handler for each of the SIH modules;
+ /*
+ * Install an irq handler for each of the SIH modules;
* clone dummy irq_chip since PIH can't *do* anything
*/
twl4030_irq_chip = dummy_irq_chip;
@@ -725,14 +738,14 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
irq_set_nested_thread(i, 1);
activate_irq(i);
}
- twl4030_irq_next = i;
- pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
- irq_num, irq_base, twl4030_irq_next - 1);
+
+ dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",
+ irq_num, irq_base, irq_end);
/* ... and the PWR_INT module ... */
- status = twl4030_sih_setup(TWL4030_MODULE_INT);
+ status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);
if (status < 0) {
- pr_err("twl4030: sih_setup PWR INT --> %d\n", status);
+ dev_err(dev, "sih_setup PWR INT --> %d\n", status);
goto fail;
}
@@ -741,11 +754,11 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
IRQF_ONESHOT,
"TWL4030-PIH", NULL);
if (status < 0) {
- pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
+ dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);
goto fail_rqirq;
}
- return status;
+ return irq_base;
fail_rqirq:
/* clean up twl4030_sih_setup */
fail:
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index c6b456ad7342..b76902f1e44a 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -39,6 +39,8 @@
#include <linux/i2c/twl.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
#include "twl-core.h"
@@ -51,8 +53,8 @@
*
* We set up IRQs starting at a platform-specified base. An interrupt map table,
* specifies mapping between interrupt number and the associated module.
- *
*/
+#define TWL6030_NR_IRQS 20
static int twl6030_interrupt_mapping[24] = {
PWR_INTR_OFFSET, /* Bit 0 PWRON */
@@ -185,8 +187,17 @@ static int twl6030_irq_thread(void *data)
}
local_irq_enable();
}
- ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
- REG_INT_STS_A, 3); /* clear INT_STS_A */
+
+ /*
+ * NOTE:
+ * Simulation confirms that documentation is wrong w.r.t the
+ * interrupt status clear operation. A single *byte* write to
+ * any one of STS_A to STS_C register results in all three
+ * STS registers being reset. Since it does not matter which
+ * value is written, all three registers are cleared on a
+ * single byte write, so we just use 0x0 to clear.
+ */
+ ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
if (ret)
pr_warning("twl6030: I2C error in clearing PIH ISR\n");
@@ -227,7 +238,7 @@ static inline void activate_irq(int irq)
#endif
}
-int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
+static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
{
if (on)
atomic_inc(&twl6030_wakeirqs);
@@ -237,11 +248,6 @@ int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
-/*----------------------------------------------------------------------*/
-
-static unsigned twl6030_irq_next;
-
-/*----------------------------------------------------------------------*/
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
{
int ret;
@@ -311,7 +317,8 @@ int twl6030_mmc_card_detect_config(void)
ret);
return ret;
}
- return 0;
+
+ return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
}
EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
@@ -340,29 +347,44 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
}
EXPORT_SYMBOL(twl6030_mmc_card_detect);
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl6030_init_irq(struct device *dev, int irq_num)
{
-
- int status = 0;
- int i;
+ struct device_node *node = dev->of_node;
+ int nr_irqs, irq_base, irq_end;
struct task_struct *task;
- int ret;
- u8 mask[4];
+ static struct irq_chip twl6030_irq_chip;
+ int status = 0;
+ int i;
+ u8 mask[4];
+
+ nr_irqs = TWL6030_NR_IRQS;
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+ if (IS_ERR_VALUE(irq_base)) {
+ dev_err(dev, "Fail to allocate IRQ descs\n");
+ return irq_base;
+ }
+
+ irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+ &irq_domain_simple_ops, NULL);
+
+ irq_end = irq_base + nr_irqs;
- static struct irq_chip twl6030_irq_chip;
mask[1] = 0xFF;
mask[2] = 0xFF;
mask[3] = 0xFF;
- ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
- REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
- ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
- REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
- ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
- REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
+
+ /* mask all int lines */
+ twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+ /* mask all int sts */
+ twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+ /* clear INT_STS_A,B,C */
+ twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
twl6030_irq_base = irq_base;
- /* install an irq handler for each of the modules;
+ /*
+ * install an irq handler for each of the modules;
* clone dummy irq_chip since PIH can't *do* anything
*/
twl6030_irq_chip = dummy_irq_chip;
@@ -377,30 +399,29 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
activate_irq(i);
}
- twl6030_irq_next = i;
- pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
- irq_num, irq_base, twl6030_irq_next - 1);
+ dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
+ irq_num, irq_base, irq_end);
/* install an irq handler to demultiplex the TWL6030 interrupt */
init_completion(&irq_event);
- status = request_irq(irq_num, handle_twl6030_pih, 0,
- "TWL6030-PIH", &irq_event);
+ status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
+ &irq_event);
if (status < 0) {
- pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
+ dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
goto fail_irq;
}
task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
if (IS_ERR(task)) {
- pr_err("twl6030: could not create irq %d thread!\n", irq_num);
+ dev_err(dev, "could not create irq %d thread!\n", irq_num);
status = PTR_ERR(task);
goto fail_kthread;
}
twl_irq = irq_num;
register_pm_notifier(&twl6030_irq_pm_notifier_block);
- return status;
+ return irq_base;
fail_kthread:
free_irq(irq_num, &irq_event);
@@ -408,6 +429,7 @@ fail_kthread:
fail_irq:
for (i = irq_base; i < irq_end; i++)
irq_set_chip_and_handler(i, NULL, NULL);
+
return status;
}
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 745c87945664..4bceee98f0a4 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -89,7 +89,7 @@ static const struct spi_device_id wm831x_spi_ids[] = {
{ "wm8326", WM8326 },
{ },
};
-MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
+MODULE_DEVICE_TABLE(spi, wm831x_spi_ids);
static struct spi_driver wm831x_spi_driver = {
.driver = {
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 237764ae5f9b..1189a17f0f25 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -271,8 +271,7 @@ static int wm8400_init(struct wm8400 *wm8400,
return -EIO;
}
if (i != reg_data[WM8400_RESET_ID].default_val) {
- dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
- reg);
+ dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", i);
return -ENODEV;
}
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 98733d408fee..9d7ca1e978fa 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -639,7 +639,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
}
pm_runtime_enable(wm8994->dev);
- pm_runtime_resume(wm8994->dev);
+ pm_runtime_idle(wm8994->dev);
return 0;
diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c
index 7605b6095453..bfd25af6ecb1 100644
--- a/drivers/mfd/wm8994-regmap.c
+++ b/drivers/mfd/wm8994-regmap.c
@@ -20,7 +20,6 @@
#include "wm8994.h"
static struct reg_default wm1811_defaults[] = {
- { 0x0000, 0x1811 }, /* R0 - Software Reset */
{ 0x0001, 0x0000 }, /* R1 - Power Management (1) */
{ 0x0002, 0x6000 }, /* R2 - Power Management (2) */
{ 0x0003, 0x0000 }, /* R3 - Power Management (3) */
@@ -61,7 +60,7 @@ static struct reg_default wm1811_defaults[] = {
{ 0x0036, 0x0000 }, /* R54 - Speaker Mixer */
{ 0x0037, 0x0000 }, /* R55 - Additional Control */
{ 0x0038, 0x0000 }, /* R56 - AntiPOP (1) */
- { 0x0039, 0x0180 }, /* R57 - AntiPOP (2) */
+ { 0x0039, 0x0000 }, /* R57 - AntiPOP (2) */
{ 0x003B, 0x000D }, /* R59 - LDO 1 */
{ 0x003C, 0x0003 }, /* R60 - LDO 2 */
{ 0x003D, 0x0039 }, /* R61 - MICBIAS1 */
@@ -69,16 +68,12 @@ static struct reg_default wm1811_defaults[] = {
{ 0x004C, 0x1F25 }, /* R76 - Charge Pump (1) */
{ 0x004D, 0xAB19 }, /* R77 - Charge Pump (2) */
{ 0x0051, 0x0004 }, /* R81 - Class W (1) */
- { 0x0054, 0x0000 }, /* R84 - DC Servo (1) */
{ 0x0055, 0x054A }, /* R85 - DC Servo (2) */
- { 0x0058, 0x0000 }, /* R88 - DC Servo Readback */
{ 0x0059, 0x0000 }, /* R89 - DC Servo (4) */
{ 0x0060, 0x0000 }, /* R96 - Analogue HP (1) */
{ 0x00C5, 0x0000 }, /* R197 - Class D Test (5) */
{ 0x00D0, 0x7600 }, /* R208 - Mic Detect 1 */
{ 0x00D1, 0x007F }, /* R209 - Mic Detect 2 */
- { 0x00D2, 0x0000 }, /* R210 - Mic Detect 3 */
- { 0x0100, 0x0100 }, /* R256 - Chip Revision */
{ 0x0101, 0x8004 }, /* R257 - Control Interface */
{ 0x0200, 0x0000 }, /* R512 - AIF1 Clocking (1) */
{ 0x0201, 0x0000 }, /* R513 - AIF1 Clocking (2) */
@@ -88,7 +83,6 @@ static struct reg_default wm1811_defaults[] = {
{ 0x0209, 0x0000 }, /* R521 - Clocking (2) */
{ 0x0210, 0x0083 }, /* R528 - AIF1 Rate */
{ 0x0211, 0x0083 }, /* R529 - AIF2 Rate */
- { 0x0212, 0x0000 }, /* R530 - Rate Status */
{ 0x0220, 0x0000 }, /* R544 - FLL1 Control (1) */
{ 0x0221, 0x0000 }, /* R545 - FLL1 Control (2) */
{ 0x0222, 0x0000 }, /* R546 - FLL1 Control (3) */
@@ -218,8 +212,6 @@ static struct reg_default wm1811_defaults[] = {
{ 0x070A, 0xA101 }, /* R1802 - GPIO 11 */
{ 0x0720, 0x0000 }, /* R1824 - Pull Control (1) */
{ 0x0721, 0x0156 }, /* R1825 - Pull Control (2) */
- { 0x0730, 0x0000 }, /* R1840 - Interrupt Status 1 */
- { 0x0731, 0x0000 }, /* R1841 - Interrupt Status 2 */
{ 0x0732, 0x0000 }, /* R1842 - Interrupt Raw Status 2 */
{ 0x0738, 0x07FF }, /* R1848 - Interrupt Status 1 Mask */
{ 0x0739, 0xDFEF }, /* R1849 - Interrupt Status 2 Mask */
@@ -228,7 +220,6 @@ static struct reg_default wm1811_defaults[] = {
};
static struct reg_default wm8994_defaults[] = {
- { 0x0000, 0x8994 }, /* R0 - Software Reset */
{ 0x0001, 0x0000 }, /* R1 - Power Management (1) */
{ 0x0002, 0x6000 }, /* R2 - Power Management (2) */
{ 0x0003, 0x0000 }, /* R3 - Power Management (3) */
@@ -275,12 +266,9 @@ static struct reg_default wm8994_defaults[] = {
{ 0x003C, 0x0003 }, /* R60 - LDO 2 */
{ 0x004C, 0x1F25 }, /* R76 - Charge Pump (1) */
{ 0x0051, 0x0004 }, /* R81 - Class W (1) */
- { 0x0054, 0x0000 }, /* R84 - DC Servo (1) */
{ 0x0055, 0x054A }, /* R85 - DC Servo (2) */
{ 0x0057, 0x0000 }, /* R87 - DC Servo (4) */
- { 0x0058, 0x0000 }, /* R88 - DC Servo Readback */
{ 0x0060, 0x0000 }, /* R96 - Analogue HP (1) */
- { 0x0100, 0x0003 }, /* R256 - Chip Revision */
{ 0x0101, 0x8004 }, /* R257 - Control Interface */
{ 0x0110, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */
{ 0x0111, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
@@ -292,7 +280,6 @@ static struct reg_default wm8994_defaults[] = {
{ 0x0209, 0x0000 }, /* R521 - Clocking (2) */
{ 0x0210, 0x0083 }, /* R528 - AIF1 Rate */
{ 0x0211, 0x0083 }, /* R529 - AIF2 Rate */
- { 0x0212, 0x0000 }, /* R530 - Rate Status */
{ 0x0220, 0x0000 }, /* R544 - FLL1 Control (1) */
{ 0x0221, 0x0000 }, /* R545 - FLL1 Control (2) */
{ 0x0222, 0x0000 }, /* R546 - FLL1 Control (3) */
@@ -445,9 +432,6 @@ static struct reg_default wm8994_defaults[] = {
{ 0x070A, 0xA101 }, /* R1802 - GPIO 11 */
{ 0x0720, 0x0000 }, /* R1824 - Pull Control (1) */
{ 0x0721, 0x0156 }, /* R1825 - Pull Control (2) */
- { 0x0730, 0x0000 }, /* R1840 - Interrupt Status 1 */
- { 0x0731, 0x0000 }, /* R1841 - Interrupt Status 2 */
- { 0x0732, 0x0000 }, /* R1842 - Interrupt Raw Status 2 */
{ 0x0738, 0x07FF }, /* R1848 - Interrupt Status 1 Mask */
{ 0x0739, 0xFFFF }, /* R1849 - Interrupt Status 2 Mask */
{ 0x0740, 0x0000 }, /* R1856 - Interrupt Control */
@@ -455,7 +439,6 @@ static struct reg_default wm8994_defaults[] = {
};
static struct reg_default wm8958_defaults[] = {
- { 0x0000, 0x8958 }, /* R0 - Software Reset */
{ 0x0001, 0x0000 }, /* R1 - Power Management (1) */
{ 0x0002, 0x6000 }, /* R2 - Power Management (2) */
{ 0x0003, 0x0000 }, /* R3 - Power Management (3) */
@@ -970,6 +953,7 @@ static bool wm8994_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8994_DC_SERVO_READBACK:
+ case WM8994_MICBIAS:
case WM8994_WRITE_SEQUENCER_CTRL_1:
case WM8994_WRITE_SEQUENCER_CTRL_2:
case WM8994_AIF1_ADC2_LEFT_VOLUME:
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h
index d95587cc794c..04d5170ac149 100644
--- a/drivers/misc/sgi-gru/gru_instructions.h
+++ b/drivers/misc/sgi-gru/gru_instructions.h
@@ -40,6 +40,7 @@ extern void gru_wait_abort_proc(void *cb);
*((volatile unsigned long *)(p)) = v; /* force st.rel */ \
} while (0)
#elif defined(CONFIG_X86_64)
+#include <asm/cacheflush.h>
#define __flush_cache(p) clflush(p)
#define gru_ordered_store_ulong(p, v) \
do { \
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index 851b2f25ce0e..c862cd4583cc 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -25,7 +25,6 @@
#endif
#if defined CONFIG_IA64
-#include <asm/system.h>
#include <asm/sn/arch.h> /* defines is_shub1() and is_shub2() */
#define is_shub() ia64_platform_is("sn2")
#endif
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index e5a3c7b6dedb..eed213a5c8cb 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -41,7 +41,6 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include "queue.h"
@@ -1080,6 +1079,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_blk_request *brq = &mqrq->brq;
struct request *req = mqrq->req;
struct mmc_blk_data *md = mq->data;
+ bool do_data_tag;
/*
* Reliable writes are used to implement Forced Unit Access and
@@ -1156,6 +1156,16 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
mmc_apply_rel_rw(brq, card, req);
/*
+ * Data tag is used only during writing meta data to speed
+ * up write and any subsequent read of this meta data
+ */
+ do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+ (req->cmd_flags & REQ_META) &&
+ (rq_data_dir(req) == WRITE) &&
+ ((brq->data.blocks * brq->data.blksz) >=
+ card->ext_csd.data_tag_unit_size);
+
+ /*
* Pre-defined multi-block transfers are preferable to
* open ended-ones (and necessary for reliable writes).
* However, it is not sufficient to just send CMD23,
@@ -1173,13 +1183,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
* We'll avoid using CMD23-bounded multiblock writes for
* these, while retaining features like reliable writes.
*/
-
- if ((md->flags & MMC_BLK_CMD23) &&
- mmc_op_multi(brq->cmd.opcode) &&
- (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+ if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
+ (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
+ do_data_tag)) {
brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
brq->sbc.arg = brq->data.blocks |
- (do_rel_wr ? (1 << 31) : 0);
+ (do_rel_wr ? (1 << 31) : 0) |
+ (do_data_tag ? (1 << 29) : 0);
brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
brq->mrq.sbc = &brq->sbc;
}
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
index 082202ae4a03..29de31e260dd 100644
--- a/drivers/mmc/core/cd-gpio.c
+++ b/drivers/mmc/core/cd-gpio.c
@@ -28,13 +28,17 @@ static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
- unsigned int irq, unsigned long flags)
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio)
{
size_t len = strlen(dev_name(host->parent)) + 4;
- struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
+ struct mmc_cd_gpio *cd;
+ int irq = gpio_to_irq(gpio);
int ret;
+ if (irq < 0)
+ return irq;
+
+ cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
if (!cd)
return -ENOMEM;
@@ -45,7 +49,8 @@ int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
goto egpioreq;
ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
- flags, cd->label, host);
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ cd->label, host);
if (ret < 0)
goto eirqreq;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 132378b89d76..14f262e9246d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -188,6 +188,12 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
struct scatterlist *sg;
#endif
+ if (mrq->sbc) {
+ pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
+ mmc_hostname(host), mrq->sbc->opcode,
+ mrq->sbc->arg, mrq->sbc->flags);
+ }
+
pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
@@ -243,16 +249,17 @@ static void mmc_wait_done(struct mmc_request *mrq)
complete(&mrq->completion);
}
-static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
if (mmc_card_removed(host->card)) {
mrq->cmd->error = -ENOMEDIUM;
complete(&mrq->completion);
- return;
+ return -ENOMEDIUM;
}
mmc_start_request(host, mrq);
+ return 0;
}
static void mmc_wait_for_req_done(struct mmc_host *host,
@@ -336,6 +343,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
struct mmc_async_req *areq, int *error)
{
int err = 0;
+ int start_err = 0;
struct mmc_async_req *data = host->areq;
/* Prepare a new request */
@@ -345,30 +353,23 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
err = host->areq->err_check(host->card, host->areq);
- if (err) {
- /* post process the completed failed request */
- mmc_post_req(host, host->areq->mrq, 0);
- if (areq)
- /*
- * Cancel the new prepared request, because
- * it can't run until the failed
- * request has been properly handled.
- */
- mmc_post_req(host, areq->mrq, -EINVAL);
-
- host->areq = NULL;
- goto out;
- }
}
- if (areq)
- __mmc_start_req(host, areq->mrq);
+ if (!err && areq)
+ start_err = __mmc_start_req(host, areq->mrq);
if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
- host->areq = areq;
- out:
+ /* Cancel a prepared request if it was not started. */
+ if ((err || start_err) && areq)
+ mmc_post_req(host, areq->mrq, -EINVAL);
+
+ if (err)
+ host->areq = NULL;
+ else
+ host->areq = areq;
+
if (error)
*error = err;
return data;
@@ -599,105 +600,6 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
EXPORT_SYMBOL(mmc_align_data_size);
/**
- * mmc_host_enable - enable a host.
- * @host: mmc host to enable
- *
- * Hosts that support power saving can use the 'enable' and 'disable'
- * methods to exit and enter power saving states. For more information
- * see comments for struct mmc_host_ops.
- */
-int mmc_host_enable(struct mmc_host *host)
-{
- if (!(host->caps & MMC_CAP_DISABLE))
- return 0;
-
- if (host->en_dis_recurs)
- return 0;
-
- if (host->nesting_cnt++)
- return 0;
-
- cancel_delayed_work_sync(&host->disable);
-
- if (host->enabled)
- return 0;
-
- if (host->ops->enable) {
- int err;
-
- host->en_dis_recurs = 1;
- mmc_host_clk_hold(host);
- err = host->ops->enable(host);
- mmc_host_clk_release(host);
- host->en_dis_recurs = 0;
-
- if (err) {
- pr_debug("%s: enable error %d\n",
- mmc_hostname(host), err);
- return err;
- }
- }
- host->enabled = 1;
- return 0;
-}
-EXPORT_SYMBOL(mmc_host_enable);
-
-static int mmc_host_do_disable(struct mmc_host *host, int lazy)
-{
- if (host->ops->disable) {
- int err;
-
- host->en_dis_recurs = 1;
- mmc_host_clk_hold(host);
- err = host->ops->disable(host, lazy);
- mmc_host_clk_release(host);
- host->en_dis_recurs = 0;
-
- if (err < 0) {
- pr_debug("%s: disable error %d\n",
- mmc_hostname(host), err);
- return err;
- }
- if (err > 0) {
- unsigned long delay = msecs_to_jiffies(err);
-
- mmc_schedule_delayed_work(&host->disable, delay);
- }
- }
- host->enabled = 0;
- return 0;
-}
-
-/**
- * mmc_host_disable - disable a host.
- * @host: mmc host to disable
- *
- * Hosts that support power saving can use the 'enable' and 'disable'
- * methods to exit and enter power saving states. For more information
- * see comments for struct mmc_host_ops.
- */
-int mmc_host_disable(struct mmc_host *host)
-{
- int err;
-
- if (!(host->caps & MMC_CAP_DISABLE))
- return 0;
-
- if (host->en_dis_recurs)
- return 0;
-
- if (--host->nesting_cnt)
- return 0;
-
- if (!host->enabled)
- return 0;
-
- err = mmc_host_do_disable(host, 0);
- return err;
-}
-EXPORT_SYMBOL(mmc_host_disable);
-
-/**
* __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
* @abort: whether or not the operation should be aborted
@@ -735,8 +637,8 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
- if (!stop)
- mmc_host_enable(host);
+ if (host->ops->enable && !stop && host->claim_cnt == 1)
+ host->ops->enable(host);
return stop;
}
@@ -761,21 +663,28 @@ int mmc_try_claim_host(struct mmc_host *host)
claimed_host = 1;
}
spin_unlock_irqrestore(&host->lock, flags);
+ if (host->ops->enable && claimed_host && host->claim_cnt == 1)
+ host->ops->enable(host);
return claimed_host;
}
EXPORT_SYMBOL(mmc_try_claim_host);
/**
- * mmc_do_release_host - release a claimed host
+ * mmc_release_host - release a host
* @host: mmc host to release
*
- * If you successfully claimed a host, this function will
- * release it again.
+ * Release a MMC host, allowing others to claim the host
+ * for their operations.
*/
-void mmc_do_release_host(struct mmc_host *host)
+void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
+ WARN_ON(!host->claimed);
+
+ if (host->ops->disable && host->claim_cnt == 1)
+ host->ops->disable(host);
+
spin_lock_irqsave(&host->lock, flags);
if (--host->claim_cnt) {
/* Release for nested claim */
@@ -787,67 +696,6 @@ void mmc_do_release_host(struct mmc_host *host)
wake_up(&host->wq);
}
}
-EXPORT_SYMBOL(mmc_do_release_host);
-
-void mmc_host_deeper_disable(struct work_struct *work)
-{
- struct mmc_host *host =
- container_of(work, struct mmc_host, disable.work);
-
- /* If the host is claimed then we do not want to disable it anymore */
- if (!mmc_try_claim_host(host))
- return;
- mmc_host_do_disable(host, 1);
- mmc_do_release_host(host);
-}
-
-/**
- * mmc_host_lazy_disable - lazily disable a host.
- * @host: mmc host to disable
- *
- * Hosts that support power saving can use the 'enable' and 'disable'
- * methods to exit and enter power saving states. For more information
- * see comments for struct mmc_host_ops.
- */
-int mmc_host_lazy_disable(struct mmc_host *host)
-{
- if (!(host->caps & MMC_CAP_DISABLE))
- return 0;
-
- if (host->en_dis_recurs)
- return 0;
-
- if (--host->nesting_cnt)
- return 0;
-
- if (!host->enabled)
- return 0;
-
- if (host->disable_delay) {
- mmc_schedule_delayed_work(&host->disable,
- msecs_to_jiffies(host->disable_delay));
- return 0;
- } else
- return mmc_host_do_disable(host, 1);
-}
-EXPORT_SYMBOL(mmc_host_lazy_disable);
-
-/**
- * mmc_release_host - release a host
- * @host: mmc host to release
- *
- * Release a MMC host, allowing others to claim the host
- * for their operations.
- */
-void mmc_release_host(struct mmc_host *host)
-{
- WARN_ON(!host->claimed);
-
- mmc_host_lazy_disable(host);
-
- mmc_do_release_host(host);
-}
-
EXPORT_SYMBOL(mmc_release_host);
/*
@@ -2115,18 +1963,36 @@ int _mmc_detect_card_removed(struct mmc_host *host)
int mmc_detect_card_removed(struct mmc_host *host)
{
struct mmc_card *card = host->card;
+ int ret;
WARN_ON(!host->claimed);
+
+ if (!card)
+ return 1;
+
+ ret = mmc_card_removed(card);
/*
* The card will be considered unchanged unless we have been asked to
* detect a change or host requires polling to provide card detection.
*/
- if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
- return mmc_card_removed(card);
+ if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
+ !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+ return ret;
host->detect_change = 0;
+ if (!ret) {
+ ret = _mmc_detect_card_removed(host);
+ if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+ /*
+ * Schedule a detect work as soon as possible to let a
+ * rescan handle the card removal.
+ */
+ cancel_delayed_work(&host->detect);
+ mmc_detect_change(host, 0);
+ }
+ }
- return _mmc_detect_card_removed(host);
+ return ret;
}
EXPORT_SYMBOL(mmc_detect_card_removed);
@@ -2203,8 +2069,6 @@ void mmc_stop_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
#endif
- if (host->caps & MMC_CAP_DISABLE)
- cancel_delayed_work(&host->disable);
cancel_delayed_work_sync(&host->detect);
mmc_flush_scheduled_work();
@@ -2399,13 +2263,11 @@ int mmc_suspend_host(struct mmc_host *host)
{
int err = 0;
- if (host->caps & MMC_CAP_DISABLE)
- cancel_delayed_work(&host->disable);
cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
if (mmc_try_claim_host(host)) {
err = mmc_cache_ctrl(host, 0);
- mmc_do_release_host(host);
+ mmc_release_host(host);
} else {
err = -EBUSY;
}
@@ -2426,7 +2288,7 @@ int mmc_suspend_host(struct mmc_host *host)
if (host->bus_ops->suspend) {
err = host->bus_ops->suspend(host);
}
- mmc_do_release_host(host);
+ mmc_release_host(host);
if (err == -ENOSYS || !host->bus_ops->resume) {
/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c3704e293a7b..91c84c7a1829 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -330,7 +330,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
- INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
#ifdef CONFIG_PM
host->pm_notify.notifier_call = mmc_pm_notify;
#endif
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 08a7852ade44..f2ab9e578126 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -14,7 +14,6 @@
int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
-void mmc_host_deeper_disable(struct work_struct *work);
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 2b9ed1401dc4..02914d609a91 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -519,6 +519,20 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
+ if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1)
+ card->ext_csd.data_sector_size = 4096;
+ else
+ card->ext_csd.data_sector_size = 512;
+
+ if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) &&
+ (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) {
+ card->ext_csd.data_tag_unit_size =
+ ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) *
+ (card->ext_csd.data_sector_size);
+ } else {
+ card->ext_csd.data_tag_unit_size = 0;
+ }
}
out:
@@ -938,7 +952,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
* bit. This bit will be lost every time after a reset or power off.
*/
- if (card->ext_csd.enhanced_area_en) {
+ if (card->ext_csd.enhanced_area_en ||
+ (card->ext_csd.rev >= 3 && (host->caps2 & MMC_CAP2_HC_ERASE_SZ))) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_ERASE_GROUP_DEF, 1,
card->ext_csd.generic_cmd6_time);
@@ -1033,22 +1048,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
- * Enable HPI feature (if supported)
- */
- if (card->ext_csd.hpi) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HPI_MGMT, 1, 0);
- if (err && err != -EBADMSG)
- goto free_card;
- if (err) {
- pr_warning("%s: Enabling HPI failed\n",
- mmc_hostname(card->host));
- err = 0;
- } else
- card->ext_csd.hpi_en = 1;
- }
-
- /*
* Compute bus speed.
*/
max_dtr = (unsigned int)-1;
@@ -1097,9 +1096,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* 4. execute tuning for HS200
*/
if ((host->caps2 & MMC_CAP2_HS200) &&
- card->host->ops->execute_tuning)
+ card->host->ops->execute_tuning) {
+ mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK_HS200);
+ mmc_host_clk_release(card->host);
+ }
if (err) {
pr_warning("%s: tuning execution failed\n",
mmc_hostname(card->host));
@@ -1219,6 +1221,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
+ * Enable HPI feature (if supported)
+ */
+ if (card->ext_csd.hpi) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HPI_MGMT, 1,
+ card->ext_csd.generic_cmd6_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warning("%s: Enabling HPI failed\n",
+ mmc_hostname(card->host));
+ err = 0;
+ } else
+ card->ext_csd.hpi_en = 1;
+ }
+
+ /*
* If cache size is higher than 0, this indicates
* the existence of cache and it can be turned on.
*/
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 4d41fa984c93..69370f494e05 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -553,18 +553,22 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
{
struct mmc_command cmd = {0};
unsigned int opcode;
- unsigned int flags;
int err;
+ if (!card->ext_csd.hpi) {
+ pr_warning("%s: Card didn't support HPI command\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
opcode = card->ext_csd.hpi_cmd;
if (opcode == MMC_STOP_TRANSMISSION)
- flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
else if (opcode == MMC_SEND_STATUS)
- flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
cmd.opcode = opcode;
cmd.arg = card->rca << 16 | 1;
- cmd.flags = flags;
cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ecbee9bf87b2..2bc06e7344db 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -533,6 +533,31 @@ config MMC_DW_IDMAC
Designware Mobile Storage IP block. This disables the external DMA
interface.
+config MMC_DW_PLTFM
+ tristate "Synopsys Designware MCI Support as platform device"
+ depends on MMC_DW
+ default y
+ help
+ This selects the common helper functions support for Host Controller
+ Interface based platform driver. Please select this option if the IP
+ is present as a platform device. This is the common interface for the
+ Synopsys Designware IP.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say Y.
+
+config MMC_DW_PCI
+ tristate "Synopsys Designware MCI support on PCI bus"
+ depends on MMC_DW && PCI
+ help
+ This selects the PCI bus for the Synopsys Designware Mobile Storage IP.
+ Select this option if the IP is present on PCI platform.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
config MMC_SH_MMCIF
tristate "SuperH Internal MMCIF support"
depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 745f8fce2519..3e7e26d08073 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -39,6 +39,8 @@ obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
+obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
+obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index e4449a54ae8f..9819dc09ce08 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -24,6 +24,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/types.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio.h>
@@ -173,6 +174,7 @@ struct atmel_mci {
struct atmel_mci_dma dma;
struct dma_chan *data_chan;
+ struct dma_slave_config dma_conf;
u32 cmd_status;
u32 data_status;
@@ -863,16 +865,17 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
if (data->flags & MMC_DATA_READ) {
direction = DMA_FROM_DEVICE;
- slave_dirn = DMA_DEV_TO_MEM;
+ host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
} else {
direction = DMA_TO_DEVICE;
- slave_dirn = DMA_MEM_TO_DEV;
+ host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
}
sglen = dma_map_sg(chan->device->dev, data->sg,
data->sg_len, direction);
- desc = chan->device->device_prep_slave_sg(chan,
+ dmaengine_slave_config(chan, &host->dma_conf);
+ desc = dmaengine_prep_slave_sg(chan,
data->sg, sglen, slave_dirn,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
@@ -1960,10 +1963,6 @@ static bool atmci_configure_dma(struct atmel_mci *host)
if (pdata && find_slave_dev(pdata->dma_slave)) {
dma_cap_mask_t mask;
- setup_dma_addr(pdata->dma_slave,
- host->mapbase + ATMCI_TDR,
- host->mapbase + ATMCI_RDR);
-
/* Try to grab a DMA channel */
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -1975,8 +1974,16 @@ static bool atmci_configure_dma(struct atmel_mci *host)
return false;
} else {
dev_info(&host->pdev->dev,
- "Using %s for DMA transfers\n",
+ "using %s for DMA transfers\n",
dma_chan_name(host->dma.chan));
+
+ host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
+ host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_conf.src_maxburst = 1;
+ host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
+ host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_conf.dst_maxburst = 1;
+ host->dma_conf.device_fc = false;
return true;
}
}
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 64a8325a4a8a..c1f3673ae1ef 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -160,6 +160,16 @@ module_param(rw_threshold, uint, S_IRUGO);
MODULE_PARM_DESC(rw_threshold,
"Read/Write threshold. Default = 32");
+static unsigned poll_threshold = 128;
+module_param(poll_threshold, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_threshold,
+ "Polling transaction size threshold. Default = 128");
+
+static unsigned poll_loopcount = 32;
+module_param(poll_loopcount, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_loopcount,
+ "Maximum polling loop count. Default = 32");
+
static unsigned __initdata use_dma = 1;
module_param(use_dma, uint, 0);
MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1");
@@ -193,6 +203,7 @@ struct mmc_davinci_host {
bool use_dma;
bool do_dma;
bool sdio_int;
+ bool active_request;
/* Scatterlist DMA uses one or more parameter RAM entries:
* the main one (associated with rxdma or txdma) plus zero or
@@ -219,6 +230,7 @@ struct mmc_davinci_host {
#endif
};
+static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);
/* PIO only */
static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
@@ -376,7 +388,20 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
writel(cmd->arg, host->base + DAVINCI_MMCARGHL);
writel(cmd_reg, host->base + DAVINCI_MMCCMD);
- writel(im_val, host->base + DAVINCI_MMCIM);
+
+ host->active_request = true;
+
+ if (!host->do_dma && host->bytes_left <= poll_threshold) {
+ u32 count = poll_loopcount;
+
+ while (host->active_request && count--) {
+ mmc_davinci_irq(0, host);
+ cpu_relax();
+ }
+ }
+
+ if (host->active_request)
+ writel(im_val, host->base + DAVINCI_MMCIM);
}
/*----------------------------------------------------------------------*/
@@ -915,6 +940,7 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
if (!data->stop || (host->cmd && host->cmd->error)) {
mmc_request_done(host->mmc, data->mrq);
writel(0, host->base + DAVINCI_MMCIM);
+ host->active_request = false;
} else
mmc_davinci_start_command(host, data->stop);
}
@@ -942,6 +968,7 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
cmd->mrq->cmd->retries = 0;
mmc_request_done(host->mmc, cmd->mrq);
writel(0, host->base + DAVINCI_MMCIM);
+ host->active_request = false;
}
}
@@ -1009,12 +1036,33 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
* by read. So, it is not unbouned loop even in the case of
* non-dma.
*/
- while (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
- davinci_fifo_data_trans(host, rw_threshold);
- status = readl(host->base + DAVINCI_MMCST0);
- if (!status)
- break;
- qstatus |= status;
+ if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
+ unsigned long im_val;
+
+ /*
+ * If interrupts fire during the following loop, they will be
+ * handled by the handler, but the PIC will still buffer these.
+ * As a result, the handler will be called again to serve these
+ * needlessly. In order to avoid these spurious interrupts,
+ * keep interrupts masked during the loop.
+ */
+ im_val = readl(host->base + DAVINCI_MMCIM);
+ writel(0, host->base + DAVINCI_MMCIM);
+
+ do {
+ davinci_fifo_data_trans(host, rw_threshold);
+ status = readl(host->base + DAVINCI_MMCST0);
+ qstatus |= status;
+ } while (host->bytes_left &&
+ (status & (MMCST0_DXRDY | MMCST0_DRRDY)));
+
+ /*
+ * If an interrupt is pending, it is assumed it will fire when
+ * it is unmasked. This assumption is also taken when the MMCIM
+ * is first set. Otherwise, writing to MMCIM after reading the
+ * status is race-prone.
+ */
+ writel(im_val, host->base + DAVINCI_MMCIM);
}
if (qstatus & MMCST0_DATDNE) {
@@ -1418,17 +1466,14 @@ static int davinci_mmcsd_suspend(struct device *dev)
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
int ret;
- mmc_host_enable(host->mmc);
ret = mmc_suspend_host(host->mmc);
if (!ret) {
writel(0, host->base + DAVINCI_MMCIM);
mmc_davinci_reset_ctrl(host, 1);
- mmc_host_disable(host->mmc);
clk_disable(host->clk);
host->suspended = 1;
} else {
host->suspended = 0;
- mmc_host_disable(host->mmc);
}
return ret;
@@ -1444,7 +1489,6 @@ static int davinci_mmcsd_resume(struct device *dev)
return 0;
clk_enable(host->clk);
- mmc_host_enable(host->mmc);
mmc_davinci_reset_ctrl(host, 0);
ret = mmc_resume_host(host->mmc);
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
new file mode 100644
index 000000000000..dc0d25a013e0
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -0,0 +1,158 @@
+/*
+ * Synopsys DesignWare Multimedia Card PCI Interface driver
+ *
+ * Copyright (C) 2012 Vayavya Labs Pvt. Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+#define PCI_BAR_NO 2
+#define COMPLETE_BAR 0
+#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700
+#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
+/* Defining the Capabilities */
+#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\
+ MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\
+ MMC_CAP_SDIO_IRQ)
+
+static struct dw_mci_board pci_board_data = {
+ .num_slots = 1,
+ .caps = DW_MCI_CAPABILITIES,
+ .bus_hz = 33 * 1000 * 1000,
+ .detect_delay_ms = 200,
+ .fifo_depth = 32,
+};
+
+static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *entries)
+{
+ struct dw_mci *host;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+ if (pci_request_regions(pdev, "dw_mmc_pci")) {
+ ret = -ENODEV;
+ goto err_disable_dev;
+ }
+
+ host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+ if (!host) {
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ host->irq = pdev->irq;
+ host->irq_flags = IRQF_SHARED;
+ host->dev = pdev->dev;
+ host->pdata = &pci_board_data;
+
+ host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
+ if (!host->regs) {
+ ret = -EIO;
+ goto err_unmap;
+ }
+
+ pci_set_drvdata(pdev, host);
+ ret = dw_mci_probe(host);
+ if (ret)
+ goto err_probe_failed;
+ return ret;
+
+err_probe_failed:
+ pci_iounmap(pdev, host->regs);
+err_unmap:
+ kfree(host);
+err_release:
+ pci_release_regions(pdev);
+err_disable_dev:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void __devexit dw_mci_pci_remove(struct pci_dev *pdev)
+{
+ struct dw_mci *host = pci_get_drvdata(pdev);
+
+ dw_mci_remove(host);
+ pci_set_drvdata(pdev, NULL);
+ pci_release_regions(pdev);
+ pci_iounmap(pdev, host->regs);
+ kfree(host);
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dw_mci_pci_suspend(struct device *dev)
+{
+ int ret;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct dw_mci *host = pci_get_drvdata(pdev);
+
+ ret = dw_mci_suspend(host);
+ return ret;
+}
+
+static int dw_mci_pci_resume(struct device *dev)
+{
+ int ret;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct dw_mci *host = pci_get_drvdata(pdev);
+
+ ret = dw_mci_resume(host);
+ return ret;
+}
+#else
+#define dw_mci_pci_suspend NULL
+#define dw_mci_pci_resume NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume);
+
+static DEFINE_PCI_DEVICE_TABLE(dw_mci_pci_id) = {
+ { PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, dw_mci_pci_id);
+
+static struct pci_driver dw_mci_pci_driver = {
+ .name = "dw_mmc_pci",
+ .id_table = dw_mci_pci_id,
+ .probe = dw_mci_pci_probe,
+ .remove = dw_mci_pci_remove,
+ .driver = {
+ .pm = &dw_mci_pci_pmops
+ },
+};
+
+static int __init dw_mci_init(void)
+{
+ return pci_register_driver(&dw_mci_pci_driver);
+}
+
+static void __exit dw_mci_exit(void)
+{
+ pci_unregister_driver(&dw_mci_pci_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver");
+MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
new file mode 100644
index 000000000000..92ec3eb3aae7
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -0,0 +1,134 @@
+/*
+ * Synopsys DesignWare Multimedia Card Interface driver
+ *
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2009, 2010 Imagination Technologies Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+ struct dw_mci *host;
+ struct resource *regs;
+ int ret;
+
+ host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ ret = -ENXIO;
+ goto err_free;
+ }
+
+ host->irq = platform_get_irq(pdev, 0);
+ if (host->irq < 0) {
+ ret = host->irq;
+ goto err_free;
+ }
+
+ host->dev = pdev->dev;
+ host->irq_flags = 0;
+ host->pdata = pdev->dev.platform_data;
+ ret = -ENOMEM;
+ host->regs = ioremap(regs->start, resource_size(regs));
+ if (!host->regs)
+ goto err_free;
+ platform_set_drvdata(pdev, host);
+ ret = dw_mci_probe(host);
+ if (ret)
+ goto err_out;
+ return ret;
+err_out:
+ iounmap(host->regs);
+err_free:
+ kfree(host);
+ return ret;
+}
+
+static int __exit dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+ struct dw_mci *host = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ dw_mci_remove(host);
+ iounmap(host->regs);
+ kfree(host);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * TODO: we should probably disable the clock to the card in the suspend path.
+ */
+static int dw_mci_pltfm_suspend(struct device *dev)
+{
+ int ret;
+ struct dw_mci *host = dev_get_drvdata(dev);
+
+ ret = dw_mci_suspend(host);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int dw_mci_pltfm_resume(struct device *dev)
+{
+ int ret;
+ struct dw_mci *host = dev_get_drvdata(dev);
+
+ ret = dw_mci_resume(host);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#else
+#define dw_mci_pltfm_suspend NULL
+#define dw_mci_pltfm_resume NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
+
+static struct platform_driver dw_mci_pltfm_driver = {
+ .remove = __exit_p(dw_mci_pltfm_remove),
+ .driver = {
+ .name = "dw_mmc",
+ .pm = &dw_mci_pltfm_pmops,
+ },
+};
+
+static int __init dw_mci_init(void)
+{
+ return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
+}
+
+static void __exit dw_mci_exit(void)
+{
+ platform_driver_unregister(&dw_mci_pltfm_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
+MODULE_AUTHOR("NXP Semiconductor VietNam");
+MODULE_AUTHOR("Imagination Technologies Ltd");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 8bec1c36b159..bf3c9b456aaf 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -268,7 +268,7 @@ static void dw_mci_start_command(struct dw_mci *host,
struct mmc_command *cmd, u32 cmd_flags)
{
host->cmd = cmd;
- dev_vdbg(&host->pdev->dev,
+ dev_vdbg(&host->dev,
"start command: ARGR=0x%08x CMDR=0x%08x\n",
cmd->arg, cmd_flags);
@@ -295,15 +295,25 @@ static void dw_mci_stop_dma(struct dw_mci *host)
}
}
+static int dw_mci_get_dma_dir(struct mmc_data *data)
+{
+ if (data->flags & MMC_DATA_WRITE)
+ return DMA_TO_DEVICE;
+ else
+ return DMA_FROM_DEVICE;
+}
+
#ifdef CONFIG_MMC_DW_IDMAC
static void dw_mci_dma_cleanup(struct dw_mci *host)
{
struct mmc_data *data = host->data;
if (data)
- dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ if (!data->host_cookie)
+ dma_unmap_sg(&host->dev,
+ data->sg,
+ data->sg_len,
+ dw_mci_get_dma_dir(data));
}
static void dw_mci_idmac_stop_dma(struct dw_mci *host)
@@ -326,7 +336,7 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
{
struct mmc_data *data = host->data;
- dev_vdbg(&host->pdev->dev, "DMA complete\n");
+ dev_vdbg(&host->dev, "DMA complete\n");
host->dma_ops->cleanup(host);
@@ -428,17 +438,15 @@ static struct dw_mci_dma_ops dw_mci_idmac_ops = {
};
#endif /* CONFIG_MMC_DW_IDMAC */
-static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
+static int dw_mci_pre_dma_transfer(struct dw_mci *host,
+ struct mmc_data *data,
+ bool next)
{
struct scatterlist *sg;
- unsigned int i, direction, sg_len;
- u32 temp;
+ unsigned int i, sg_len;
- host->using_dma = 0;
-
- /* If we don't have a channel, we can't do DMA */
- if (!host->use_dma)
- return -ENODEV;
+ if (!next && data->host_cookie)
+ return data->host_cookie;
/*
* We don't do DMA on "complex" transfers, i.e. with
@@ -447,6 +455,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
*/
if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
return -EINVAL;
+
if (data->blksz & 3)
return -EINVAL;
@@ -455,17 +464,74 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
return -EINVAL;
}
- host->using_dma = 1;
+ sg_len = dma_map_sg(&host->dev,
+ data->sg,
+ data->sg_len,
+ dw_mci_get_dma_dir(data));
+ if (sg_len == 0)
+ return -EINVAL;
- if (data->flags & MMC_DATA_READ)
- direction = DMA_FROM_DEVICE;
- else
- direction = DMA_TO_DEVICE;
+ if (next)
+ data->host_cookie = sg_len;
- sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
- direction);
+ return sg_len;
+}
- dev_vdbg(&host->pdev->dev,
+static void dw_mci_pre_req(struct mmc_host *mmc,
+ struct mmc_request *mrq,
+ bool is_first_req)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+
+ if (!slot->host->use_dma || !data)
+ return;
+
+ if (data->host_cookie) {
+ data->host_cookie = 0;
+ return;
+ }
+
+ if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
+ data->host_cookie = 0;
+}
+
+static void dw_mci_post_req(struct mmc_host *mmc,
+ struct mmc_request *mrq,
+ int err)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+
+ if (!slot->host->use_dma || !data)
+ return;
+
+ if (data->host_cookie)
+ dma_unmap_sg(&slot->host->dev,
+ data->sg,
+ data->sg_len,
+ dw_mci_get_dma_dir(data));
+ data->host_cookie = 0;
+}
+
+static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
+{
+ int sg_len;
+ u32 temp;
+
+ host->using_dma = 0;
+
+ /* If we don't have a channel, we can't do DMA */
+ if (!host->use_dma)
+ return -ENODEV;
+
+ sg_len = dw_mci_pre_dma_transfer(host, data, 0);
+ if (sg_len < 0)
+ return sg_len;
+
+ host->using_dma = 1;
+
+ dev_vdbg(&host->dev,
"sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
(unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
sg_len);
@@ -579,8 +645,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot)
SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
/* enable clock */
- mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE |
- SDMMC_CLKEN_LOW_PWR);
+ mci_writel(host, CLKENA, ((SDMMC_CLKEN_ENABLE |
+ SDMMC_CLKEN_LOW_PWR) << slot->id));
/* inform CIU */
mci_send_cmd(slot,
@@ -800,6 +866,8 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request,
+ .pre_req = dw_mci_pre_req,
+ .post_req = dw_mci_post_req,
.set_ios = dw_mci_set_ios,
.get_ro = dw_mci_get_ro,
.get_cd = dw_mci_get_cd,
@@ -821,12 +889,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
slot = list_entry(host->queue.next,
struct dw_mci_slot, queue_node);
list_del(&slot->queue_node);
- dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+ dev_vdbg(&host->dev, "list not empty: %s is next\n",
mmc_hostname(slot->mmc));
host->state = STATE_SENDING_CMD;
dw_mci_start_request(host, slot);
} else {
- dev_vdbg(&host->pdev->dev, "list empty\n");
+ dev_vdbg(&host->dev, "list empty\n");
host->state = STATE_IDLE;
}
@@ -965,7 +1033,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
data->bytes_xfered = 0;
data->error = -ETIMEDOUT;
} else {
- dev_err(&host->pdev->dev,
+ dev_err(&host->dev,
"data FIFO error "
"(status=%08x)\n",
status);
@@ -1682,7 +1750,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
struct mmc_host *mmc;
struct dw_mci_slot *slot;
- mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev);
+ mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
if (!mmc)
return -ENOMEM;
@@ -1720,13 +1788,11 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-#ifdef CONFIG_MMC_DW_IDMAC
- mmc->max_segs = host->ring_size;
- mmc->max_blk_size = 65536;
- mmc->max_blk_count = host->ring_size;
- mmc->max_seg_size = 0x1000;
- mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
-#else
+ if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
+ mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
+ else
+ mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
+
if (host->pdata->blk_settings) {
mmc->max_segs = host->pdata->blk_settings->max_segs;
mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
@@ -1735,13 +1801,20 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
} else {
/* Useful defaults if platform data is unset. */
+#ifdef CONFIG_MMC_DW_IDMAC
+ mmc->max_segs = host->ring_size;
+ mmc->max_blk_size = 65536;
+ mmc->max_blk_count = host->ring_size;
+ mmc->max_seg_size = 0x1000;
+ mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
+#else
mmc->max_segs = 64;
mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
mmc->max_blk_count = 512;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
- }
#endif /* CONFIG_MMC_DW_IDMAC */
+ }
host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
@@ -1789,10 +1862,10 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
/* Alloc memory for sg translation */
- host->sg_cpu = dma_alloc_coherent(&host->pdev->dev, PAGE_SIZE,
+ host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
- dev_err(&host->pdev->dev, "%s: could not alloc DMA memory\n",
+ dev_err(&host->dev, "%s: could not alloc DMA memory\n",
__func__);
goto no_dma;
}
@@ -1800,7 +1873,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
/* Determine which DMA interface to use */
#ifdef CONFIG_MMC_DW_IDMAC
host->dma_ops = &dw_mci_idmac_ops;
- dev_info(&host->pdev->dev, "Using internal DMA controller.\n");
+ dev_info(&host->dev, "Using internal DMA controller.\n");
#endif
if (!host->dma_ops)
@@ -1808,12 +1881,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
if (host->dma_ops->init) {
if (host->dma_ops->init(host)) {
- dev_err(&host->pdev->dev, "%s: Unable to initialize "
+ dev_err(&host->dev, "%s: Unable to initialize "
"DMA Controller.\n", __func__);
goto no_dma;
}
} else {
- dev_err(&host->pdev->dev, "DMA initialization not found.\n");
+ dev_err(&host->dev, "DMA initialization not found.\n");
goto no_dma;
}
@@ -1821,7 +1894,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
return;
no_dma:
- dev_info(&host->pdev->dev, "Using PIO mode.\n");
+ dev_info(&host->dev, "Using PIO mode.\n");
host->use_dma = 0;
return;
}
@@ -1847,61 +1920,37 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
return false;
}
-static int dw_mci_probe(struct platform_device *pdev)
+int dw_mci_probe(struct dw_mci *host)
{
- struct dw_mci *host;
- struct resource *regs;
- struct dw_mci_board *pdata;
- int irq, ret, i, width;
+ int width, i, ret = 0;
u32 fifo_size;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs)
- return -ENXIO;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
- if (!host)
- return -ENOMEM;
-
- host->pdev = pdev;
- host->pdata = pdata = pdev->dev.platform_data;
- if (!pdata || !pdata->init) {
- dev_err(&pdev->dev,
+ if (!host->pdata || !host->pdata->init) {
+ dev_err(&host->dev,
"Platform data must supply init function\n");
- ret = -ENODEV;
- goto err_freehost;
+ return -ENODEV;
}
- if (!pdata->select_slot && pdata->num_slots > 1) {
- dev_err(&pdev->dev,
+ if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
+ dev_err(&host->dev,
"Platform data must supply select_slot function\n");
- ret = -ENODEV;
- goto err_freehost;
+ return -ENODEV;
}
- if (!pdata->bus_hz) {
- dev_err(&pdev->dev,
+ if (!host->pdata->bus_hz) {
+ dev_err(&host->dev,
"Platform data must supply bus speed\n");
- ret = -ENODEV;
- goto err_freehost;
+ return -ENODEV;
}
- host->bus_hz = pdata->bus_hz;
- host->quirks = pdata->quirks;
+ host->bus_hz = host->pdata->bus_hz;
+ host->quirks = host->pdata->quirks;
spin_lock_init(&host->lock);
INIT_LIST_HEAD(&host->queue);
- ret = -ENOMEM;
- host->regs = ioremap(regs->start, resource_size(regs));
- if (!host->regs)
- goto err_freehost;
- host->dma_ops = pdata->dma_ops;
+ host->dma_ops = host->pdata->dma_ops;
dw_mci_init_dma(host);
/*
@@ -1931,7 +1980,7 @@ static int dw_mci_probe(struct platform_device *pdev)
}
/* Reset all blocks */
- if (!mci_wait_reset(&pdev->dev, host)) {
+ if (!mci_wait_reset(&host->dev, host)) {
ret = -ENODEV;
goto err_dmaunmap;
}
@@ -1974,13 +2023,10 @@ static int dw_mci_probe(struct platform_device *pdev)
if (!dw_mci_card_workqueue)
goto err_dmaunmap;
INIT_WORK(&host->card_work, dw_mci_work_routine_card);
-
- ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host);
+ ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
if (ret)
goto err_workqueue;
- platform_set_drvdata(pdev, host);
-
if (host->pdata->num_slots)
host->num_slots = host->pdata->num_slots;
else
@@ -2000,7 +2046,7 @@ static int dw_mci_probe(struct platform_device *pdev)
* Need to check the version-id and set data-offset for DATA register.
*/
host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
- dev_info(&pdev->dev, "Version ID is %04x\n", host->verid);
+ dev_info(&host->dev, "Version ID is %04x\n", host->verid);
if (host->verid < DW_MMC_240A)
host->data_offset = DATA_OFFSET;
@@ -2017,12 +2063,12 @@ static int dw_mci_probe(struct platform_device *pdev)
DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
- dev_info(&pdev->dev, "DW MMC controller at irq %d, "
+ dev_info(&host->dev, "DW MMC controller at irq %d, "
"%d bit host data width, "
"%u deep fifo\n",
- irq, width, fifo_size);
+ host->irq, width, fifo_size);
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
- dev_info(&pdev->dev, "Internal DMAC interrupt fix enabled.\n");
+ dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
return 0;
@@ -2033,7 +2079,7 @@ err_init_slot:
dw_mci_cleanup_slot(host->slot[i], i);
i--;
}
- free_irq(irq, host);
+ free_irq(host->irq, host);
err_workqueue:
destroy_workqueue(dw_mci_card_workqueue);
@@ -2041,33 +2087,26 @@ err_workqueue:
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
- dma_free_coherent(&host->pdev->dev, PAGE_SIZE,
+ dma_free_coherent(&host->dev, PAGE_SIZE,
host->sg_cpu, host->sg_dma);
- iounmap(host->regs);
if (host->vmmc) {
regulator_disable(host->vmmc);
regulator_put(host->vmmc);
}
-
-
-err_freehost:
- kfree(host);
return ret;
}
+EXPORT_SYMBOL(dw_mci_probe);
-static int __exit dw_mci_remove(struct platform_device *pdev)
+void dw_mci_remove(struct dw_mci *host)
{
- struct dw_mci *host = platform_get_drvdata(pdev);
int i;
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
- platform_set_drvdata(pdev, NULL);
-
for (i = 0; i < host->num_slots; i++) {
- dev_dbg(&pdev->dev, "remove slot %d\n", i);
+ dev_dbg(&host->dev, "remove slot %d\n", i);
if (host->slot[i])
dw_mci_cleanup_slot(host->slot[i], i);
}
@@ -2076,9 +2115,9 @@ static int __exit dw_mci_remove(struct platform_device *pdev)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
- free_irq(platform_get_irq(pdev, 0), host);
+ free_irq(host->irq, host);
destroy_workqueue(dw_mci_card_workqueue);
- dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+ dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
@@ -2088,20 +2127,18 @@ static int __exit dw_mci_remove(struct platform_device *pdev)
regulator_put(host->vmmc);
}
- iounmap(host->regs);
-
- kfree(host);
- return 0;
}
+EXPORT_SYMBOL(dw_mci_remove);
+
+
#ifdef CONFIG_PM_SLEEP
/*
* TODO: we should probably disable the clock to the card in the suspend path.
*/
-static int dw_mci_suspend(struct device *dev)
+int dw_mci_suspend(struct dw_mci *host)
{
- int i, ret;
- struct dw_mci *host = dev_get_drvdata(dev);
+ int i, ret = 0;
for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i];
@@ -2123,11 +2160,11 @@ static int dw_mci_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL(dw_mci_suspend);
-static int dw_mci_resume(struct device *dev)
+int dw_mci_resume(struct dw_mci *host)
{
int i, ret;
- struct dw_mci *host = dev_get_drvdata(dev);
if (host->vmmc)
regulator_enable(host->vmmc);
@@ -2135,7 +2172,7 @@ static int dw_mci_resume(struct device *dev)
if (host->dma_ops->init)
host->dma_ops->init(host);
- if (!mci_wait_reset(dev, host)) {
+ if (!mci_wait_reset(&host->dev, host)) {
ret = -ENODEV;
return ret;
}
@@ -2157,32 +2194,19 @@ static int dw_mci_resume(struct device *dev)
if (ret < 0)
return ret;
}
-
return 0;
}
-#else
-#define dw_mci_suspend NULL
-#define dw_mci_resume NULL
+EXPORT_SYMBOL(dw_mci_resume);
#endif /* CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume);
-
-static struct platform_driver dw_mci_driver = {
- .remove = __exit_p(dw_mci_remove),
- .driver = {
- .name = "dw_mmc",
- .pm = &dw_mci_pmops,
- },
-};
-
static int __init dw_mci_init(void)
{
- return platform_driver_probe(&dw_mci_driver, dw_mci_probe);
+ printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
+ return 0;
}
static void __exit dw_mci_exit(void)
{
- platform_driver_unregister(&dw_mci_driver);
}
module_init(dw_mci_init);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index df392a1143f2..15c27e17c23f 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -175,4 +175,11 @@
(*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value))
#endif
+extern int dw_mci_probe(struct dw_mci *host);
+extern void dw_mci_remove(struct dw_mci *host);
+#ifdef CONFIG_PM
+extern int dw_mci_suspend(struct dw_mci *host);
+extern int dw_mci_resume(struct dw_mci *host);
+#endif
+
#endif /* _DW_MMC_H_ */
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 983e244eca76..032b84791a16 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -30,6 +30,7 @@
#include <linux/dma-mapping.h>
#include <linux/amba/mmci.h>
#include <linux/pm_runtime.h>
+#include <linux/types.h>
#include <asm/div64.h>
#include <asm/io.h>
@@ -400,6 +401,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
.src_maxburst = variant->fifohalfsize >> 2, /* # of words */
.dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
+ .device_fc = false,
};
struct dma_chan *chan;
struct dma_device *device;
@@ -441,7 +443,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
return -EINVAL;
dmaengine_slave_config(chan, &conf);
- desc = device->device_prep_slave_sg(chan, data->sg, nr_sg,
+ desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
conf.direction, DMA_CTRL_ACK);
if (!desc)
goto unmap_exit;
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 4184b7946bbf..b2058b432320 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -33,6 +33,7 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/dmaengine.h>
+#include <linux/types.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -254,7 +255,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
if (nents != data->sg_len)
return -EINVAL;
- host->desc = host->dma->device->device_prep_slave_sg(host->dma,
+ host->desc = dmaengine_prep_slave_sg(host->dma,
data->sg, data->sg_len, slave_dirn,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -267,6 +268,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
wmb();
dmaengine_submit(host->desc);
+ dma_async_issue_pending(host->dma);
return 0;
}
@@ -710,6 +712,7 @@ static int mxcmci_setup_dma(struct mmc_host *mmc)
config->src_addr_width = 4;
config->dst_maxburst = host->burstlen;
config->src_maxburst = host->burstlen;
+ config->device_fc = false;
return dmaengine_slave_config(host->dma, config);
}
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 382c835d217c..65f36cf2ff33 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -324,7 +324,7 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
sg_len = SSP_PIO_NUM;
}
- desc = host->dmach->device->device_prep_slave_sg(host->dmach,
+ desc = dmaengine_prep_slave_sg(host->dmach,
sgl, sg_len, host->slave_dirn, append);
if (desc) {
desc->callback = mxs_mmc_dma_irq_callback;
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index fd0c661bbad3..47adb161d3ad 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -26,6 +26,9 @@
#include <linux/platform_device.h>
#include <linux/timer.h>
#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
#include <linux/mmc/mmc.h>
@@ -106,17 +109,6 @@
#define SOFTRESET (1 << 1)
#define RESETDONE (1 << 0)
-/*
- * FIXME: Most likely all the data using these _DEVID defines should come
- * from the platform_data, or implemented in controller and slot specific
- * functions.
- */
-#define OMAP_MMC1_DEVID 0
-#define OMAP_MMC2_DEVID 1
-#define OMAP_MMC3_DEVID 2
-#define OMAP_MMC4_DEVID 3
-#define OMAP_MMC5_DEVID 4
-
#define MMC_AUTOSUSPEND_DELAY 100
#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MIN_CLOCK 400000
@@ -164,7 +156,6 @@ struct omap_hsmmc_host {
void __iomem *base;
resource_size_t mapbase;
spinlock_t irq_lock; /* Prevent races with irq handler */
- unsigned int id;
unsigned int dma_len;
unsigned int dma_sg_idx;
unsigned char bus_mode;
@@ -179,7 +170,6 @@ struct omap_hsmmc_host {
int got_dbclk;
int response_busy;
int context_loss;
- int dpm_state;
int vdd;
int protect_card;
int reqs_blocked;
@@ -241,28 +231,7 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
#ifdef CONFIG_REGULATOR
-static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
- int vdd)
-{
- struct omap_hsmmc_host *host =
- platform_get_drvdata(to_platform_device(dev));
- int ret;
-
- if (mmc_slot(host).before_set_reg)
- mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
-
- if (power_on)
- ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
- else
- ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
-
- if (mmc_slot(host).after_set_reg)
- mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
-
- return ret;
-}
-
-static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
+static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
int vdd)
{
struct omap_hsmmc_host *host =
@@ -275,6 +244,13 @@ static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
*/
if (!host->vcc)
return 0;
+ /*
+ * With DT, never turn OFF the regulator. This is because
+ * the pbias cell programming support is still missing when
+ * booting with Device tree
+ */
+ if (of_have_populated_dt() && !vdd)
+ return 0;
if (mmc_slot(host).before_set_reg)
mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
@@ -318,106 +294,16 @@ static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
return ret;
}
-static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on,
- int vdd)
-{
- return 0;
-}
-
-static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
- int vdd, int cardsleep)
-{
- struct omap_hsmmc_host *host =
- platform_get_drvdata(to_platform_device(dev));
- int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
-
- return regulator_set_mode(host->vcc, mode);
-}
-
-static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep,
- int vdd, int cardsleep)
-{
- struct omap_hsmmc_host *host =
- platform_get_drvdata(to_platform_device(dev));
- int err, mode;
-
- /*
- * If we don't see a Vcc regulator, assume it's a fixed
- * voltage always-on regulator.
- */
- if (!host->vcc)
- return 0;
-
- mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
-
- if (!host->vcc_aux)
- return regulator_set_mode(host->vcc, mode);
-
- if (cardsleep) {
- /* VCC can be turned off if card is asleep */
- if (sleep)
- err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
- else
- err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
- } else
- err = regulator_set_mode(host->vcc, mode);
- if (err)
- return err;
-
- if (!mmc_slot(host).vcc_aux_disable_is_sleep)
- return regulator_set_mode(host->vcc_aux, mode);
-
- if (sleep)
- return regulator_disable(host->vcc_aux);
- else
- return regulator_enable(host->vcc_aux);
-}
-
-static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep,
- int vdd, int cardsleep)
-{
- return 0;
-}
-
static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
{
struct regulator *reg;
- int ret = 0;
int ocr_value = 0;
- switch (host->id) {
- case OMAP_MMC1_DEVID:
- /* On-chip level shifting via PBIAS0/PBIAS1 */
- mmc_slot(host).set_power = omap_hsmmc_1_set_power;
- mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep;
- break;
- case OMAP_MMC2_DEVID:
- case OMAP_MMC3_DEVID:
- case OMAP_MMC5_DEVID:
- /* Off-chip level shifting, or none */
- mmc_slot(host).set_power = omap_hsmmc_235_set_power;
- mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep;
- break;
- case OMAP_MMC4_DEVID:
- mmc_slot(host).set_power = omap_hsmmc_4_set_power;
- mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep;
- default:
- pr_err("MMC%d configuration not supported!\n", host->id);
- return -EINVAL;
- }
+ mmc_slot(host).set_power = omap_hsmmc_set_power;
reg = regulator_get(host->dev, "vmmc");
if (IS_ERR(reg)) {
dev_dbg(host->dev, "vmmc regulator missing\n");
- /*
- * HACK: until fixed.c regulator is usable,
- * we don't require a main regulator
- * for MMC2 or MMC3
- */
- if (host->id == OMAP_MMC1_DEVID) {
- ret = PTR_ERR(reg);
- goto err;
- }
} else {
host->vcc = reg;
ocr_value = mmc_regulator_get_ocrmask(reg);
@@ -425,8 +311,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
mmc_slot(host).ocr_mask = ocr_value;
} else {
if (!(mmc_slot(host).ocr_mask & ocr_value)) {
- pr_err("MMC%d ocrmask %x is not supported\n",
- host->id, mmc_slot(host).ocr_mask);
+ dev_err(host->dev, "ocrmask %x is not supported\n",
+ mmc_slot(host).ocr_mask);
mmc_slot(host).ocr_mask = 0;
return -EINVAL;
}
@@ -459,11 +345,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
}
return 0;
-
-err:
- mmc_slot(host).set_power = NULL;
- mmc_slot(host).set_sleep = NULL;
- return ret;
}
static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
@@ -471,7 +352,6 @@ static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
regulator_put(host->vcc);
regulator_put(host->vcc_aux);
mmc_slot(host).set_power = NULL;
- mmc_slot(host).set_sleep = NULL;
}
static inline int omap_hsmmc_have_reg(void)
@@ -710,7 +590,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
- if (host->id == OMAP_MMC1_DEVID) {
+ if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
if (host->power_mode != MMC_POWER_OFF &&
(1 << ios->vdd) <= MMC_VDD_23_24)
hctl = SDVS18;
@@ -1261,14 +1141,14 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
host->reqs_blocked = 0;
if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
if (host->protect_card) {
- pr_info("%s: cover is closed, "
+ dev_info(host->dev, "%s: cover is closed, "
"card is now accessible\n",
mmc_hostname(host->mmc));
host->protect_card = 0;
}
} else {
if (!host->protect_card) {
- pr_info("%s: cover is open, "
+ dev_info(host->dev, "%s: cover is open, "
"card is now inaccessible\n",
mmc_hostname(host->mmc));
host->protect_card = 1;
@@ -1405,7 +1285,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
if (!next && data->host_cookie &&
data->host_cookie != host->next_data.cookie) {
- pr_warning("[%s] invalid cookie: data->host_cookie %d"
+ dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d"
" host->next_data.cookie %d\n",
__func__, data->host_cookie, host->next_data.cookie);
data->host_cookie = 0;
@@ -1663,7 +1543,13 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* of external transceiver; but they all handle 1.8V.
*/
if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
- (ios->vdd == DUAL_VOLT_OCR_BIT)) {
+ (ios->vdd == DUAL_VOLT_OCR_BIT) &&
+ /*
+ * With pbias cell programming missing, this
+ * can't be allowed when booting with device
+ * tree.
+ */
+ (!of_have_populated_dt())) {
/*
* The mmc_select_voltage fn of the core does
* not seem to set the power_mode to
@@ -1748,7 +1634,7 @@ static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
return 0;
}
-static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
+static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
@@ -1782,15 +1668,8 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
if (host->pdata->get_context_loss_count)
context_loss = host->pdata->get_context_loss_count(host->dev);
- seq_printf(s, "mmc%d:\n"
- " enabled:\t%d\n"
- " dpm_state:\t%d\n"
- " nesting_cnt:\t%d\n"
- " ctx_loss:\t%d:%d\n"
- "\nregs:\n",
- mmc->index, mmc->enabled ? 1 : 0,
- host->dpm_state, mmc->nesting_cnt,
- host->context_loss, context_loss);
+ seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n",
+ mmc->index, host->context_loss, context_loss);
if (host->suspended) {
seq_printf(s, "host suspended, can't read registers\n");
@@ -1847,6 +1726,65 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
#endif
+#ifdef CONFIG_OF
+static u16 omap4_reg_offset = 0x100;
+
+static const struct of_device_id omap_mmc_of_match[] = {
+ {
+ .compatible = "ti,omap2-hsmmc",
+ },
+ {
+ .compatible = "ti,omap3-hsmmc",
+ },
+ {
+ .compatible = "ti,omap4-hsmmc",
+ .data = &omap4_reg_offset,
+ },
+ {},
+}
+MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
+
+static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
+{
+ struct omap_mmc_platform_data *pdata;
+ struct device_node *np = dev->of_node;
+ u32 bus_width;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL; /* out of memory */
+
+ if (of_find_property(np, "ti,dual-volt", NULL))
+ pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
+
+ /* This driver only supports 1 slot */
+ pdata->nr_slots = 1;
+ pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0);
+ pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0);
+
+ if (of_find_property(np, "ti,non-removable", NULL)) {
+ pdata->slots[0].nonremovable = true;
+ pdata->slots[0].no_regulator_off_init = true;
+ }
+ of_property_read_u32(np, "ti,bus-width", &bus_width);
+ if (bus_width == 4)
+ pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA;
+ else if (bus_width == 8)
+ pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA;
+
+ if (of_find_property(np, "ti,needs-special-reset", NULL))
+ pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
+ return pdata;
+}
+#else
+static inline struct omap_mmc_platform_data
+ *of_get_hsmmc_pdata(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
static int __init omap_hsmmc_probe(struct platform_device *pdev)
{
struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
@@ -1854,6 +1792,16 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
struct omap_hsmmc_host *host = NULL;
struct resource *res;
int ret, irq;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
+ if (match) {
+ pdata = of_get_hsmmc_pdata(&pdev->dev);
+ if (match->data) {
+ u16 *offsetp = match->data;
+ pdata->reg_offset = *offsetp;
+ }
+ }
if (pdata == NULL) {
dev_err(&pdev->dev, "Platform Data is missing\n");
@@ -1894,7 +1842,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
host->dev->dma_mask = &pdata->dma_mask;
host->dma_ch = -1;
host->irq = irq;
- host->id = pdev->id;
host->slot_id = 0;
host->mapbase = res->start;
host->base = ioremap(host->mapbase, SZ_4K);
@@ -1912,8 +1859,12 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
if (mmc_slot(host).vcc_aux_disable_is_sleep)
mmc_slot(host).no_off = 1;
- mmc->f_min = OMAP_MMC_MIN_CLOCK;
- mmc->f_max = OMAP_MMC_MAX_CLOCK;
+ mmc->f_min = OMAP_MMC_MIN_CLOCK;
+
+ if (pdata->max_freq > 0)
+ mmc->f_max = pdata->max_freq;
+ else
+ mmc->f_max = OMAP_MMC_MAX_CLOCK;
spin_lock_init(&host->irq_lock);
@@ -1926,7 +1877,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_context_save(host);
- mmc->caps |= MMC_CAP_DISABLE;
if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n");
mmc->caps2 |= MMC_CAP2_NO_MULTI_READ;
@@ -1977,32 +1927,19 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_conf_bus_power(host);
- /* Select DMA lines */
- switch (host->id) {
- case OMAP_MMC1_DEVID:
- host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
- host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
- break;
- case OMAP_MMC2_DEVID:
- host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
- host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
- break;
- case OMAP_MMC3_DEVID:
- host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
- host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
- break;
- case OMAP_MMC4_DEVID:
- host->dma_line_tx = OMAP44XX_DMA_MMC4_TX;
- host->dma_line_rx = OMAP44XX_DMA_MMC4_RX;
- break;
- case OMAP_MMC5_DEVID:
- host->dma_line_tx = OMAP44XX_DMA_MMC5_TX;
- host->dma_line_rx = OMAP44XX_DMA_MMC5_RX;
- break;
- default:
- dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!res) {
+ dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
+ goto err_irq;
+ }
+ host->dma_line_tx = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!res) {
+ dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
goto err_irq;
}
+ host->dma_line_rx = res->start;
/* Request IRQ for MMC operations */
ret = request_irq(host->irq, omap_hsmmc_irq, 0,
@@ -2083,6 +2020,7 @@ err_irq_cd_init:
err_irq:
pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev);
+ pm_runtime_disable(host->dev);
clk_put(host->fclk);
if (host->got_dbclk) {
clk_disable(host->dbclk);
@@ -2269,6 +2207,7 @@ static struct platform_driver omap_hsmmc_driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &omap_hsmmc_dev_pm_ops,
+ .of_match_table = of_match_ptr(omap_mmc_of_match),
},
};
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 5d876ff86f37..f8eb1fb0c921 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -1,7 +1,7 @@
/*
* Freescale eSDHC controller driver.
*
- * Copyright (c) 2007, 2010 Freescale Semiconductor, Inc.
+ * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc.
* Copyright (c) 2009 MontaVista Software, Inc.
*
* Authors: Xiaobo Xie <X.Xie@freescale.com>
@@ -14,6 +14,7 @@
*/
#include <linux/io.h>
+#include <linux/of.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
@@ -114,6 +115,34 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
return pltfm_host->clock / 256 / 16;
}
+static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ /* Workaround to reduce the clock frequency for p1010 esdhc */
+ if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
+ if (clock > 20000000)
+ clock -= 5000000;
+ if (clock > 40000000)
+ clock -= 5000000;
+ }
+
+ /* Set the clock */
+ esdhc_set_clock(host, clock);
+}
+
+#ifdef CONFIG_PM
+static u32 esdhc_proctl;
+static void esdhc_of_suspend(struct sdhci_host *host)
+{
+ esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
+}
+
+static void esdhc_of_resume(struct sdhci_host *host)
+{
+ esdhc_of_enable_dma(host);
+ sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
+}
+#endif
+
static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = sdhci_be32bs_readl,
.read_w = esdhc_readw,
@@ -121,10 +150,14 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.write_l = sdhci_be32bs_writel,
.write_w = esdhc_writew,
.write_b = esdhc_writeb,
- .set_clock = esdhc_set_clock,
+ .set_clock = esdhc_of_set_clock,
.enable_dma = esdhc_of_enable_dma,
.get_max_clock = esdhc_of_get_max_clock,
.get_min_clock = esdhc_of_get_min_clock,
+#ifdef CONFIG_PM
+ .platform_suspend = esdhc_of_suspend,
+ .platform_resume = esdhc_of_resume,
+#endif
};
static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 6ebdc4010e7c..fbbebe251e01 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -29,6 +29,12 @@
#include "sdhci.h"
/*
+ * PCI device IDs
+ */
+#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
+#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
+
+/*
* PCI registers
*/
@@ -47,6 +53,7 @@ struct sdhci_pci_slot;
struct sdhci_pci_fixes {
unsigned int quirks;
+ unsigned int quirks2;
bool allow_runtime_pm;
int (*probe) (struct sdhci_pci_chip *);
@@ -73,6 +80,7 @@ struct sdhci_pci_chip {
struct pci_dev *pdev;
unsigned int quirks;
+ unsigned int quirks2;
bool allow_runtime_pm;
const struct sdhci_pci_fixes *fixes;
@@ -172,6 +180,12 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip)
return 0;
}
+static int pch_hc_probe_slot(struct sdhci_pci_slot *slot)
+{
+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+ return 0;
+}
+
#ifdef CONFIG_PM_RUNTIME
static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
@@ -244,7 +258,8 @@ static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
- slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
+ slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC |
+ MMC_CAP2_HC_ERASE_SZ;
return 0;
}
@@ -271,6 +286,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
.allow_runtime_pm = true,
.probe_slot = mfd_sdio_probe_slot,
};
@@ -281,6 +297,11 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
.probe_slot = mfd_emmc_probe_slot,
};
+static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
+ .quirks = SDHCI_QUIRK_BROKEN_ADMA,
+ .probe_slot = pch_hc_probe_slot,
+};
+
/* O2Micro extra registers */
#define O2_SD_LOCK_WP 0xD3
#define O2_SD_MULTI_VCC3V 0xEE
@@ -817,6 +838,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
},
{
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCH_SDIO0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCH_SDIO1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio,
+ },
+
+ {
.vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120,
.subvendor = PCI_ANY_ID,
@@ -1206,6 +1243,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
host->hw_name = "PCI";
host->ops = &sdhci_pci_ops;
host->quirks = chip->quirks;
+ host->quirks2 = chip->quirks2;
host->irq = pdev->irq;
@@ -1365,6 +1403,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
if (chip->fixes) {
chip->quirks = chip->fixes->quirks;
+ chip->quirks2 = chip->fixes->quirks2;
chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
}
chip->num_slots = slots;
@@ -1379,6 +1418,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
slots = chip->num_slots; /* Quirk may have changed this */
+ pci_enable_msi(pdev);
+
for (i = 0; i < slots; i++) {
slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
if (IS_ERR(slot)) {
@@ -1397,6 +1438,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
return 0;
free:
+ pci_disable_msi(pdev);
+
pci_set_drvdata(pdev, NULL);
kfree(chip);
@@ -1419,6 +1462,8 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
for (i = 0; i < chip->num_slots; i++)
sdhci_pci_remove_slot(chip->slots[i]);
+ pci_disable_msi(pdev);
+
pci_set_drvdata(pdev, NULL);
kfree(chip);
}
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index b7f8b33c5f19..6dfa82e03c7e 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -300,20 +300,15 @@ static int sdhci_resume(struct device *dev)
return sdhci_resume_host(host);
}
-
-const struct dev_pm_ops sdhci_pm_ops = {
- .suspend = sdhci_suspend,
- .resume = sdhci_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
+
static struct platform_driver sdhci_driver = {
.driver = {
.name = "sdhci",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &sdhci_pm_ops,
-#endif
},
.probe = sdhci_probe,
.remove = __devexit_p(sdhci_remove),
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index cb348569454b..53b26502f6e2 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -19,6 +19,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/mmc/card.h>
@@ -31,6 +32,19 @@
#include "sdhci-pltfm.h"
+#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
+#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
+
+struct sdhci_tegra_soc_data {
+ struct sdhci_pltfm_data *pdata;
+ u32 nvquirks;
+};
+
+struct sdhci_tegra {
+ const struct tegra_sdhci_platform_data *plat;
+ const struct sdhci_tegra_soc_data *soc_data;
+};
+
static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
{
u32 val;
@@ -46,7 +60,12 @@ static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
{
- if (unlikely(reg == SDHCI_HOST_VERSION)) {
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+
+ if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) &&
+ (reg == SDHCI_HOST_VERSION))) {
/* Erratum: Version register is invalid in HW. */
return SDHCI_SPEC_200;
}
@@ -56,6 +75,10 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+
/* Seems like we're getting spurious timeout and crc errors, so
* disable signalling of them. In case of real errors software
* timers should take care of eventually detecting them.
@@ -65,7 +88,8 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
writel(val, host->ioaddr + reg);
- if (unlikely(reg == SDHCI_INT_ENABLE)) {
+ if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) &&
+ (reg == SDHCI_INT_ENABLE))) {
/* Erratum: Must enable block gap interrupt detection */
u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
if (val & SDHCI_INT_CARD_INT)
@@ -76,10 +100,11 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
}
}
-static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
+static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
- struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
if (!gpio_is_valid(plat->wp_gpio))
return -1;
@@ -98,7 +123,8 @@ static irqreturn_t carddetect_irq(int irq, void *data)
static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
u32 ctrl;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
@@ -124,16 +150,44 @@ static struct sdhci_ops tegra_sdhci_ops = {
.platform_8bit_width = tegra_sdhci_8bit,
};
-static struct sdhci_pltfm_data sdhci_tegra_pdata = {
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
+ .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_NO_HISPD_BIT |
+ SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+ .ops = &tegra_sdhci_ops,
+};
+
+static struct sdhci_tegra_soc_data soc_data_tegra20 = {
+ .pdata = &sdhci_tegra20_pdata,
+ .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
+ NVQUIRK_ENABLE_BLOCK_GAP_DET,
+};
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+static struct sdhci_pltfm_data sdhci_tegra30_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
.ops = &tegra_sdhci_ops,
};
+static struct sdhci_tegra_soc_data soc_data_tegra30 = {
+ .pdata = &sdhci_tegra30_pdata,
+};
+#endif
+
static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = {
- { .compatible = "nvidia,tegra20-sdhci", },
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
+#endif
{}
};
MODULE_DEVICE_TABLE(of, sdhci_dt_ids);
@@ -164,13 +218,22 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
{
+ const struct of_device_id *match;
+ const struct sdhci_tegra_soc_data *soc_data;
+ struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct tegra_sdhci_platform_data *plat;
- struct sdhci_host *host;
+ struct sdhci_tegra *tegra_host;
struct clk *clk;
int rc;
- host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata);
+ match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
+ if (match)
+ soc_data = match->data;
+ else
+ soc_data = &soc_data_tegra20;
+
+ host = sdhci_pltfm_init(pdev, soc_data->pdata);
if (IS_ERR(host))
return PTR_ERR(host);
@@ -187,7 +250,17 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
goto err_no_plat;
}
- pltfm_host->priv = plat;
+ tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL);
+ if (!tegra_host) {
+ dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n");
+ rc = -ENOMEM;
+ goto err_no_plat;
+ }
+
+ tegra_host->plat = plat;
+ tegra_host->soc_data = soc_data;
+
+ pltfm_host->priv = tegra_host;
if (gpio_is_valid(plat->power_gpio)) {
rc = gpio_request(plat->power_gpio, "sdhci_power");
@@ -283,7 +356,8 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
@@ -326,5 +400,5 @@ static struct platform_driver sdhci_tegra_driver = {
module_platform_driver(sdhci_tegra_driver);
MODULE_DESCRIPTION("SDHCI driver for Tegra");
-MODULE_AUTHOR(" Google, Inc.");
+MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8d66706824a6..8262cadfdab7 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2267,8 +2267,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
{
irqreturn_t result;
struct sdhci_host *host = dev_id;
- u32 intmask;
- int cardint = 0;
+ u32 intmask, unexpected = 0;
+ int cardint = 0, max_loops = 16;
spin_lock(&host->lock);
@@ -2286,6 +2286,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
goto out;
}
+again:
DBG("*** %s got interrupt: 0x%08x\n",
mmc_hostname(host->mmc), intmask);
@@ -2344,19 +2345,23 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask &= ~SDHCI_INT_CARD_INT;
if (intmask) {
- pr_err("%s: Unexpected interrupt 0x%08x.\n",
- mmc_hostname(host->mmc), intmask);
- sdhci_dumpregs(host);
-
+ unexpected |= intmask;
sdhci_writel(host, intmask, SDHCI_INT_STATUS);
}
result = IRQ_HANDLED;
- mmiowb();
+ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+ if (intmask && --max_loops)
+ goto again;
out:
spin_unlock(&host->lock);
+ if (unexpected) {
+ pr_err("%s: Unexpected interrupt 0x%08x.\n",
+ mmc_hostname(host->mmc), unexpected);
+ sdhci_dumpregs(host);
+ }
/*
* We have to delay this as it calls back into the driver.
*/
@@ -2379,6 +2384,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
int ret;
bool has_tuning_timer;
+ if (host->ops->platform_suspend)
+ host->ops->platform_suspend(host);
+
sdhci_disable_card_detection(host);
/* Disable tuning since we are suspending */
@@ -2423,12 +2431,24 @@ int sdhci_resume_host(struct sdhci_host *host)
if (ret)
return ret;
- sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
- mmiowb();
+ if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) &&
+ (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
+ /* Card keeps power but host controller does not */
+ sdhci_init(host, 0);
+ host->pwr = 0;
+ host->clock = 0;
+ sdhci_do_set_ios(host, &host->mmc->ios);
+ } else {
+ sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
+ mmiowb();
+ }
ret = mmc_resume_host(host->mmc);
sdhci_enable_card_detection(host);
+ if (host->ops->platform_resume)
+ host->ops->platform_resume(host);
+
/* Set the re-tuning expiration flag */
if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
(host->tuning_mode == SDHCI_TUNING_MODE_1))
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index ad265b96b75b..f761f23d2a28 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -275,6 +275,8 @@ struct sdhci_ops {
void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*hw_reset)(struct sdhci_host *host);
+ void (*platform_suspend)(struct sdhci_host *host);
+ void (*platform_resume)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 75a485448796..aafaf0b6eb1c 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -286,7 +286,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
DMA_FROM_DEVICE);
if (ret > 0) {
host->dma_active = true;
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
}
@@ -335,7 +335,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
DMA_TO_DEVICE);
if (ret > 0) {
host->dma_active = true;
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
}
@@ -746,7 +746,6 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
case MMC_SET_WRITE_PROT:
case MMC_CLR_WRITE_PROT:
case MMC_ERASE:
- case MMC_GEN_CMD:
tmp |= CMD_SET_RBSY;
break;
}
@@ -829,7 +828,6 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
case MMC_SET_WRITE_PROT:
case MMC_CLR_WRITE_PROT:
case MMC_ERASE:
- case MMC_GEN_CMD:
mask = MASK_START_CMD | MASK_MRBSYE;
break;
default:
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 58da3c44acc5..934b68e9efc3 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -90,6 +90,15 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
return 0;
}
+static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
+{
+ mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100));
+}
+
+static const struct sh_mobile_sdhi_ops sdhi_ops = {
+ .cd_wakeup = sh_mobile_sdhi_cd_wakeup,
+};
+
static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
{
struct sh_mobile_sdhi *priv;
@@ -109,6 +118,12 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data = &priv->mmc_data;
p->pdata = mmc_data;
+ if (p->init) {
+ ret = p->init(pdev, &sdhi_ops);
+ if (ret)
+ goto einit;
+ }
+
snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
priv->clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(priv->clk)) {
@@ -117,8 +132,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
goto eclkget;
}
- clk_enable(priv->clk);
-
mmc_data->hclk = clk_get_rate(priv->clk);
mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
mmc_data->get_cd = sh_mobile_sdhi_get_cd;
@@ -129,6 +142,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->ocr_mask = p->tmio_ocr_mask;
mmc_data->capabilities |= p->tmio_caps;
+ mmc_data->cd_gpio = p->cd_gpio;
if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
priv->param_tx.slave_id = p->dma_slave_tx;
@@ -211,7 +225,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
mmc_hostname(host->mmc), (unsigned long)
- (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start),
+ (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
mmc_data->hclk / 1000000);
return ret;
@@ -232,9 +246,11 @@ eirq_sdio:
eirq_card_detect:
tmio_mmc_host_remove(host);
eprobe:
- clk_disable(priv->clk);
clk_put(priv->clk);
eclkget:
+ if (p->cleanup)
+ p->cleanup(pdev);
+einit:
kfree(priv);
return ret;
}
@@ -258,8 +274,11 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
free_irq(irq, host);
}
- clk_disable(priv->clk);
clk_put(priv->clk);
+
+ if (p->cleanup)
+ p->cleanup(pdev);
+
kfree(priv);
return 0;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index f96c536d130a..d857f5c6e7d9 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -47,16 +47,14 @@ struct tmio_mmc_host {
struct mmc_request *mrq;
struct mmc_data *data;
struct mmc_host *mmc;
- unsigned int sdio_irq_enabled;
+
+ /* Controller power state */
+ bool power;
/* Callbacks for clock / power control */
void (*set_pwr)(struct platform_device *host, int state);
void (*set_clk_div)(struct platform_device *host, int state);
- int pm_error;
- /* recognise system-wide suspend in runtime PM methods */
- bool pm_global;
-
/* pio related stuff */
struct scatterlist *sg_ptr;
struct scatterlist *sg_orig;
@@ -86,6 +84,7 @@ struct tmio_mmc_host {
spinlock_t lock; /* protect host private data */
unsigned long last_req_ts;
struct mutex ios_lock; /* protect set_ios() context */
+ bool native_hotplug;
};
int tmio_mmc_host_probe(struct tmio_mmc_host **host,
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
index 8253ec12003e..fff928604859 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -88,7 +88,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
if (ret > 0)
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_DEV_TO_MEM, DMA_CTRL_ACK);
if (desc) {
@@ -169,7 +169,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
if (ret > 0)
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ desc = dmaengine_prep_slave_sg(chan, sg, ret,
DMA_MEM_TO_DEV, DMA_CTRL_ACK);
if (desc) {
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index e21988901c36..9a7996ade58e 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -34,6 +34,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/mfd/tmio.h>
+#include <linux/mmc/cd-gpio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/tmio.h>
#include <linux/module.h>
@@ -127,7 +128,6 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
struct tmio_mmc_host *host = mmc_priv(mmc);
if (enable) {
- host->sdio_irq_enabled = 1;
host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
~TMIO_SDIO_STAT_IOIRQ;
sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
@@ -136,7 +136,6 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
- host->sdio_irq_enabled = 0;
}
}
@@ -304,6 +303,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
{
struct mmc_data *data = host->data;
int c = cmd->opcode;
+ u32 irq_mask = TMIO_MASK_CMD;
/* Command 12 is handled by hardware */
if (cmd->opcode == 12 && !cmd->arg) {
@@ -339,7 +339,9 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
c |= TRANSFER_READ;
}
- tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_CMD);
+ if (!host->native_hotplug)
+ irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
+ tmio_mmc_enable_mmc_irqs(host, irq_mask);
/* Fire off the command */
sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
@@ -758,7 +760,7 @@ fail:
static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
- struct tmio_mmc_data *pdata = host->pdata;
+ struct device *dev = &host->pdev->dev;
unsigned long flags;
mutex_lock(&host->ios_lock);
@@ -766,13 +768,13 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_lock_irqsave(&host->lock, flags);
if (host->mrq) {
if (IS_ERR(host->mrq)) {
- dev_dbg(&host->pdev->dev,
+ dev_dbg(dev,
"%s.%d: concurrent .set_ios(), clk %u, mode %u\n",
current->comm, task_pid_nr(current),
ios->clock, ios->power_mode);
host->mrq = ERR_PTR(-EINTR);
} else {
- dev_dbg(&host->pdev->dev,
+ dev_dbg(dev,
"%s.%d: CMD%u active since %lu, now %lu!\n",
current->comm, task_pid_nr(current),
host->mrq->cmd->opcode, host->last_req_ts, jiffies);
@@ -788,13 +790,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_unlock_irqrestore(&host->lock, flags);
/*
- * pdata->power == false only if COLD_CD is available, otherwise only
- * in short time intervals during probing or resuming
+ * host->power toggles between false and true in both cases - either
+ * or not the controller can be runtime-suspended during inactivity.
+ * But if the controller has to be kept on, the runtime-pm usage_count
+ * is kept positive, so no suspending actually takes place.
*/
if (ios->power_mode == MMC_POWER_ON && ios->clock) {
- if (!pdata->power) {
- pm_runtime_get_sync(&host->pdev->dev);
- pdata->power = true;
+ if (!host->power) {
+ pm_runtime_get_sync(dev);
+ host->power = true;
}
tmio_mmc_set_clock(host, ios->clock);
/* power up SD bus */
@@ -805,9 +809,9 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
} else if (ios->power_mode != MMC_POWER_UP) {
if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
host->set_pwr(host->pdev, 0);
- if (pdata->power) {
- pdata->power = false;
- pm_runtime_put(&host->pdev->dev);
+ if (host->power) {
+ host->power = false;
+ pm_runtime_put(dev);
}
tmio_mmc_clk_stop(host);
}
@@ -913,7 +917,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- pdata->power = false;
+ _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
+ mmc->caps & MMC_CAP_NEEDS_POLL ||
+ mmc->caps & MMC_CAP_NONREMOVABLE);
+
+ _host->power = false;
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume(&pdev->dev);
if (ret < 0)
@@ -926,14 +934,13 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
* 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL
* 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE
*
- * While we increment the rtpm counter for all scenarios when the mmc
- * core activates us by calling an appropriate set_ios(), we must
+ * While we increment the runtime PM counter for all scenarios when
+ * the mmc core activates us by calling an appropriate set_ios(), we
+ * must additionally ensure that in case 2) the tmio mmc hardware stays
* additionally ensure that in case 2) the tmio mmc hardware stays
* powered on during runtime for the card detection to work.
*/
- if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD
- || mmc->caps & MMC_CAP_NEEDS_POLL
- || mmc->caps & MMC_CAP_NONREMOVABLE))
+ if (_host->native_hotplug)
pm_runtime_get_noresume(&pdev->dev);
tmio_mmc_clk_stop(_host);
@@ -963,9 +970,19 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
irq_mask |= TMIO_MASK_READOP;
if (!_host->chan_tx)
irq_mask |= TMIO_MASK_WRITEOP;
+ if (!_host->native_hotplug)
+ irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
tmio_mmc_enable_mmc_irqs(_host, irq_mask);
+ if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
+ ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio);
+ if (ret < 0) {
+ tmio_mmc_host_remove(_host);
+ return ret;
+ }
+ }
+
*host = _host;
return 0;
@@ -983,22 +1000,22 @@ EXPORT_SYMBOL(tmio_mmc_host_probe);
void tmio_mmc_host_remove(struct tmio_mmc_host *host)
{
struct platform_device *pdev = host->pdev;
+ struct tmio_mmc_data *pdata = host->pdata;
+ struct mmc_host *mmc = host->mmc;
- /*
- * We don't have to manipulate pdata->power here: if there is a card in
- * the slot, the runtime PM is active and our .runtime_resume() will not
- * be run. If there is no card in the slot and the platform can suspend
- * the controller, the runtime PM is suspended and pdata->power == false,
- * so, our .runtime_resume() will not try to detect a card in the slot.
- */
- if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD
- || host->mmc->caps & MMC_CAP_NEEDS_POLL
- || host->mmc->caps & MMC_CAP_NONREMOVABLE)
+ if (pdata->flags & TMIO_MMC_USE_GPIO_CD)
+ /*
+ * This means we can miss a card-eject, but this is anyway
+ * possible, because of delayed processing of hotplug events.
+ */
+ mmc_cd_gpio_free(mmc);
+
+ if (!host->native_hotplug)
pm_runtime_get_sync(&pdev->dev);
dev_pm_qos_hide_latency_limit(&pdev->dev);
- mmc_remove_host(host->mmc);
+ mmc_remove_host(mmc);
cancel_work_sync(&host->done);
cancel_delayed_work_sync(&host->delayed_reset_work);
tmio_mmc_release_dma(host);
@@ -1007,7 +1024,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
pm_runtime_disable(&pdev->dev);
iounmap(host->ctl);
- mmc_free_host(host->mmc);
+ mmc_free_host(mmc);
}
EXPORT_SYMBOL(tmio_mmc_host_remove);
@@ -1021,8 +1038,6 @@ int tmio_mmc_host_suspend(struct device *dev)
if (!ret)
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
- host->pm_error = pm_runtime_put_sync(dev);
-
return ret;
}
EXPORT_SYMBOL(tmio_mmc_host_suspend);
@@ -1032,20 +1047,10 @@ int tmio_mmc_host_resume(struct device *dev)
struct mmc_host *mmc = dev_get_drvdata(dev);
struct tmio_mmc_host *host = mmc_priv(mmc);
- /* The MMC core will perform the complete set up */
- host->pdata->power = false;
-
- host->pm_global = true;
- if (!host->pm_error)
- pm_runtime_get_sync(dev);
-
- if (host->pm_global) {
- /* Runtime PM resume callback didn't run */
- tmio_mmc_reset(host);
- tmio_mmc_enable_dma(host, true);
- host->pm_global = false;
- }
+ tmio_mmc_reset(host);
+ tmio_mmc_enable_dma(host, true);
+ /* The MMC core will perform the complete set up */
return mmc_resume_host(mmc);
}
EXPORT_SYMBOL(tmio_mmc_host_resume);
@@ -1062,19 +1067,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct tmio_mmc_host *host = mmc_priv(mmc);
- struct tmio_mmc_data *pdata = host->pdata;
tmio_mmc_reset(host);
tmio_mmc_enable_dma(host, true);
- if (pdata->power) {
- /* Only entered after a card-insert interrupt */
- if (!mmc->card)
- tmio_mmc_set_ios(mmc, &mmc->ios);
- mmc_detect_change(mmc, msecs_to_jiffies(100));
- }
- host->pm_global = false;
-
return 0;
}
EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index ecff765579dd..5d53c5760a6c 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -93,7 +93,6 @@
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/pci.h>
#include <linux/mtd/mtd.h>
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index e585263161b9..288594163c22 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -42,7 +42,6 @@
#include <linux/ioctl.h>
#include <linux/init.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/mtd/mtd.h>
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index e8e9fec23553..0259cf583022 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -14,7 +14,6 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 35b4fb55dbd6..ae7e37d9ac17 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -27,6 +27,10 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
@@ -34,22 +38,10 @@
#include <linux/dmaengine.h>
#include <linux/gpio.h>
#include <linux/io.h>
+#include <linux/platform_data/atmel.h>
-#include <mach/board.h>
#include <mach/cpu.h>
-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
-#define hard_ecc 1
-#else
-#define hard_ecc 0
-#endif
-
-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE
-#define no_ecc 1
-#else
-#define no_ecc 0
-#endif
-
static int use_dma = 1;
module_param(use_dma, int, 0);
@@ -95,7 +87,7 @@ struct atmel_nand_host {
struct mtd_info mtd;
void __iomem *io_base;
dma_addr_t io_phys;
- struct atmel_nand_data *board;
+ struct atmel_nand_data board;
struct device *dev;
void __iomem *ecc;
@@ -113,8 +105,8 @@ static int cpu_has_dma(void)
*/
static void atmel_nand_enable(struct atmel_nand_host *host)
{
- if (gpio_is_valid(host->board->enable_pin))
- gpio_set_value(host->board->enable_pin, 0);
+ if (gpio_is_valid(host->board.enable_pin))
+ gpio_set_value(host->board.enable_pin, 0);
}
/*
@@ -122,8 +114,8 @@ static void atmel_nand_enable(struct atmel_nand_host *host)
*/
static void atmel_nand_disable(struct atmel_nand_host *host)
{
- if (gpio_is_valid(host->board->enable_pin))
- gpio_set_value(host->board->enable_pin, 1);
+ if (gpio_is_valid(host->board.enable_pin))
+ gpio_set_value(host->board.enable_pin, 1);
}
/*
@@ -144,9 +136,9 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
return;
if (ctrl & NAND_CLE)
- writeb(cmd, host->io_base + (1 << host->board->cle));
+ writeb(cmd, host->io_base + (1 << host->board.cle));
else
- writeb(cmd, host->io_base + (1 << host->board->ale));
+ writeb(cmd, host->io_base + (1 << host->board.ale));
}
/*
@@ -157,8 +149,8 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
struct nand_chip *nand_chip = mtd->priv;
struct atmel_nand_host *host = nand_chip->priv;
- return gpio_get_value(host->board->rdy_pin) ^
- !!host->board->rdy_pin_active_low;
+ return gpio_get_value(host->board.rdy_pin) ^
+ !!host->board.rdy_pin_active_low;
}
/*
@@ -273,7 +265,7 @@ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
return;
- if (host->board->bus_width_16)
+ if (host->board.bus_width_16)
atmel_read_buf16(mtd, buf, len);
else
atmel_read_buf8(mtd, buf, len);
@@ -289,7 +281,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
return;
- if (host->board->bus_width_16)
+ if (host->board.bus_width_16)
atmel_write_buf16(mtd, buf, len);
else
atmel_write_buf8(mtd, buf, len);
@@ -481,6 +473,56 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
}
}
+#if defined(CONFIG_OF)
+static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ struct device_node *np)
+{
+ u32 val;
+ int ecc_mode;
+ struct atmel_nand_data *board = &host->board;
+ enum of_gpio_flags flags;
+
+ if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
+ if (val >= 32) {
+ dev_err(host->dev, "invalid addr-offset %u\n", val);
+ return -EINVAL;
+ }
+ board->ale = val;
+ }
+
+ if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) {
+ if (val >= 32) {
+ dev_err(host->dev, "invalid cmd-offset %u\n", val);
+ return -EINVAL;
+ }
+ board->cle = val;
+ }
+
+ ecc_mode = of_get_nand_ecc_mode(np);
+
+ board->ecc_mode = ecc_mode < 0 ? NAND_ECC_SOFT : ecc_mode;
+
+ board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
+
+ if (of_get_nand_bus_width(np) == 16)
+ board->bus_width_16 = 1;
+
+ board->rdy_pin = of_get_gpio_flags(np, 0, &flags);
+ board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW);
+
+ board->enable_pin = of_get_gpio(np, 1);
+ board->det_pin = of_get_gpio(np, 2);
+
+ return 0;
+}
+#else
+static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ struct device_node *np)
+{
+ return -EINVAL;
+}
+#endif
+
/*
* Probe for the NAND device.
*/
@@ -491,6 +533,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
struct nand_chip *nand_chip;
struct resource *regs;
struct resource *mem;
+ struct mtd_part_parser_data ppdata = {};
int res;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -517,8 +560,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
mtd = &host->mtd;
nand_chip = &host->nand_chip;
- host->board = pdev->dev.platform_data;
host->dev = &pdev->dev;
+ if (pdev->dev.of_node) {
+ res = atmel_of_init_port(host, pdev->dev.of_node);
+ if (res)
+ goto err_nand_ioremap;
+ } else {
+ memcpy(&host->board, pdev->dev.platform_data,
+ sizeof(struct atmel_nand_data));
+ }
nand_chip->priv = host; /* link the private data structures */
mtd->priv = nand_chip;
@@ -529,26 +579,25 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
nand_chip->IO_ADDR_W = host->io_base;
nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
- if (gpio_is_valid(host->board->rdy_pin))
+ if (gpio_is_valid(host->board.rdy_pin))
nand_chip->dev_ready = atmel_nand_device_ready;
+ nand_chip->ecc.mode = host->board.ecc_mode;
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!regs && hard_ecc) {
+ if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
printk(KERN_ERR "atmel_nand: can't get I/O resource "
"regs\nFalling back on software ECC\n");
+ nand_chip->ecc.mode = NAND_ECC_SOFT;
}
- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
- if (no_ecc)
- nand_chip->ecc.mode = NAND_ECC_NONE;
- if (hard_ecc && regs) {
+ if (nand_chip->ecc.mode == NAND_ECC_HW) {
host->ecc = ioremap(regs->start, resource_size(regs));
if (host->ecc == NULL) {
printk(KERN_ERR "atmel_nand: ioremap failed\n");
res = -EIO;
goto err_ecc_ioremap;
}
- nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.calculate = atmel_nand_calculate;
nand_chip->ecc.correct = atmel_nand_correct;
nand_chip->ecc.hwctl = atmel_nand_hwctl;
@@ -558,7 +607,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
nand_chip->chip_delay = 20; /* 20us command delay time */
- if (host->board->bus_width_16) /* 16-bit bus width */
+ if (host->board.bus_width_16) /* 16-bit bus width */
nand_chip->options |= NAND_BUSWIDTH_16;
nand_chip->read_buf = atmel_read_buf;
@@ -567,15 +616,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
atmel_nand_enable(host);
- if (gpio_is_valid(host->board->det_pin)) {
- if (gpio_get_value(host->board->det_pin)) {
+ if (gpio_is_valid(host->board.det_pin)) {
+ if (gpio_get_value(host->board.det_pin)) {
printk(KERN_INFO "No SmartMedia card inserted.\n");
res = -ENXIO;
goto err_no_card;
}
}
- if (on_flash_bbt) {
+ if (host->board.on_flash_bbt || on_flash_bbt) {
printk(KERN_INFO "atmel_nand: Use On Flash BBT\n");
nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
}
@@ -650,8 +699,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
}
mtd->name = "atmel_nand";
- res = mtd_device_parse_register(mtd, NULL, 0,
- host->board->parts, host->board->num_parts);
+ ppdata.of_node = pdev->dev.of_node;
+ res = mtd_device_parse_register(mtd, NULL, &ppdata,
+ host->board.parts, host->board.num_parts);
if (!res)
return res;
@@ -695,11 +745,21 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
return 0;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_nand_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-nand" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
+#endif
+
static struct platform_driver atmel_nand_driver = {
.remove = __exit_p(atmel_nand_remove),
.driver = {
.name = "atmel_nand",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(atmel_nand_dt_ids),
},
};
diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c
index 50387fd4009b..64c9cbaf86a1 100644
--- a/drivers/mtd/nand/bcm_umi_nand.c
+++ b/drivers/mtd/nand/bcm_umi_nand.c
@@ -31,7 +31,6 @@
#include <linux/mtd/partitions.h>
#include <asm/mach-types.h>
-#include <asm/system.h>
#include <mach/reg_nand.h>
#include <mach/reg_umi.h>
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 7db6555ed3ba..590dd5cceed6 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -835,7 +835,7 @@ int gpmi_send_command(struct gpmi_nand_data *this)
| BM_GPMI_CTRL0_ADDRESS_INCREMENT
| BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
pio[1] = pio[2] = 0;
- desc = channel->device->device_prep_slave_sg(channel,
+ desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
if (!desc) {
@@ -848,8 +848,7 @@ int gpmi_send_command(struct gpmi_nand_data *this)
sg_init_one(sgl, this->cmd_buffer, this->command_length);
dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
- desc = channel->device->device_prep_slave_sg(channel,
- sgl, 1, DMA_MEM_TO_DEV, 1);
+ desc = dmaengine_prep_slave_sg(channel, sgl, 1, DMA_MEM_TO_DEV, 1);
if (!desc) {
pr_err("step 2 error\n");
return -1;
@@ -880,8 +879,7 @@ int gpmi_send_data(struct gpmi_nand_data *this)
| BF_GPMI_CTRL0_ADDRESS(address)
| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
pio[1] = 0;
- desc = channel->device->device_prep_slave_sg(channel,
- (struct scatterlist *)pio,
+ desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
if (!desc) {
pr_err("step 1 error\n");
@@ -890,7 +888,7 @@ int gpmi_send_data(struct gpmi_nand_data *this)
/* [2] send DMA request */
prepare_data_dma(this, DMA_TO_DEVICE);
- desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
+ desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
1, DMA_MEM_TO_DEV, 1);
if (!desc) {
pr_err("step 2 error\n");
@@ -916,7 +914,7 @@ int gpmi_read_data(struct gpmi_nand_data *this)
| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
pio[1] = 0;
- desc = channel->device->device_prep_slave_sg(channel,
+ desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
if (!desc) {
@@ -926,8 +924,8 @@ int gpmi_read_data(struct gpmi_nand_data *this)
/* [2] : send DMA request */
prepare_data_dma(this, DMA_FROM_DEVICE);
- desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
- 1, DMA_DEV_TO_MEM, 1);
+ desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
+ 1, DMA_DEV_TO_MEM, 1);
if (!desc) {
pr_err("step 2 error\n");
return -1;
@@ -972,8 +970,7 @@ int gpmi_send_page(struct gpmi_nand_data *this,
pio[4] = payload;
pio[5] = auxiliary;
- desc = channel->device->device_prep_slave_sg(channel,
- (struct scatterlist *)pio,
+ desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
if (!desc) {
pr_err("step 2 error\n");
@@ -1007,7 +1004,7 @@ int gpmi_read_page(struct gpmi_nand_data *this,
| BF_GPMI_CTRL0_ADDRESS(address)
| BF_GPMI_CTRL0_XFER_COUNT(0);
pio[1] = 0;
- desc = channel->device->device_prep_slave_sg(channel,
+ desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio, 2,
DMA_TRANS_NONE, 0);
if (!desc) {
@@ -1036,7 +1033,7 @@ int gpmi_read_page(struct gpmi_nand_data *this,
pio[3] = geo->page_size;
pio[4] = payload;
pio[5] = auxiliary;
- desc = channel->device->device_prep_slave_sg(channel,
+ desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 1);
if (!desc) {
@@ -1055,7 +1052,7 @@ int gpmi_read_page(struct gpmi_nand_data *this,
| BF_GPMI_CTRL0_ADDRESS(address)
| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
pio[1] = 0;
- desc = channel->device->device_prep_slave_sg(channel,
+ desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio, 2,
DMA_TRANS_NONE, 1);
if (!desc) {
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 9abd4eb86dc1..dd5e04813b76 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -70,7 +70,6 @@ static const char *version =
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 6057b30417a2..0910dce3996d 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -229,7 +229,6 @@ static int dma;
#include <linux/bitops.h>
#include <linux/gfp.h>
-#include <asm/system.h>
#include <asm/dma.h>
#include <asm/io.h>
diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c
index 980e65c14936..5bed4c4e2508 100644
--- a/drivers/net/arcnet/com20020_cs.c
+++ b/drivers/net/arcnet/com20020_cs.c
@@ -47,7 +47,6 @@
#include <pcmcia/ds.h>
#include <asm/io.h>
-#include <asm/system.h>
#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b920d829692a..0c76186bb9e7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -54,7 +54,6 @@
#include <linux/inet.h>
#include <linux/bitops.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <asm/dma.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 98a5a7d867f5..034c16b60e96 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -40,7 +40,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/string.h>
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7cb2785e209d..ec03b401620a 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -35,7 +35,6 @@
#include <asm/io.h> /* CRIS_LED_* I/O functions */
#include <asm/irq.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/ethernet.h>
#include <asm/cache.h>
#include <arch/io_interface_mux.h>
diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c
index e61b2f82ba3a..66df93638085 100644
--- a/drivers/net/ethernet/3com/3c574_cs.c
+++ b/drivers/net/ethernet/3com/3c574_cs.c
@@ -95,7 +95,6 @@ earlier 3Com products.
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/system.h>
/*====================================================================*/
diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c
index b23253b9f742..a556c01e011b 100644
--- a/drivers/net/ethernet/3com/3c589_cs.c
+++ b/drivers/net/ethernet/3com/3c589_cs.c
@@ -50,7 +50,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/system.h>
/* To minimize the size of the driver source I only define operating
constants if they are used several times. You'll need the manual
diff --git a/drivers/net/ethernet/8390/3c503.c b/drivers/net/ethernet/8390/3c503.c
index fbab1367505f..49d76bd0dc86 100644
--- a/drivers/net/ethernet/8390/3c503.c
+++ b/drivers/net/ethernet/8390/3c503.c
@@ -54,7 +54,6 @@ static const char version[] =
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/ac3200.c b/drivers/net/ethernet/8390/ac3200.c
index 5337dd0a59b0..ccf07942ff6e 100644
--- a/drivers/net/ethernet/8390/ac3200.c
+++ b/drivers/net/ethernet/8390/ac3200.c
@@ -34,7 +34,6 @@ static const char version[] =
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/ethernet/8390/apne.c b/drivers/net/ethernet/8390/apne.c
index 3ad5d2f9a49c..923959275a82 100644
--- a/drivers/net/ethernet/8390/apne.c
+++ b/drivers/net/ethernet/8390/apne.c
@@ -39,7 +39,6 @@
#include <linux/interrupt.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/setup.h>
#include <asm/amigaints.h>
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index c30adcc9828a..11476ca95e93 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -31,7 +31,6 @@
#include <net/ax88796.h>
-#include <asm/system.h>
/* Rename the lib8390.c functions to show that they are in this driver */
#define __ei_open ax_ei_open
diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
index c5bd8eb7a9f5..e1b3941bd149 100644
--- a/drivers/net/ethernet/8390/axnet_cs.c
+++ b/drivers/net/ethernet/8390/axnet_cs.c
@@ -46,7 +46,6 @@
#include <pcmcia/cisreg.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/8390/e2100.c b/drivers/net/ethernet/8390/e2100.c
index d16dc53c1813..ed55ce85ebbf 100644
--- a/drivers/net/ethernet/8390/e2100.c
+++ b/drivers/net/ethernet/8390/e2100.c
@@ -48,7 +48,6 @@ static const char version[] =
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/es3210.c b/drivers/net/ethernet/8390/es3210.c
index 6428f9e7a554..ba1b5c95531f 100644
--- a/drivers/net/ethernet/8390/es3210.c
+++ b/drivers/net/ethernet/8390/es3210.c
@@ -59,7 +59,6 @@ static const char version[] =
#include <linux/etherdevice.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c
index 48c4948750d1..dbefd5658c14 100644
--- a/drivers/net/ethernet/8390/etherh.c
+++ b/drivers/net/ethernet/8390/etherh.c
@@ -45,9 +45,9 @@
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/ecard.h>
#include <asm/io.h>
+#include <asm/system_info.h>
#define EI_SHIFT(x) (ei_local->reg_offset[x])
diff --git a/drivers/net/ethernet/8390/hp-plus.c b/drivers/net/ethernet/8390/hp-plus.c
index d42938b6b596..52f70f999c00 100644
--- a/drivers/net/ethernet/8390/hp-plus.c
+++ b/drivers/net/ethernet/8390/hp-plus.c
@@ -33,7 +33,6 @@ static const char version[] =
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <asm/system.h>
#include <asm/io.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/hp.c b/drivers/net/ethernet/8390/hp.c
index 113f1e075a26..37fa89aa4578 100644
--- a/drivers/net/ethernet/8390/hp.c
+++ b/drivers/net/ethernet/8390/hp.c
@@ -33,7 +33,6 @@ static const char version[] =
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <asm/system.h>
#include <asm/io.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/lib8390.c b/drivers/net/ethernet/8390/lib8390.c
index e77f624e8194..b329f5c0d62b 100644
--- a/drivers/net/ethernet/8390/lib8390.c
+++ b/drivers/net/ethernet/8390/lib8390.c
@@ -57,7 +57,6 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/ethernet/8390/lne390.c b/drivers/net/ethernet/8390/lne390.c
index 69490ae018ea..479409bf2e3c 100644
--- a/drivers/net/ethernet/8390/lne390.c
+++ b/drivers/net/ethernet/8390/lne390.c
@@ -46,7 +46,6 @@ static const char *version =
#include <linux/etherdevice.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c
index af5d9822cad9..88ccc8b14f0a 100644
--- a/drivers/net/ethernet/8390/mac8390.c
+++ b/drivers/net/ethernet/8390/mac8390.c
@@ -37,7 +37,6 @@
#include <linux/bitops.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <asm/dma.h>
#include <asm/hwtest.h>
#include <asm/macints.h>
diff --git a/drivers/net/ethernet/8390/ne-h8300.c b/drivers/net/ethernet/8390/ne-h8300.c
index 9b9c77d5a65c..7fc28f2d28a6 100644
--- a/drivers/net/ethernet/8390/ne-h8300.c
+++ b/drivers/net/ethernet/8390/ne-h8300.c
@@ -29,7 +29,6 @@ static const char version1[] =
#include <linux/etherdevice.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c
index f92ea2a65a57..d04911d33b64 100644
--- a/drivers/net/ethernet/8390/ne.c
+++ b/drivers/net/ethernet/8390/ne.c
@@ -53,7 +53,6 @@ static const char version2[] =
#include <linux/jiffies.h>
#include <linux/platform_device.h>
-#include <asm/system.h>
#include <asm/io.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/ne2.c b/drivers/net/ethernet/8390/ne2.c
index 922b32036c63..ef85839f43d8 100644
--- a/drivers/net/ethernet/8390/ne2.c
+++ b/drivers/net/ethernet/8390/ne2.c
@@ -76,7 +76,6 @@ static const char *version = "ne2.c:v0.91 Nov 16 1998 Wim Dumon <wimpie@kotnet.o
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c
index 3fab04a0034a..5e8845febfb8 100644
--- a/drivers/net/ethernet/8390/ne2k-pci.c
+++ b/drivers/net/ethernet/8390/ne2k-pci.c
@@ -54,7 +54,6 @@ static int options[MAX_UNITS];
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/8390/ne3210.c b/drivers/net/ethernet/8390/ne3210.c
index 2a3e8057feae..a2f8b2b8e27c 100644
--- a/drivers/net/ethernet/8390/ne3210.c
+++ b/drivers/net/ethernet/8390/ne3210.c
@@ -39,7 +39,6 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
index f2a4e5de18c4..de1af0bfed4c 100644
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ b/drivers/net/ethernet/8390/pcnet_cs.c
@@ -49,7 +49,6 @@
#include <pcmcia/cisreg.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/8390/smc-mca.c b/drivers/net/ethernet/8390/smc-mca.c
index 77efec44fea0..7a68590f2804 100644
--- a/drivers/net/ethernet/8390/smc-mca.c
+++ b/drivers/net/ethernet/8390/smc-mca.c
@@ -47,7 +47,6 @@
#include <linux/etherdevice.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c
index 1cc306a83ff7..b0fbce39661a 100644
--- a/drivers/net/ethernet/8390/smc-ultra.c
+++ b/drivers/net/ethernet/8390/smc-ultra.c
@@ -69,7 +69,6 @@ static const char version[] =
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/smc-ultra32.c b/drivers/net/ethernet/8390/smc-ultra32.c
index bb87053eb3da..923e42aedcfd 100644
--- a/drivers/net/ethernet/8390/smc-ultra32.c
+++ b/drivers/net/ethernet/8390/smc-ultra32.c
@@ -57,7 +57,6 @@ static const char *version = "smc-ultra32.c: 06/97 v1.00\n";
#include <linux/etherdevice.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c
index 3b903759980a..8df4c4157230 100644
--- a/drivers/net/ethernet/8390/stnic.c
+++ b/drivers/net/ethernet/8390/stnic.c
@@ -17,7 +17,6 @@
#include <linux/init.h>
#include <linux/delay.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <mach-se/mach/se.h>
#include <asm/machvec.h>
diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c
index c175fadb597b..03eb3eed49fa 100644
--- a/drivers/net/ethernet/8390/wd.c
+++ b/drivers/net/ethernet/8390/wd.c
@@ -39,7 +39,6 @@ static const char version[] =
#include <linux/etherdevice.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "8390.h"
diff --git a/drivers/net/ethernet/8390/zorro8390.c b/drivers/net/ethernet/8390/zorro8390.c
index bcd27323b203..7818e6397e91 100644
--- a/drivers/net/ethernet/8390/zorro8390.c
+++ b/drivers/net/ethernet/8390/zorro8390.c
@@ -31,7 +31,6 @@
#include <linux/zorro.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index 6c3b1c0adaa0..7219123fa0a4 100644
--- a/drivers/net/ethernet/alteon/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -78,7 +78,6 @@
#include <net/sock.h>
#include <net/ip.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/amd/7990.c b/drivers/net/ethernet/amd/7990.c
index 1b046f58d58f..6e722dc37db7 100644
--- a/drivers/net/ethernet/amd/7990.c
+++ b/drivers/net/ethernet/amd/7990.c
@@ -33,7 +33,6 @@
#include <linux/socket.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index cc7b9e46780c..e10ffad525a7 100644
--- a/drivers/net/ethernet/amd/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -30,7 +30,6 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/system.h>
#define TX_BUFFERS 15
#define RX_BUFFERS 25
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 9f62504d0086..64d0d9c1afa2 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -88,7 +88,6 @@ Revision History:
#include <linux/crc32.h>
#include <linux/dma-mapping.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c
index 7dc508e5c72e..75299f500ee5 100644
--- a/drivers/net/ethernet/amd/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -64,7 +64,6 @@
#include <linux/types.h>
#include <asm/addrspace.h>
-#include <asm/system.h>
#include <asm/dec/interrupts.h>
#include <asm/dec/ioasic.h>
diff --git a/drivers/net/ethernet/amd/hplance.c b/drivers/net/ethernet/amd/hplance.c
index 4e2d68a4de8a..8baff4e5d964 100644
--- a/drivers/net/ethernet/amd/hplance.c
+++ b/drivers/net/ethernet/amd/hplance.c
@@ -22,7 +22,6 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/mvme147.c
index 56bc47a94186..9af3c307862c 100644
--- a/drivers/net/ethernet/amd/mvme147.c
+++ b/drivers/net/ethernet/amd/mvme147.c
@@ -22,7 +22,6 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/mvme147hw.h>
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index ebdb9e238a8d..9f59bf63514b 100644
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -154,7 +154,6 @@ Include Files
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/system.h>
/* ----------------------------------------------------------------------------
Defines
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index e3fe3504e198..d7a3533d990b 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -95,7 +95,6 @@ static char lancestr[] = "LANCE";
#include <linux/of_device.h>
#include <linux/gfp.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 7b71387cf93c..4e4bb3875868 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -48,7 +48,6 @@
#include <net/checksum.h>
#include <net/ip.h>
-#include <asm/system.h>
#include <linux/io.h>
#include <asm/byteorder.h>
#include <linux/uaccess.h>
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index 30fee428c489..b9406cbfc180 100644
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -148,7 +148,6 @@
#include <linux/delay.h>
#include <linux/gfp.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/atomic.h>
diff --git a/drivers/net/ethernet/cirrus/mac89x0.c b/drivers/net/ethernet/cirrus/mac89x0.c
index 932fdccc339a..e285f384b096 100644
--- a/drivers/net/ethernet/cirrus/mac89x0.c
+++ b/drivers/net/ethernet/cirrus/mac89x0.c
@@ -99,7 +99,6 @@ static char *version =
#include <linux/bitops.h>
#include <linux/gfp.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/hwtest.h>
#include <asm/macints.h>
diff --git a/drivers/net/ethernet/dlink/de600.c b/drivers/net/ethernet/dlink/de600.c
index 682750c052c8..414f0eea1049 100644
--- a/drivers/net/ethernet/dlink/de600.c
+++ b/drivers/net/ethernet/dlink/de600.c
@@ -46,7 +46,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
-#include <asm/system.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/net/ethernet/dlink/de620.c b/drivers/net/ethernet/dlink/de620.c
index afc5aaac6b60..2e2bc60ee811 100644
--- a/drivers/net/ethernet/dlink/de620.c
+++ b/drivers/net/ethernet/dlink/de620.c
@@ -122,7 +122,6 @@ static const char version[] =
#include <linux/skbuff.h>
#include <asm/io.h>
-#include <asm/system.h>
/* Constant definitions for the DE-620 registers, commands and bits */
#include "de620.h"
diff --git a/drivers/net/ethernet/fujitsu/at1700.c b/drivers/net/ethernet/fujitsu/at1700.c
index 586b46fd4eed..3d94797c8f9b 100644
--- a/drivers/net/ethernet/fujitsu/at1700.c
+++ b/drivers/net/ethernet/fujitsu/at1700.c
@@ -52,7 +52,6 @@
#include <linux/crc32.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/fujitsu/eth16i.c b/drivers/net/ethernet/fujitsu/eth16i.c
index c3f0178fb5cb..a992d1f7e0d2 100644
--- a/drivers/net/ethernet/fujitsu/eth16i.c
+++ b/drivers/net/ethernet/fujitsu/eth16i.c
@@ -163,7 +163,6 @@ static char *version =
#include <linux/jiffies.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
index 0230319ddb59..2418faf2251a 100644
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -57,7 +57,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/system.h>
/*====================================================================*/
diff --git a/drivers/net/ethernet/i825xx/3c507.c b/drivers/net/ethernet/i825xx/3c507.c
index ed6925f11479..e8984b059905 100644
--- a/drivers/net/ethernet/i825xx/3c507.c
+++ b/drivers/net/ethernet/i825xx/3c507.c
@@ -63,7 +63,6 @@ static const char version[] =
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
/* use 0 for production, 1 for verification, 2..7 for debug */
diff --git a/drivers/net/ethernet/i825xx/3c527.c b/drivers/net/ethernet/i825xx/3c527.c
index ef43f3e951c5..278e791afe00 100644
--- a/drivers/net/ethernet/i825xx/3c527.c
+++ b/drivers/net/ethernet/i825xx/3c527.c
@@ -106,7 +106,6 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.
#include <linux/semaphore.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/i825xx/eepro.c b/drivers/net/ethernet/i825xx/eepro.c
index 7a4ad4a07917..7f49fd54c521 100644
--- a/drivers/net/ethernet/i825xx/eepro.c
+++ b/drivers/net/ethernet/i825xx/eepro.c
@@ -148,7 +148,6 @@ static const char version[] =
#include <linux/bitops.h>
#include <linux/ethtool.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/i825xx/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c
index 3fc649e54a32..cc2e66ad4436 100644
--- a/drivers/net/ethernet/i825xx/eexpress.c
+++ b/drivers/net/ethernet/i825xx/eexpress.c
@@ -116,7 +116,6 @@
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/ethernet/i825xx/ether1.c b/drivers/net/ethernet/i825xx/ether1.c
index 406a12b46404..067db3f13e91 100644
--- a/drivers/net/ethernet/i825xx/ether1.c
+++ b/drivers/net/ethernet/i825xx/ether1.c
@@ -48,7 +48,6 @@
#include <linux/skbuff.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/ecard.h>
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c
index a43649735a04..bd1f1ef91e19 100644
--- a/drivers/net/ethernet/i825xx/znet.c
+++ b/drivers/net/ethernet/i825xx/znet.c
@@ -100,7 +100,6 @@
#include <linux/if_arp.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index e877371680a9..9010cea68bc3 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1616,11 +1616,8 @@ static struct vio_driver ibmveth_driver = {
.probe = ibmveth_probe,
.remove = ibmveth_remove,
.get_desired_dma = ibmveth_get_desired_dma,
- .driver = {
- .name = ibmveth_driver_name,
- .owner = THIS_MODULE,
- .pm = &ibmveth_pm_ops,
- }
+ .name = ibmveth_driver_name,
+ .pm = &ibmveth_pm_ops,
};
static int __init ibmveth_module_init(void)
diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
index f30db1c46600..bc58f1dc22f5 100644
--- a/drivers/net/ethernet/korina.c
+++ b/drivers/net/ethernet/korina.c
@@ -55,7 +55,6 @@
#include <linux/crc32.h>
#include <asm/bootinfo.h>
-#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <asm/io.h>
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 75af1afe46c8..5e1ca0f05090 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -57,7 +57,6 @@
#include <linux/types.h>
#include <linux/inet_lro.h>
#include <linux/slab.h>
-#include <asm/system.h>
static char mv643xx_eth_driver_name[] = "mv643xx_eth";
static char mv643xx_eth_driver_version[] = "1.4";
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 45a6333588e6..efec6b60b327 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -43,7 +43,6 @@
#include <linux/interrupt.h>
#include <linux/types.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include <asm/cacheflush.h>
#include <linux/pxa168_eth.h>
diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index 0686b93f1857..f84dd2dc82b6 100644
--- a/drivers/net/ethernet/micrel/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
@@ -458,7 +458,7 @@ static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev)
if (sg_dma_len(&ctl->sg) % 4)
sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4;
- ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+ ctl->adesc = dmaengine_prep_slave_sg(ctl->chan,
&ctl->sg, 1, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
if (!ctl->adesc)
@@ -570,7 +570,7 @@ static int __ks8842_start_new_rx_dma(struct net_device *netdev)
sg_dma_len(sg) = DMA_BUFFER_SIZE;
- ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+ ctl->adesc = dmaengine_prep_slave_sg(ctl->chan,
sg, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c
index 5b89fd377ae3..95dd39ffb230 100644
--- a/drivers/net/ethernet/natsemi/jazzsonic.c
+++ b/drivers/net/ethernet/natsemi/jazzsonic.c
@@ -38,7 +38,6 @@
#include <linux/slab.h>
#include <asm/bootinfo.h>
-#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c
index e640e23460de..b9680ba5a325 100644
--- a/drivers/net/ethernet/natsemi/macsonic.c
+++ b/drivers/net/ethernet/natsemi/macsonic.c
@@ -53,7 +53,6 @@
#include <linux/slab.h>
#include <asm/bootinfo.h>
-#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/hwtest.h>
diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c
index c24b46cbfe27..d52728b3c436 100644
--- a/drivers/net/ethernet/natsemi/ns83820.c
+++ b/drivers/net/ethernet/natsemi/ns83820.c
@@ -121,7 +121,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#define DRV_NAME "ns83820"
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 22a8de00bf02..6338ef8606ae 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -81,7 +81,6 @@
#include <linux/prefetch.h>
#include <net/tcp.h>
-#include <asm/system.h>
#include <asm/div64.h>
#include <asm/irq.h>
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 8561dd25db66..aca13046e432 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -69,7 +69,6 @@
#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#define TX_WORK_PER_LOOP 64
#define RX_WORK_PER_LOOP 64
diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c
index 46c1932048cb..e02f04d7f3ad 100644
--- a/drivers/net/ethernet/realtek/atp.c
+++ b/drivers/net/ethernet/realtek/atp.c
@@ -140,7 +140,6 @@ static int xcvr[NUM_UNITS]; /* The data transfer mode. */
#include <linux/delay.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 27c358c8f4dc..7b23554f80b6 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -29,7 +29,6 @@
#include <linux/pci-aspm.h>
#include <linux/prefetch.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index 7b819bd8c416..df808ac8cb65 100644
--- a/drivers/net/ethernet/seeq/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -64,7 +64,6 @@
#include <linux/delay.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/ecard.h>
#include <asm/io.h>
diff --git a/drivers/net/ethernet/seeq/seeq8005.c b/drivers/net/ethernet/seeq/seeq8005.c
index 798990774446..698edbbfc149 100644
--- a/drivers/net/ethernet/seeq/seeq8005.c
+++ b/drivers/net/ethernet/seeq/seeq8005.c
@@ -47,7 +47,6 @@ static const char version[] =
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c
index d12e48a7861d..04393b5fef71 100644
--- a/drivers/net/ethernet/smsc/smc91c92_cs.c
+++ b/drivers/net/ethernet/smsc/smc91c92_cs.c
@@ -53,7 +53,6 @@
#include <pcmcia/ss.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
/*====================================================================*/
diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c
index 3c2295560732..ce4df61b4b56 100644
--- a/drivers/net/ethernet/sun/cassini.c
+++ b/drivers/net/ethernet/sun/cassini.c
@@ -99,7 +99,6 @@
#include <net/checksum.h>
#include <linux/atomic.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index f359863b5340..2a83fc57edba 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -35,7 +35,6 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include "sunbmac.h"
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index ba041596e046..558409ff4058 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -41,7 +41,6 @@
#include <linux/mm.h>
#include <linux/gfp.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 8b627e2f798d..b95e7e681b38 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -36,7 +36,6 @@
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 139d6b410d68..7d4a040d84a2 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -28,7 +28,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 92a037a8228a..38e3ae9155b7 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -1259,10 +1259,7 @@ static struct vio_driver vnet_port_driver = {
.id_table = vnet_port_match,
.probe = vnet_port_probe,
.remove = vnet_port_remove,
- .driver = {
- .name = "vnet_port",
- .owner = THIS_MODULE,
- }
+ .name = "vnet_port",
};
static int __init vnet_init(void)
diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c
index 840e0e9031f5..277c93e9ff4d 100644
--- a/drivers/net/ethernet/tundra/tsi108_eth.c
+++ b/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -50,7 +50,6 @@
#include <linux/platform_device.h>
#include <linux/gfp.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/tsi108.h>
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index 5c69c6f93fb8..94a1f94f74b8 100644
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -89,7 +89,6 @@
#include <pcmcia/ciscode.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#ifndef MANFID_COMPAQ
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 2a5a34d2d67b..64783a0d545a 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -13,7 +13,6 @@
*/
#include <linux/module.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/bitops.h>
#include <linux/string.h>
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index f1aea0c98333..acb636963e90 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -86,7 +86,6 @@
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 18d8affecd1b..76d54774ba82 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -69,7 +69,6 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index bc02968cee16..aed1a6105b24 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -17,7 +17,6 @@
* Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
*/
#include <linux/module.h>
-#include <asm/system.h>
#include <linux/bitops.h>
#include <asm/uaccess.h>
#include <linux/crc16.h>
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 33655814448e..efc6c97163a7 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -177,7 +177,6 @@
#include <net/ax25.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 696327773fbe..5a6412ecce73 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -52,7 +52,6 @@
#include <linux/bitops.h>
#include <linux/random.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/firmware.h>
diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c
index 2a51363d9fed..168c8f41d09f 100644
--- a/drivers/net/hippi/rrunner.c
+++ b/drivers/net/hippi/rrunner.c
@@ -43,7 +43,6 @@
#include <linux/slab.h>
#include <net/sock.h>
-#include <asm/system.h>
#include <asm/cache.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 617a446d126c..4351296dde32 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -156,7 +156,6 @@
#include <linux/pci.h>
#include <linux/rtnetlink.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <net/irda/wrapper.h>
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index b71998d0b5b4..32eb94ece6c1 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -41,7 +41,6 @@
#include <linux/in.h>
#include <linux/init.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
index 1a5a316cc968..bed62d9c53c8 100644
--- a/drivers/net/plip/plip.c
+++ b/drivers/net/plip/plip.c
@@ -113,7 +113,6 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"
#include <net/neighbour.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
index 0a0a6643cf3a..1252d9c726a7 100644
--- a/drivers/net/slip/slhc.c
+++ b/drivers/net/slip/slhc.c
@@ -75,7 +75,6 @@
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/timer.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <net/checksum.h>
#include <asm/unaligned.h>
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index 69345dfae0fd..d4c9db3da22a 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -64,7 +64,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/bitops.h>
#include <linux/sched.h>
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index d7c292aa76b1..b15ac81d46fa 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -68,7 +68,6 @@
#include <net/checksum.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "3c359.h"
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 515f122777ab..b715e6b444da 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -33,7 +33,6 @@
#include <linux/netdevice.h>
#include <linux/trdevice.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/tokenring/ibmtr_cs.c b/drivers/net/tokenring/ibmtr_cs.c
index 91b684630fc5..356e28e4881b 100644
--- a/drivers/net/tokenring/ibmtr_cs.c
+++ b/drivers/net/tokenring/ibmtr_cs.c
@@ -63,7 +63,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/system.h>
#define PCMCIA
#include "ibmtr.c"
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 8d71e0d29062..3e4b4f091113 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -127,7 +127,6 @@
#include <net/checksum.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "lanstreamer.h"
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index 1cdc034f6aec..28adcdf3b14c 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -28,7 +28,6 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
#include <linux/netdevice.h>
#include <linux/trdevice.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index fd8dce90c957..0e234741cc79 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -106,7 +106,6 @@
#include <net/net_namespace.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "olympic.h"
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index 8d362e64a40e..62d90e40f9ec 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -31,7 +31,6 @@ static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n
#include <linux/trdevice.h>
#include <linux/platform_device.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/pci.h>
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 46db5c5395b2..ee11e93dc30e 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -38,7 +38,6 @@ static const char version[] = "skisa.c: v1.03 09/12/2002 by Jochen Friedrich\n";
#include <linux/trdevice.h>
#include <linux/platform_device.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/pci.h>
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 029846a98636..cb35fb79e016 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -49,7 +49,6 @@
#include <linux/bitops.h>
#include <linux/firmware.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/irq.h>
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 102f896bbc58..be4813e0366c 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -98,7 +98,6 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A
#include <linux/firmware.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/irq.h>
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index d3e788a9cd1c..fb9918da5792 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -34,7 +34,6 @@
#include <linux/netdevice.h>
#include <linux/trdevice.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 74d7f76d14a3..bb8c72c79c6f 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -69,7 +69,6 @@
#include <net/rtnetlink.h>
#include <net/sock.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
/* Uncomment to enable debugging */
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 48ab38a34c5a..147614ed86aa 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -50,7 +50,6 @@
#include <net/sock.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index fe8d060d8fff..c676de7de024 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -93,7 +93,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <asm/cache.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c
index 33b67d88fceb..cf4903355a34 100644
--- a/drivers/net/wan/hd64570.c
+++ b/drivers/net/wan/hd64570.c
@@ -40,7 +40,6 @@
#include <linux/string.h>
#include <linux/types.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include "hd64570.h"
diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c
index efc0db101183..e2779faa6c4f 100644
--- a/drivers/net/wan/hd64572.c
+++ b/drivers/net/wan/hd64572.c
@@ -40,7 +40,6 @@
#include <linux/string.h>
#include <linux/types.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include "hd64572.h"
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 7beeb9b88a3b..a73b49eb87e3 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -35,7 +35,6 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index c8531612eea9..de3bbf43fc5a 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -54,7 +54,6 @@
#include <linux/sdla.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index e862369b4a6d..d7a65e141d1a 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/string.h>
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index ddc061dd150c..520a4b2eb9cc 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -37,7 +37,6 @@
#include <linux/scatterlist.h>
#include <linux/crypto.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index c983c10e0f6a..630577dd3a7a 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -37,7 +37,6 @@
#include <pcmcia/ds.h>
#include <linux/io.h>
-#include <asm/system.h>
#include "airo.h"
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 3010cee7b95a..6c87a823f5a9 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -50,7 +50,6 @@
#include <linux/timer.h>
#include <asm/byteorder.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index ec295c4f677d..ded03d226a71 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -48,7 +48,6 @@
#include <pcmcia/ciscode.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/wireless.h>
#include "atmel.h"
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index 851fa10241e1..c5404cb59e08 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -24,7 +24,6 @@
#include <linux/slab.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <linux/if_arp.h>
#include "prismcompat.h"
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 04fec1fa6e0b..86a738bf591c 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -53,7 +53,6 @@
#include <net/iw_handler.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 98fbf54f6004..00f6e69c1dcd 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -53,7 +53,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include "wl3501.h"
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index b764ac22d523..44d01afafe9c 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/setup.h>
-#include <asm/system.h>
#include <asm/page.h>
#include <asm/hwtest.h>
#include <linux/proc_fs.h>
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 6ea51dcbc728..8e84ce9765a9 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -91,4 +91,8 @@ config OF_PCI_IRQ
help
OpenFirmware PCI IRQ routing helpers
+config OF_MTD
+ depends on MTD
+ def_bool y
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index a73f5a51ff4c..aa90e602c8a7 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_OF_SELFTEST) += selftest.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
+obj-$(CONFIG_OF_MTD) += of_mtd.o
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 7e62d15d60f6..bba81216b4db 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -78,8 +78,9 @@ err0:
EXPORT_SYMBOL(of_get_named_gpio_flags);
/**
- * of_gpio_count - Count GPIOs for a device
+ * of_gpio_named_count - Count GPIOs for a device
* @np: device node to count GPIOs for
+ * @propname: property name containing gpio specifier(s)
*
* The function returns the count of GPIOs specified for a node.
*
@@ -93,14 +94,14 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);
* defines four GPIOs (so this function will return 4), two of which
* are not specified.
*/
-unsigned int of_gpio_count(struct device_node *np)
+unsigned int of_gpio_named_count(struct device_node *np, const char* propname)
{
unsigned int cnt = 0;
do {
int ret;
- ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells",
+ ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
cnt, NULL);
/* A hole in the gpios = <> counts anyway. */
if (ret < 0 && ret != -EEXIST)
@@ -109,7 +110,7 @@ unsigned int of_gpio_count(struct device_node *np)
return cnt;
}
-EXPORT_SYMBOL(of_gpio_count);
+EXPORT_SYMBOL(of_gpio_named_count);
/**
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
@@ -228,7 +229,7 @@ void of_gpiochip_remove(struct gpio_chip *chip)
}
/* Private function for resolving node pointer to gpio_chip */
-static int of_gpiochip_is_match(struct gpio_chip *chip, void *data)
+static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data)
{
return chip->of_node == data;
}
diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
new file mode 100644
index 000000000000..e7cad627a5d1
--- /dev/null
+++ b/drivers/of/of_mtd.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * OF helpers for mtd.
+ *
+ * This file is released under the GPLv2
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/of_mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/export.h>
+
+/**
+ * It maps 'enum nand_ecc_modes_t' found in include/linux/mtd/nand.h
+ * into the device tree binding of 'nand-ecc', so that MTD
+ * device driver can get nand ecc from device tree.
+ */
+static const char *nand_ecc_modes[] = {
+ [NAND_ECC_NONE] = "none",
+ [NAND_ECC_SOFT] = "soft",
+ [NAND_ECC_HW] = "hw",
+ [NAND_ECC_HW_SYNDROME] = "hw_syndrome",
+ [NAND_ECC_HW_OOB_FIRST] = "hw_oob_first",
+ [NAND_ECC_SOFT_BCH] = "soft_bch",
+};
+
+/**
+ * of_get_nand_ecc_mode - Get nand ecc mode for given device_node
+ * @np: Pointer to the given device_node
+ *
+ * The function gets ecc mode string from property 'nand-ecc-mode',
+ * and return its index in nand_ecc_modes table, or errno in error case.
+ */
+const int of_get_nand_ecc_mode(struct device_node *np)
+{
+ const char *pm;
+ int err, i;
+
+ err = of_property_read_string(np, "nand-ecc-mode", &pm);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
+ if (!strcasecmp(pm, nand_ecc_modes[i]))
+ return i;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
+
+/**
+ * of_get_nand_bus_width - Get nand bus witdh for given device_node
+ * @np: Pointer to the given device_node
+ *
+ * return bus width option, or errno in error case.
+ */
+int of_get_nand_bus_width(struct device_node *np)
+{
+ u32 val;
+
+ if (of_property_read_u32(np, "nand-bus-width", &val))
+ return 8;
+
+ switch(val) {
+ case 8:
+ case 16:
+ return val;
+ default:
+ return -EIO;
+ }
+}
+EXPORT_SYMBOL_GPL(of_get_nand_bus_width);
+
+/**
+ * of_get_nand_on_flash_bbt - Get nand on flash bbt for given device_node
+ * @np: Pointer to the given device_node
+ *
+ * return true if present false other wise
+ */
+bool of_get_nand_on_flash_bbt(struct device_node *np)
+{
+ return of_property_read_bool(np, "nand-on-flash-bbt");
+}
+EXPORT_SYMBOL_GPL(of_get_nand_on_flash_bbt);
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 0610e91bceb2..432d4bbcc62a 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -55,7 +55,6 @@
#include <asm/pdc.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/hardware.h>
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 95930d016235..1f9e9fefb8e7 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -140,7 +140,6 @@
#include <asm/pdc.h>
#include <asm/pdcpat.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <asm/io.h> /* read/write functions */
#ifdef CONFIG_SUPERIO
#include <asm/superio.h>
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index e8857647e210..052fa230bc77 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -43,7 +43,6 @@
#include <asm/pdc.h>
#include <asm/pdcpat.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <asm/ropes.h>
#include <asm/hardware.h> /* for register_parisc_driver() stuff */
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 1dd68f502634..9694c1e783a5 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -16,13 +16,13 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <pcmcia/ss.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/sizes.h>
-#include <asm/gpio.h>
#include <mach/board.h>
#include <mach/at91rm9200_mc.h>
@@ -70,7 +70,7 @@ static irqreturn_t at91_cf_irq(int irq, void *_cf)
{
struct at91_cf_socket *cf = _cf;
- if (irq == cf->board->det_pin) {
+ if (irq == gpio_to_irq(cf->board->det_pin)) {
unsigned present = at91_cf_present(cf);
/* kick pccard as needed */
@@ -96,8 +96,8 @@ static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp)
/* NOTE: CF is always 3VCARD */
if (at91_cf_present(cf)) {
- int rdy = cf->board->irq_pin; /* RDY/nIRQ */
- int vcc = cf->board->vcc_pin;
+ int rdy = gpio_is_valid(cf->board->irq_pin); /* RDY/nIRQ */
+ int vcc = gpio_is_valid(cf->board->vcc_pin);
*sp = SS_DETECT | SS_3VCARD;
if (!rdy || gpio_get_value(rdy))
@@ -118,7 +118,7 @@ at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
cf = container_of(sock, struct at91_cf_socket, socket);
/* switch Vcc if needed and possible */
- if (cf->board->vcc_pin) {
+ if (gpio_is_valid(cf->board->vcc_pin)) {
switch (s->Vcc) {
case 0:
gpio_set_value(cf->board->vcc_pin, 0);
@@ -222,7 +222,7 @@ static int __init at91_cf_probe(struct platform_device *pdev)
struct resource *io;
int status;
- if (!board || !board->det_pin || !board->rst_pin)
+ if (!board || !gpio_is_valid(board->det_pin) || !gpio_is_valid(board->rst_pin))
return -ENODEV;
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -242,7 +242,7 @@ static int __init at91_cf_probe(struct platform_device *pdev)
status = gpio_request(board->det_pin, "cf_det");
if (status < 0)
goto fail0;
- status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf);
+ status = request_irq(gpio_to_irq(board->det_pin), at91_cf_irq, 0, driver_name, cf);
if (status < 0)
goto fail00;
device_init_wakeup(&pdev->dev, 1);
@@ -251,7 +251,7 @@ static int __init at91_cf_probe(struct platform_device *pdev)
if (status < 0)
goto fail0a;
- if (board->vcc_pin) {
+ if (gpio_is_valid(board->vcc_pin)) {
status = gpio_request(board->vcc_pin, "cf_vcc");
if (status < 0)
goto fail0b;
@@ -263,15 +263,15 @@ static int __init at91_cf_probe(struct platform_device *pdev)
* unless we report that we handle everything (sigh).
* (Note: DK board doesn't wire the IRQ pin...)
*/
- if (board->irq_pin) {
+ if (gpio_is_valid(board->irq_pin)) {
status = gpio_request(board->irq_pin, "cf_irq");
if (status < 0)
goto fail0c;
- status = request_irq(board->irq_pin, at91_cf_irq,
+ status = request_irq(gpio_to_irq(board->irq_pin), at91_cf_irq,
IRQF_SHARED, driver_name, cf);
if (status < 0)
goto fail0d;
- cf->socket.pci_irq = board->irq_pin;
+ cf->socket.pci_irq = gpio_to_irq(board->irq_pin);
} else
cf->socket.pci_irq = nr_irqs + 1;
@@ -290,7 +290,7 @@ static int __init at91_cf_probe(struct platform_device *pdev)
}
pr_info("%s: irqs det #%d, io #%d\n", driver_name,
- board->det_pin, board->irq_pin);
+ gpio_to_irq(board->det_pin), gpio_to_irq(board->irq_pin));
cf->socket.owner = THIS_MODULE;
cf->socket.dev.parent = &pdev->dev;
@@ -312,19 +312,19 @@ fail2:
fail1:
if (cf->socket.io_offset)
iounmap((void __iomem *) cf->socket.io_offset);
- if (board->irq_pin) {
- free_irq(board->irq_pin, cf);
+ if (gpio_is_valid(board->irq_pin)) {
+ free_irq(gpio_to_irq(board->irq_pin), cf);
fail0d:
gpio_free(board->irq_pin);
}
fail0c:
- if (board->vcc_pin)
+ if (gpio_is_valid(board->vcc_pin))
gpio_free(board->vcc_pin);
fail0b:
gpio_free(board->rst_pin);
fail0a:
device_init_wakeup(&pdev->dev, 0);
- free_irq(board->det_pin, cf);
+ free_irq(gpio_to_irq(board->det_pin), cf);
fail00:
gpio_free(board->det_pin);
fail0:
@@ -341,15 +341,15 @@ static int __exit at91_cf_remove(struct platform_device *pdev)
pcmcia_unregister_socket(&cf->socket);
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);
+ if (gpio_is_valid(board->irq_pin)) {
+ free_irq(gpio_to_irq(board->irq_pin), cf);
gpio_free(board->irq_pin);
}
- if (board->vcc_pin)
+ if (gpio_is_valid(board->vcc_pin))
gpio_free(board->vcc_pin);
gpio_free(board->rst_pin);
device_init_wakeup(&pdev->dev, 0);
- free_irq(board->det_pin, cf);
+ free_irq(gpio_to_irq(board->det_pin), cf);
gpio_free(board->det_pin);
kfree(cf);
return 0;
@@ -363,9 +363,9 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
struct at91_cf_data *board = cf->board;
if (device_may_wakeup(&pdev->dev)) {
- enable_irq_wake(board->det_pin);
- if (board->irq_pin)
- enable_irq_wake(board->irq_pin);
+ enable_irq_wake(gpio_to_irq(board->det_pin));
+ if (gpio_is_valid(board->irq_pin))
+ enable_irq_wake(gpio_to_irq(board->irq_pin));
}
return 0;
}
@@ -376,9 +376,9 @@ static int at91_cf_resume(struct platform_device *pdev)
struct at91_cf_data *board = cf->board;
if (device_may_wakeup(&pdev->dev)) {
- disable_irq_wake(board->det_pin);
- if (board->irq_pin)
- disable_irq_wake(board->irq_pin);
+ disable_irq_wake(gpio_to_irq(board->det_pin));
+ if (gpio_is_valid(board->irq_pin))
+ disable_irq_wake(gpio_to_irq(board->irq_pin));
}
return 0;
diff --git a/drivers/pcmcia/bcm63xx_pcmcia.c b/drivers/pcmcia/bcm63xx_pcmcia.c
index 693577e0fefc..c2e997a570bf 100644
--- a/drivers/pcmcia/bcm63xx_pcmcia.c
+++ b/drivers/pcmcia/bcm63xx_pcmcia.c
@@ -475,7 +475,7 @@ static void __devexit bcm63xx_cb_exit(struct pci_dev *dev)
bcm63xx_cb_dev = NULL;
}
-static struct pci_device_id bcm63xx_cb_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(bcm63xx_cb_table) = {
{
.vendor = PCI_VENDOR_ID_BROADCOM,
.device = BCM6348_CPU_ID,
diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c
index 49221395101e..ac1a2232eab9 100644
--- a/drivers/pcmcia/bfin_cf_pcmcia.c
+++ b/drivers/pcmcia/bfin_cf_pcmcia.c
@@ -310,18 +310,7 @@ static struct platform_driver bfin_cf_driver = {
.remove = __devexit_p(bfin_cf_remove),
};
-static int __init bfin_cf_init(void)
-{
- return platform_driver_register(&bfin_cf_driver);
-}
-
-static void __exit bfin_cf_exit(void)
-{
- platform_driver_unregister(&bfin_cf_driver);
-}
-
-module_init(bfin_cf_init);
-module_exit(bfin_cf_exit);
+module_platform_driver(bfin_cf_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index d9ea192c4001..673c14ea11e3 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -29,7 +29,6 @@
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
index 5b7c22784aff..a484b1fb3382 100644
--- a/drivers/pcmcia/db1xxx_ss.c
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -172,12 +172,12 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
if ((sock->board_type == BOARD_TYPE_DB1200) ||
(sock->board_type == BOARD_TYPE_DB1300)) {
ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
- IRQF_DISABLED, "pcmcia_insert", sock);
+ 0, "pcmcia_insert", sock);
if (ret)
goto out1;
ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
- IRQF_DISABLED, "pcmcia_eject", sock);
+ 0, "pcmcia_eject", sock);
if (ret) {
free_irq(sock->insert_irq, sock);
goto out1;
@@ -580,18 +580,7 @@ static struct platform_driver db1x_pcmcia_socket_driver = {
.remove = __devexit_p(db1x_pcmcia_socket_remove),
};
-int __init db1x_pcmcia_socket_load(void)
-{
- return platform_driver_register(&db1x_pcmcia_socket_driver);
-}
-
-void __exit db1x_pcmcia_socket_unload(void)
-{
- platform_driver_unregister(&db1x_pcmcia_socket_driver);
-}
-
-module_init(db1x_pcmcia_socket_load);
-module_exit(db1x_pcmcia_socket_unload);
+module_platform_driver(db1x_pcmcia_socket_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PCMCIA Socket Services for Alchemy Db/Pb1x00 boards");
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index 06ad3e5e7d3d..7647d232e9e2 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -365,17 +365,7 @@ static struct platform_driver electra_cf_driver = {
.remove = electra_cf_remove,
};
-static int __init electra_cf_init(void)
-{
- return platform_driver_register(&electra_cf_driver);
-}
-module_init(electra_cf_init);
-
-static void __exit electra_cf_exit(void)
-{
- platform_driver_unregister(&electra_cf_driver);
-}
-module_exit(electra_cf_exit);
+module_platform_driver(electra_cf_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 3e447d0387b7..4e8831bdb6ef 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -17,7 +17,6 @@
#include <pcmcia/ss.h>
-#include <asm/system.h>
#include <asm/io.h>
#include "i82092aa.h"
@@ -26,14 +25,9 @@
MODULE_LICENSE("GPL");
/* PCI core routines */
-static struct pci_device_id i82092aa_pci_ids[] = {
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_82092AA_0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- {}
+static DEFINE_PCI_DEVICE_TABLE(i82092aa_pci_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82092AA_0) },
+ { }
};
MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 72a033a2acdb..e6f3d17dd2b4 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -48,7 +48,6 @@
#include <linux/bitops.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 2adb0106a039..a26f38c6402a 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -24,7 +24,6 @@
#include <linux/bitops.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 1511ff71c87b..296514155cd5 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -24,7 +24,6 @@
#include <linux/bitops.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/addrspace.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 271a590a5f3c..a3a851e49321 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -52,7 +52,6 @@
#include <linux/of_platform.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/time.h>
#include <asm/mpc8xx.h>
#include <asm/8xx_immap.h>
@@ -1304,15 +1303,4 @@ static struct platform_driver m8xx_pcmcia_driver = {
.remove = m8xx_remove,
};
-static int __init m8xx_init(void)
-{
- return platform_driver_register(&m8xx_pcmcia_driver);
-}
-
-static void __exit m8xx_exit(void)
-{
- platform_driver_unregister(&m8xx_pcmcia_driver);
-}
-
-module_init(m8xx_init);
-module_exit(m8xx_exit);
+module_platform_driver(m8xx_pcmcia_driver);
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 96c72e90b79c..253e3867dec7 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -19,7 +19,6 @@
#include <pcmcia/ss.h>
-#include <asm/system.h>
#include "pd6729.h"
#include "i82365.h"
@@ -763,13 +762,8 @@ static void __devexit pd6729_pci_remove(struct pci_dev *dev)
kfree(socket);
}
-static struct pci_device_id pd6729_pci_ids[] = {
- {
- .vendor = PCI_VENDOR_ID_CIRRUS,
- .device = PCI_DEVICE_ID_CIRRUS_6729,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
+static DEFINE_PCI_DEVICE_TABLE(pd6729_pci_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729) },
{ }
};
MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 66a54222bbf4..490bb82b5bdb 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -29,7 +29,6 @@
#include <mach/smemc.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <mach/pxa2xx-regs.h>
#include <asm/mach-types.h>
diff --git a/drivers/pcmcia/pxa2xx_viper.c b/drivers/pcmcia/pxa2xx_viper.c
index adfae4987a42..cb0c37ec7f24 100644
--- a/drivers/pcmcia/pxa2xx_viper.c
+++ b/drivers/pcmcia/pxa2xx_viper.c
@@ -177,18 +177,7 @@ static struct platform_driver viper_pcmcia_driver = {
.id_table = viper_pcmcia_id_table,
};
-static int __init viper_pcmcia_init(void)
-{
- return platform_driver_register(&viper_pcmcia_driver);
-}
-
-static void __exit viper_pcmcia_exit(void)
-{
- return platform_driver_unregister(&viper_pcmcia_driver);
-}
-
-module_init(viper_pcmcia_init);
-module_exit(viper_pcmcia_exit);
+module_platform_driver(viper_pcmcia_driver);
MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index a3ee89a6dd0e..6eecd7cddf57 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -41,7 +41,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include "soc_common.h"
#include "sa11xx_base.h"
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index e0433f571962..a2bc6ee1702e 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -46,7 +46,6 @@
#include <linux/timer.h>
#include <mach/hardware.h>
-#include <asm/system.h>
#include "soc_common.h"
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 71aeed93037c..d6881514d38e 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -23,7 +23,6 @@
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/mutex.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 310160bffe38..cbe15fc37411 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -47,7 +47,6 @@
#include <linux/bitops.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/ss.h>
#include "tcic.h"
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
index c6d36b3a6ce8..cd0a315d922b 100644
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -563,11 +563,8 @@ static int __devinit vrc4173_cardu_setup(char *options)
__setup("vrc4173_cardu=", vrc4173_cardu_setup);
-static struct pci_device_id vrc4173_cardu_id_table[] __devinitdata = {
- { .vendor = PCI_VENDOR_ID_NEC,
- .device = PCI_DEVICE_ID_NEC_NAPCCARD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID, },
+static DEFINE_PCI_DEVICE_TABLE(vrc4173_cardu_id_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NAPCCARD) },
{0, }
};
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
index 379f4218857d..fd5fbd10aad0 100644
--- a/drivers/pcmcia/xxs1500_ss.c
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -21,7 +21,6 @@
#include <pcmcia/cistpl.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
#define MEM_MAP_SIZE 0x400000
@@ -321,18 +320,7 @@ static struct platform_driver xxs1500_pcmcia_socket_driver = {
.remove = __devexit_p(xxs1500_pcmcia_remove),
};
-int __init xxs1500_pcmcia_socket_load(void)
-{
- return platform_driver_register(&xxs1500_pcmcia_socket_driver);
-}
-
-void __exit xxs1500_pcmcia_socket_unload(void)
-{
- platform_driver_unregister(&xxs1500_pcmcia_socket_driver);
-}
-
-module_init(xxs1500_pcmcia_socket_load);
-module_exit(xxs1500_pcmcia_socket_unload);
+module_platform_driver(xxs1500_pcmcia_socket_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 849c0c11d2af..d07f9ac8c41d 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1352,7 +1352,7 @@ static const struct dev_pm_ops yenta_pm_ops = {
.driver_data = CARDBUS_TYPE_##type, \
}
-static struct pci_device_id yenta_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(yenta_table) = {
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1031, TI),
/*
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2dc02c972ce9..2a262f5c5c0c 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -26,6 +26,10 @@ config ACER_WMI
depends on RFKILL || RFKILL = n
depends on ACPI_WMI
select INPUT_SPARSEKMAP
+ # Acer WMI depends on ACPI_VIDEO when ACPI is enabled
+ # but for select to work, need to select ACPI_VIDEO's dependencies, ick
+ select VIDEO_OUTPUT_CONTROL if ACPI
+ select ACPI_VIDEO if ACPI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
wireless radio and bluetooth control, and on some laptops,
@@ -54,7 +58,6 @@ config ACERHDF
config ASUS_LAPTOP
tristate "Asus Laptop Extras"
depends on ACPI
- depends on !ACPI_ASUS
select LEDS_CLASS
select NEW_LEDS
select BACKLIGHT_CLASS_DEVICE
@@ -460,10 +463,9 @@ config INTEL_MENLOW
If unsure, say N.
config EEEPC_LAPTOP
- tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+ tristate "Eee PC Hotkey Driver"
depends on ACPI
depends on INPUT
- depends on EXPERIMENTAL
depends on RFKILL || RFKILL = n
depends on HOTPLUG_PCI
select BACKLIGHT_CLASS_DEVICE
@@ -482,11 +484,10 @@ config EEEPC_LAPTOP
doesn't work on your Eee PC, try eeepc-wmi instead.
config ASUS_WMI
- tristate "ASUS WMI Driver (EXPERIMENTAL)"
+ tristate "ASUS WMI Driver"
depends on ACPI_WMI
depends on INPUT
depends on HWMON
- depends on EXPERIMENTAL
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL || RFKILL = n
depends on HOTPLUG_PCI
@@ -501,7 +502,7 @@ config ASUS_WMI
be called asus-wmi.
config ASUS_NB_WMI
- tristate "Asus Notebook WMI Driver (EXPERIMENTAL)"
+ tristate "Asus Notebook WMI Driver"
depends on ASUS_WMI
---help---
This is a driver for newer Asus notebooks. It adds extra features
@@ -514,7 +515,7 @@ config ASUS_NB_WMI
here.
config EEEPC_WMI
- tristate "Eee PC WMI Driver (EXPERIMENTAL)"
+ tristate "Eee PC WMI Driver"
depends on ASUS_WMI
---help---
This is a driver for newer Eee PC laptops. It adds extra features
@@ -559,38 +560,6 @@ config MSI_WMI
To compile this driver as a module, choose M here: the module will
be called msi-wmi.
-config ACPI_ASUS
- tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
- depends on ACPI
- select BACKLIGHT_CLASS_DEVICE
- ---help---
- This driver provides support for extra features of ACPI-compatible
- ASUS laptops. As some of Medion laptops are made by ASUS, it may also
- support some Medion laptops (such as 9675 for example). It makes all
- the extra buttons generate standard ACPI events that go through
- /proc/acpi/events, and (on some models) adds support for changing the
- display brightness and output, switching the LCD backlight on and off,
- and most importantly, allows you to blink those fancy LEDs intended
- for reporting mail and wireless status.
-
- Note: display switching code is currently considered EXPERIMENTAL,
- toying with these values may even lock your machine.
-
- All settings are changed via /proc/acpi/asus directory entries. Owner
- and group for these entries can be set with asus_uid and asus_gid
- parameters.
-
- More information and a userspace daemon for handling the extra buttons
- at <http://acpi4asus.sf.net>.
-
- If you have an ACPI-compatible ASUS laptop, say Y or M here. This
- driver is still under development, so if your laptop is unsupported or
- something works not quite as expected, please use the mailing list
- available on the above page (acpi4asus-user@lists.sourceforge.net).
-
- NOTE: This driver is deprecated and will probably be removed soon,
- use asus-laptop instead.
-
config TOPSTAR_LAPTOP
tristate "Topstar Laptop Extras"
depends on ACPI
@@ -604,6 +573,7 @@ config TOPSTAR_LAPTOP
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on ACPI
+ depends on ACPI_WMI
select LEDS_CLASS
select NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
@@ -746,13 +716,18 @@ config XO15_EBOOK
config SAMSUNG_LAPTOP
tristate "Samsung Laptop driver"
- depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+ depends on X86
+ depends on RFKILL || RFKILL = n
+ depends on BACKLIGHT_CLASS_DEVICE
+ select LEDS_CLASS
+ select NEW_LEDS
---help---
This module implements a driver for a wide range of different
Samsung laptops. It offers control over the different
- function keys, wireless LED, LCD backlight level, and
- sometimes provides a "performance_control" sysfs file to allow
- the performance level of the laptop to be changed.
+ function keys, wireless LED, LCD backlight level.
+
+ It may also provide some sysfs files described in
+ <file:Documentation/ABI/testing/sysfs-platform-samsung-laptop>
To compile this driver as a module, choose M here: the module
will be called samsung-laptop.
@@ -781,4 +756,14 @@ config SAMSUNG_Q10
This driver provides support for backlight control on Samsung Q10
and related laptops, including Dell Latitude X200.
+config APPLE_GMUX
+ tristate "Apple Gmux Driver"
+ depends on PNP
+ select BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This driver provides support for the gmux device found on many
+ Apple laptops, which controls the display mux for the hybrid
+ graphics as well as the backlight. Currently only backlight
+ control is supported by the driver.
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index bb947657d490..bf7e4f935b17 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -29,9 +29,12 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ACPI_WMI) += wmi.o
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
-obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
+
+# toshiba_acpi must link after wmi to ensure that wmi devices are found
+# before toshiba_acpi initializes
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
+
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
@@ -46,3 +49,4 @@ obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
+obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 1e5290b5396d..c1a3fd8e1243 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -43,6 +43,7 @@
#include <linux/input/sparse-keymap.h>
#include <acpi/acpi_drivers.h>
+#include <acpi/video.h>
MODULE_AUTHOR("Carlos Corbacho");
MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
@@ -105,13 +106,19 @@ static const struct key_entry acer_wmi_keymap[] = {
{KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
{KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
{KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
+ {KE_KEY, 0x29, {KEY_PROG3} }, /* P_Key for TM8372 */
{KE_IGNORE, 0x41, {KEY_MUTE} },
{KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
+ {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
{KE_IGNORE, 0x43, {KEY_NEXTSONG} },
+ {KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
{KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
+ {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
{KE_IGNORE, 0x45, {KEY_STOP} },
+ {KE_IGNORE, 0x50, {KEY_STOP} },
{KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
{KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
+ {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
{KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
{KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
{KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
@@ -153,7 +160,14 @@ struct lm_return_value {
u16 reserved;
} __attribute__((packed));
-struct wmid3_gds_input_param { /* Get Device Status input parameter */
+struct wmid3_gds_set_input_param { /* Set Device Status input parameter */
+ u8 function_num; /* Function Number */
+ u8 hotkey_number; /* Hotkey Number */
+ u16 devices; /* Set Device */
+ u8 volume_value; /* Volume Value */
+} __attribute__((packed));
+
+struct wmid3_gds_get_input_param { /* Get Device Status input parameter */
u8 function_num; /* Function Number */
u8 hotkey_number; /* Hotkey Number */
u16 devices; /* Get Device */
@@ -171,6 +185,11 @@ struct hotkey_function_type_aa {
u8 length;
u16 handle;
u16 commun_func_bitmap;
+ u16 application_func_bitmap;
+ u16 media_func_bitmap;
+ u16 display_func_bitmap;
+ u16 others_func_bitmap;
+ u8 commun_fn_key_number;
} __attribute__((packed));
/*
@@ -207,6 +226,7 @@ static int force_series;
static bool ec_raw_mode;
static bool has_type_aa;
static u16 commun_func_bitmap;
+static u8 commun_fn_key_number;
module_param(mailled, int, 0444);
module_param(brightness, int, 0444);
@@ -468,6 +488,15 @@ static struct dmi_system_id acer_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "Lenovo Ideapad S205 (Brazos)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
+ },
+ .driver_data = &quirk_lenovo_ideapad_s205,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Lenovo 3000 N200",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -478,6 +507,25 @@ static struct dmi_system_id acer_quirks[] = {
{}
};
+static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
+{
+ interface->capability &= ~ACER_CAP_BRIGHTNESS;
+ pr_info("Brightness must be controlled by generic video driver\n");
+ return 0;
+}
+
+static const struct dmi_system_id video_vendor_dmi_table[] = {
+ {
+ .callback = video_set_backlight_video_vendor,
+ .ident = "Acer TravelMate 4750",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
+ },
+ },
+ {}
+};
+
/* Find which quirks are needed for a particular vendor/ model pair */
static void find_quirks(void)
{
@@ -536,8 +584,7 @@ struct acpi_buffer *result)
return status;
}
-static acpi_status AMW0_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status AMW0_get_u32(u32 *value, u32 cap)
{
int err;
u8 result;
@@ -607,7 +654,7 @@ struct wmi_interface *iface)
return AE_OK;
}
-static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status AMW0_set_u32(u32 value, u32 cap)
{
struct wmab_args args;
@@ -692,6 +739,7 @@ static const struct acpi_device_id norfkill_ids[] = {
{ "VPC2004", 0},
{ "IBM0068", 0},
{ "LEN0068", 0},
+ { "SNY5001", 0}, /* sony-laptop in charge */
{ "", 0},
};
@@ -827,8 +875,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
return status;
}
-static acpi_status WMID_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status WMID_get_u32(u32 *value, u32 cap)
{
acpi_status status;
u8 tmp;
@@ -864,7 +911,7 @@ struct wmi_interface *iface)
return status;
}
-static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status WMID_set_u32(u32 value, u32 cap)
{
u32 method_id = 0;
char param;
@@ -912,13 +959,13 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
struct wmid3_gds_return_value return_value;
acpi_status status;
union acpi_object *obj;
- struct wmid3_gds_input_param params = {
+ struct wmid3_gds_get_input_param params = {
.function_num = 0x1,
- .hotkey_number = 0x01,
+ .hotkey_number = commun_fn_key_number,
.devices = device,
};
struct acpi_buffer input = {
- sizeof(struct wmid3_gds_input_param),
+ sizeof(struct wmid3_gds_get_input_param),
&params
};
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -981,19 +1028,28 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
acpi_status status;
union acpi_object *obj;
u16 devices;
- struct wmid3_gds_input_param params = {
+ struct wmid3_gds_get_input_param get_params = {
.function_num = 0x1,
- .hotkey_number = 0x01,
+ .hotkey_number = commun_fn_key_number,
.devices = commun_func_bitmap,
};
- struct acpi_buffer input = {
- sizeof(struct wmid3_gds_input_param),
- &params
+ struct acpi_buffer get_input = {
+ sizeof(struct wmid3_gds_get_input_param),
+ &get_params
+ };
+ struct wmid3_gds_set_input_param set_params = {
+ .function_num = 0x2,
+ .hotkey_number = commun_fn_key_number,
+ .devices = commun_func_bitmap,
+ };
+ struct acpi_buffer set_input = {
+ sizeof(struct wmid3_gds_set_input_param),
+ &set_params
};
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
- status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+ status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
if (ACPI_FAILURE(status))
return status;
@@ -1006,7 +1062,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
return AE_ERROR;
}
if (obj->buffer.length != 8) {
- pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+ pr_warn("Unknown buffer length %d\n", obj->buffer.length);
kfree(obj);
return AE_ERROR;
}
@@ -1015,18 +1071,16 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
kfree(obj);
if (return_value.error_code || return_value.ec_return_value) {
- pr_warning("Get Current Device Status failed: "
- "0x%x - 0x%x\n", return_value.error_code,
+ pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
+ return_value.error_code,
return_value.ec_return_value);
return status;
}
devices = return_value.devices;
- params.function_num = 0x2;
- params.hotkey_number = 0x01;
- params.devices = (value) ? (devices | device) : (devices & ~device);
+ set_params.devices = (value) ? (devices | device) : (devices & ~device);
- status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
+ status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
if (ACPI_FAILURE(status))
return status;
@@ -1039,7 +1093,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
return AE_ERROR;
}
if (obj->buffer.length != 4) {
- pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+ pr_warn("Unknown buffer length %d\n", obj->buffer.length);
kfree(obj);
return AE_ERROR;
}
@@ -1048,8 +1102,8 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
kfree(obj);
if (return_value.error_code || return_value.ec_return_value)
- pr_warning("Set Device Status failed: "
- "0x%x - 0x%x\n", return_value.error_code,
+ pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
+ return_value.error_code,
return_value.ec_return_value);
return status;
@@ -1096,6 +1150,8 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
interface->capability |= ACER_CAP_THREEG;
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
interface->capability |= ACER_CAP_BLUETOOTH;
+
+ commun_fn_key_number = type_aa->commun_fn_key_number;
}
static acpi_status WMID_set_capabilities(void)
@@ -1154,15 +1210,15 @@ static acpi_status get_u32(u32 *value, u32 cap)
switch (interface->type) {
case ACER_AMW0:
- status = AMW0_get_u32(value, cap, interface);
+ status = AMW0_get_u32(value, cap);
break;
case ACER_AMW0_V2:
if (cap == ACER_CAP_MAILLED) {
- status = AMW0_get_u32(value, cap, interface);
+ status = AMW0_get_u32(value, cap);
break;
}
case ACER_WMID:
- status = WMID_get_u32(value, cap, interface);
+ status = WMID_get_u32(value, cap);
break;
case ACER_WMID_v2:
if (cap & (ACER_CAP_WIRELESS |
@@ -1170,7 +1226,7 @@ static acpi_status get_u32(u32 *value, u32 cap)
ACER_CAP_THREEG))
status = wmid_v2_get_u32(value, cap);
else if (wmi_has_guid(WMID_GUID2))
- status = WMID_get_u32(value, cap, interface);
+ status = WMID_get_u32(value, cap);
break;
}
@@ -1184,10 +1240,10 @@ static acpi_status set_u32(u32 value, u32 cap)
if (interface->capability & cap) {
switch (interface->type) {
case ACER_AMW0:
- return AMW0_set_u32(value, cap, interface);
+ return AMW0_set_u32(value, cap);
case ACER_AMW0_V2:
if (cap == ACER_CAP_MAILLED)
- return AMW0_set_u32(value, cap, interface);
+ return AMW0_set_u32(value, cap);
/*
* On some models, some WMID methods don't toggle
@@ -1197,21 +1253,21 @@ static acpi_status set_u32(u32 value, u32 cap)
*/
if (cap == ACER_CAP_WIRELESS ||
cap == ACER_CAP_BLUETOOTH) {
- status = WMID_set_u32(value, cap, interface);
+ status = WMID_set_u32(value, cap);
if (ACPI_FAILURE(status))
return status;
- return AMW0_set_u32(value, cap, interface);
+ return AMW0_set_u32(value, cap);
}
case ACER_WMID:
- return WMID_set_u32(value, cap, interface);
+ return WMID_set_u32(value, cap);
case ACER_WMID_v2:
if (cap & (ACER_CAP_WIRELESS |
ACER_CAP_BLUETOOTH |
ACER_CAP_THREEG))
return wmid_v2_set_u32(value, cap);
else if (wmi_has_guid(WMID_GUID2))
- return WMID_set_u32(value, cap, interface);
+ return WMID_set_u32(value, cap);
default:
return AE_BAD_PARAMETER;
}
@@ -1488,8 +1544,8 @@ static ssize_t show_bool_threeg(struct device *dev,
u32 result; \
acpi_status status;
- pr_info("This threeg sysfs will be removed in 2012"
- " - used by: %s\n", current->comm);
+ pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+ current->comm);
status = get_u32(&result, ACER_CAP_THREEG);
if (ACPI_SUCCESS(status))
return sprintf(buf, "%u\n", result);
@@ -1501,8 +1557,8 @@ static ssize_t set_bool_threeg(struct device *dev,
{
u32 tmp = simple_strtoul(buf, NULL, 10);
acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
- pr_info("This threeg sysfs will be removed in 2012"
- " - used by: %s\n", current->comm);
+ pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+ current->comm);
if (ACPI_FAILURE(status))
return -EINVAL;
return count;
@@ -1513,8 +1569,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
- pr_info("This interface sysfs will be removed in 2012"
- " - used by: %s\n", current->comm);
+ pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
+ current->comm);
switch (interface->type) {
case ACER_AMW0:
return sprintf(buf, "AMW0\n");
@@ -1981,9 +2037,13 @@ static int __init acer_wmi_init(void)
set_quirks();
if (acpi_video_backlight_support()) {
- interface->capability &= ~ACER_CAP_BRIGHTNESS;
- pr_info("Brightness must be controlled by "
- "generic video driver\n");
+ if (dmi_check_system(video_vendor_dmi_table)) {
+ acpi_video_unregister();
+ } else {
+ interface->capability &= ~ACER_CAP_BRIGHTNESS;
+ pr_info("Brightness must be controlled by "
+ "acpi video driver\n");
+ }
}
if (wmi_has_guid(WMID_GUID3)) {
@@ -2008,7 +2068,7 @@ static int __init acer_wmi_init(void)
err = platform_driver_register(&acer_platform_driver);
if (err) {
- pr_err("Unable to register platform driver.\n");
+ pr_err("Unable to register platform driver\n");
goto error_platform_register;
}
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 760c6d7624fe..bc8384c6f3eb 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -244,12 +244,11 @@ static void acerhdf_change_fanstate(int state)
unsigned char cmd;
if (verbose)
- pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ?
- "OFF" : "ON");
+ pr_notice("fan %s\n", state == ACERHDF_FAN_OFF ? "OFF" : "ON");
if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
pr_err("invalid fan state %d requested, setting to auto!\n",
- state);
+ state);
state = ACERHDF_FAN_AUTO;
}
@@ -264,19 +263,18 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
{
if (fanon > ACERHDF_MAX_FANON) {
pr_err("fanon temperature too high, set to %d\n",
- ACERHDF_MAX_FANON);
+ ACERHDF_MAX_FANON);
fanon = ACERHDF_MAX_FANON;
}
if (kernelmode && prev_interval != interval) {
if (interval > ACERHDF_MAX_INTERVAL) {
pr_err("interval too high, set to %d\n",
- ACERHDF_MAX_INTERVAL);
+ ACERHDF_MAX_INTERVAL);
interval = ACERHDF_MAX_INTERVAL;
}
if (verbose)
- pr_notice("interval changed to: %d\n",
- interval);
+ pr_notice("interval changed to: %d\n", interval);
thermal->polling_delay = interval*1000;
prev_interval = interval;
}
@@ -587,8 +585,8 @@ static int acerhdf_check_hardware(void)
}
if (!bios_cfg) {
- pr_err("unknown (unsupported) BIOS version %s/%s/%s, "
- "please report, aborting!\n", vendor, product, version);
+ pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n",
+ vendor, product, version);
return -EINVAL;
}
@@ -598,8 +596,7 @@ static int acerhdf_check_hardware(void)
*/
if (!kernelmode) {
pr_notice("Fan control off, to enable do:\n");
- pr_notice("echo -n \"enabled\" > "
- "/sys/class/thermal/thermal_zone0/mode\n");
+ pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zone0/mode\n");
}
return 0;
diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c
index 19170bb7700b..a514bf66fdd7 100644
--- a/drivers/platform/x86/amilo-rfkill.c
+++ b/drivers/platform/x86/amilo-rfkill.c
@@ -97,9 +97,12 @@ static struct rfkill *amilo_rfkill_dev;
static int __devinit amilo_rfkill_probe(struct platform_device *device)
{
+ int rc;
const struct dmi_system_id *system_id =
dmi_first_match(amilo_rfkill_id_table);
- int rc;
+
+ if (!system_id)
+ return -ENXIO;
amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
RFKILL_TYPE_WLAN,
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
new file mode 100644
index 000000000000..8a582bdfdc76
--- /dev/null
+++ b/drivers/platform/x86/apple-gmux.c
@@ -0,0 +1,244 @@
+/*
+ * Gmux driver for Apple laptops
+ *
+ * Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/backlight.h>
+#include <linux/acpi.h>
+#include <linux/pnp.h>
+#include <linux/apple_bl.h>
+#include <linux/slab.h>
+#include <acpi/video.h>
+#include <asm/io.h>
+
+struct apple_gmux_data {
+ unsigned long iostart;
+ unsigned long iolen;
+
+ struct backlight_device *bdev;
+};
+
+/*
+ * gmux port offsets. Many of these are not yet used, but may be in the
+ * future, and it's useful to have them documented here anyhow.
+ */
+#define GMUX_PORT_VERSION_MAJOR 0x04
+#define GMUX_PORT_VERSION_MINOR 0x05
+#define GMUX_PORT_VERSION_RELEASE 0x06
+#define GMUX_PORT_SWITCH_DISPLAY 0x10
+#define GMUX_PORT_SWITCH_GET_DISPLAY 0x11
+#define GMUX_PORT_INTERRUPT_ENABLE 0x14
+#define GMUX_PORT_INTERRUPT_STATUS 0x16
+#define GMUX_PORT_SWITCH_DDC 0x28
+#define GMUX_PORT_SWITCH_EXTERNAL 0x40
+#define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41
+#define GMUX_PORT_DISCRETE_POWER 0x50
+#define GMUX_PORT_MAX_BRIGHTNESS 0x70
+#define GMUX_PORT_BRIGHTNESS 0x74
+
+#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
+
+#define GMUX_INTERRUPT_ENABLE 0xff
+#define GMUX_INTERRUPT_DISABLE 0x00
+
+#define GMUX_INTERRUPT_STATUS_ACTIVE 0
+#define GMUX_INTERRUPT_STATUS_DISPLAY (1 << 0)
+#define GMUX_INTERRUPT_STATUS_POWER (1 << 2)
+#define GMUX_INTERRUPT_STATUS_HOTPLUG (1 << 3)
+
+#define GMUX_BRIGHTNESS_MASK 0x00ffffff
+#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
+
+static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
+{
+ return inb(gmux_data->iostart + port);
+}
+
+static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
+ u8 val)
+{
+ outb(val, gmux_data->iostart + port);
+}
+
+static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
+{
+ return inl(gmux_data->iostart + port);
+}
+
+static int gmux_get_brightness(struct backlight_device *bd)
+{
+ struct apple_gmux_data *gmux_data = bl_get_data(bd);
+ return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) &
+ GMUX_BRIGHTNESS_MASK;
+}
+
+static int gmux_update_status(struct backlight_device *bd)
+{
+ struct apple_gmux_data *gmux_data = bl_get_data(bd);
+ u32 brightness = bd->props.brightness;
+
+ /*
+ * Older gmux versions require writing out lower bytes first then
+ * setting the upper byte to 0 to flush the values. Newer versions
+ * accept a single u32 write, but the old method also works, so we
+ * just use the old method for all gmux versions.
+ */
+ gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
+ gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
+ gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
+ gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
+
+ return 0;
+}
+
+static const struct backlight_ops gmux_bl_ops = {
+ .get_brightness = gmux_get_brightness,
+ .update_status = gmux_update_status,
+};
+
+static int __devinit gmux_probe(struct pnp_dev *pnp,
+ const struct pnp_device_id *id)
+{
+ struct apple_gmux_data *gmux_data;
+ struct resource *res;
+ struct backlight_properties props;
+ struct backlight_device *bdev;
+ u8 ver_major, ver_minor, ver_release;
+ int ret = -ENXIO;
+
+ gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
+ if (!gmux_data)
+ return -ENOMEM;
+ pnp_set_drvdata(pnp, gmux_data);
+
+ res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
+ if (!res) {
+ pr_err("Failed to find gmux I/O resource\n");
+ goto err_free;
+ }
+
+ gmux_data->iostart = res->start;
+ gmux_data->iolen = res->end - res->start;
+
+ if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
+ pr_err("gmux I/O region too small (%lu < %u)\n",
+ gmux_data->iolen, GMUX_MIN_IO_LEN);
+ goto err_free;
+ }
+
+ if (!request_region(gmux_data->iostart, gmux_data->iolen,
+ "Apple gmux")) {
+ pr_err("gmux I/O already in use\n");
+ goto err_free;
+ }
+
+ /*
+ * On some machines the gmux is in ACPI even thought the machine
+ * doesn't really have a gmux. Check for invalid version information
+ * to detect this.
+ */
+ ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
+ ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
+ ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
+ if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
+ pr_info("gmux device not present\n");
+ ret = -ENODEV;
+ goto err_release;
+ }
+
+ pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
+ ver_release);
+
+ memset(&props, 0, sizeof(props));
+ props.type = BACKLIGHT_PLATFORM;
+ props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
+
+ /*
+ * Currently it's assumed that the maximum brightness is less than
+ * 2^24 for compatibility with old gmux versions. Cap the max
+ * brightness at this value, but print a warning if the hardware
+ * reports something higher so that it can be fixed.
+ */
+ if (WARN_ON(props.max_brightness > GMUX_MAX_BRIGHTNESS))
+ props.max_brightness = GMUX_MAX_BRIGHTNESS;
+
+ bdev = backlight_device_register("gmux_backlight", &pnp->dev,
+ gmux_data, &gmux_bl_ops, &props);
+ if (IS_ERR(bdev)) {
+ ret = PTR_ERR(bdev);
+ goto err_release;
+ }
+
+ gmux_data->bdev = bdev;
+ bdev->props.brightness = gmux_get_brightness(bdev);
+ backlight_update_status(bdev);
+
+ /*
+ * The backlight situation on Macs is complicated. If the gmux is
+ * present it's the best choice, because it always works for
+ * backlight control and supports more levels than other options.
+ * Disable the other backlight choices.
+ */
+ acpi_video_unregister();
+ apple_bl_unregister();
+
+ return 0;
+
+err_release:
+ release_region(gmux_data->iostart, gmux_data->iolen);
+err_free:
+ kfree(gmux_data);
+ return ret;
+}
+
+static void __devexit gmux_remove(struct pnp_dev *pnp)
+{
+ struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+
+ backlight_device_unregister(gmux_data->bdev);
+ release_region(gmux_data->iostart, gmux_data->iolen);
+ kfree(gmux_data);
+
+ acpi_video_register();
+ apple_bl_register();
+}
+
+static const struct pnp_device_id gmux_device_ids[] = {
+ {"APP000B", 0},
+ {"", 0}
+};
+
+static struct pnp_driver gmux_pnp_driver = {
+ .name = "apple-gmux",
+ .probe = gmux_probe,
+ .remove = __devexit_p(gmux_remove),
+ .id_table = gmux_device_ids,
+};
+
+static int __init apple_gmux_init(void)
+{
+ return pnp_register_driver(&gmux_pnp_driver);
+}
+
+static void __exit apple_gmux_exit(void)
+{
+ pnp_unregister_driver(&gmux_pnp_driver);
+}
+
+module_init(apple_gmux_init);
+module_exit(apple_gmux_exit);
+
+MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>");
+MODULE_DESCRIPTION("Apple Gmux Driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pnp, gmux_device_ids);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b7944f903886..e38f91be0b10 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -81,6 +81,19 @@ static uint wapf = 1;
module_param(wapf, uint, 0444);
MODULE_PARM_DESC(wapf, "WAPF value");
+static char *wled_type = "unknown";
+static char *bled_type = "unknown";
+
+module_param(wled_type, charp, 0444);
+MODULE_PARM_DESC(wlan_status, "Set the wled type on boot "
+ "(unknown, led or rfkill). "
+ "default is unknown");
+
+module_param(bled_type, charp, 0444);
+MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
+ "(unknown, led or rfkill). "
+ "default is unknown");
+
static int wlan_status = 1;
static int bluetooth_status = 1;
static int wimax_status = -1;
@@ -137,6 +150,11 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
#define WM_RSTS 0x08 /* internal wimax */
#define WW_RSTS 0x20 /* internal wwan */
+/* WLED and BLED type */
+#define TYPE_UNKNOWN 0
+#define TYPE_LED 1
+#define TYPE_RFKILL 2
+
/* LED */
#define METHOD_MLED "MLED"
#define METHOD_TLED "TLED"
@@ -218,8 +236,9 @@ struct asus_led {
/*
* Same thing for rfkill
*/
-struct asus_pega_rfkill {
- int control_id; /* type of control. Maps to PEGA_* values */
+struct asus_rfkill {
+ /* type of control. Maps to PEGA_* values or *_RSTS */
+ int control_id;
struct rfkill *rfkill;
struct asus_laptop *asus;
};
@@ -240,6 +259,8 @@ struct asus_laptop {
struct key_entry *keymap;
struct input_polled_dev *pega_accel_poll;
+ struct asus_led wled;
+ struct asus_led bled;
struct asus_led mled;
struct asus_led tled;
struct asus_led rled;
@@ -248,6 +269,8 @@ struct asus_laptop {
struct asus_led kled;
struct workqueue_struct *led_workqueue;
+ int wled_type;
+ int bled_type;
int wireless_status;
bool have_rsts;
bool is_pega_lucid;
@@ -256,11 +279,11 @@ struct asus_laptop {
int pega_acc_y;
int pega_acc_z;
- struct rfkill *gps_rfkill;
-
- struct asus_pega_rfkill wlanrfk;
- struct asus_pega_rfkill btrfk;
- struct asus_pega_rfkill wwanrfk;
+ struct asus_rfkill wlan;
+ struct asus_rfkill bluetooth;
+ struct asus_rfkill wwan;
+ struct asus_rfkill wimax;
+ struct asus_rfkill gps;
acpi_handle handle; /* the handle of the hotk device */
u32 ledd_status; /* status of the LED display */
@@ -274,6 +297,7 @@ static const struct key_entry asus_keymap[] = {
{KE_KEY, 0x02, { KEY_SCREENLOCK } },
{KE_KEY, 0x05, { KEY_WLAN } },
{KE_KEY, 0x08, { KEY_F13 } },
+ {KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
{KE_KEY, 0x17, { KEY_ZOOM } },
{KE_KEY, 0x1f, { KEY_BATTERY } },
/* End of Lenovo SL Specific keycodes */
@@ -299,6 +323,8 @@ static const struct key_entry asus_keymap[] = {
{KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
+ {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
+ {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
{KE_KEY, 0x7E, { KEY_BLUETOOTH } },
{KE_KEY, 0x7D, { KEY_BLUETOOTH } },
{KE_KEY, 0x82, { KEY_CAMERA } },
@@ -601,6 +627,10 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
static void asus_led_exit(struct asus_laptop *asus)
{
+ if (!IS_ERR_OR_NULL(asus->wled.led.dev))
+ led_classdev_unregister(&asus->wled.led);
+ if (!IS_ERR_OR_NULL(asus->bled.led.dev))
+ led_classdev_unregister(&asus->bled.led);
if (!IS_ERR_OR_NULL(asus->mled.led.dev))
led_classdev_unregister(&asus->mled.led);
if (!IS_ERR_OR_NULL(asus->tled.led.dev))
@@ -642,7 +672,7 @@ static int asus_led_register(struct asus_laptop *asus,
static int asus_led_init(struct asus_laptop *asus)
{
- int r;
+ int r = 0;
/*
* The Pegatron Lucid has no physical leds, but all methods are
@@ -661,6 +691,16 @@ static int asus_led_init(struct asus_laptop *asus)
if (!asus->led_workqueue)
return -ENOMEM;
+ if (asus->wled_type == TYPE_LED)
+ r = asus_led_register(asus, &asus->wled, "asus::wlan",
+ METHOD_WLAN);
+ if (r)
+ goto error;
+ if (asus->bled_type == TYPE_LED)
+ r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
+ METHOD_BLUETOOTH);
+ if (r)
+ goto error;
r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
if (r)
goto error;
@@ -963,7 +1003,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
}
-/*
+/*e
* Bluetooth
*/
static int asus_bluetooth_set(struct asus_laptop *asus, int status)
@@ -1228,7 +1268,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
ret = asus_gps_switch(asus, !!value);
if (ret)
return ret;
- rfkill_set_sw_state(asus->gps_rfkill, !value);
+ rfkill_set_sw_state(asus->gps.rfkill, !value);
return rv;
}
@@ -1246,90 +1286,139 @@ static const struct rfkill_ops asus_gps_rfkill_ops = {
.set_block = asus_gps_rfkill_set,
};
+static int asus_rfkill_set(void *data, bool blocked)
+{
+ struct asus_rfkill *rfk = data;
+ struct asus_laptop *asus = rfk->asus;
+
+ if (rfk->control_id == WL_RSTS)
+ return asus_wlan_set(asus, !blocked);
+ else if (rfk->control_id == BT_RSTS)
+ return asus_bluetooth_set(asus, !blocked);
+ else if (rfk->control_id == WM_RSTS)
+ return asus_wimax_set(asus, !blocked);
+ else if (rfk->control_id == WW_RSTS)
+ return asus_wwan_set(asus, !blocked);
+
+ return -EINVAL;
+}
+
+static const struct rfkill_ops asus_rfkill_ops = {
+ .set_block = asus_rfkill_set,
+};
+
+static void asus_rfkill_terminate(struct asus_rfkill *rfk)
+{
+ if (!rfk->rfkill)
+ return ;
+
+ rfkill_unregister(rfk->rfkill);
+ rfkill_destroy(rfk->rfkill);
+ rfk->rfkill = NULL;
+}
+
static void asus_rfkill_exit(struct asus_laptop *asus)
{
- if (asus->gps_rfkill) {
- rfkill_unregister(asus->gps_rfkill);
- rfkill_destroy(asus->gps_rfkill);
- asus->gps_rfkill = NULL;
- }
+ asus_rfkill_terminate(&asus->wwan);
+ asus_rfkill_terminate(&asus->bluetooth);
+ asus_rfkill_terminate(&asus->wlan);
+ asus_rfkill_terminate(&asus->gps);
}
-static int asus_rfkill_init(struct asus_laptop *asus)
+static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
+ const char *name, int control_id, int type,
+ const struct rfkill_ops *ops)
{
int result;
- if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) ||
- acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) ||
- acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
- return 0;
-
- asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
- RFKILL_TYPE_GPS,
- &asus_gps_rfkill_ops, asus);
- if (!asus->gps_rfkill)
+ rfk->control_id = control_id;
+ rfk->asus = asus;
+ rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
+ type, ops, rfk);
+ if (!rfk->rfkill)
return -EINVAL;
- result = rfkill_register(asus->gps_rfkill);
+ result = rfkill_register(rfk->rfkill);
if (result) {
- rfkill_destroy(asus->gps_rfkill);
- asus->gps_rfkill = NULL;
+ rfkill_destroy(rfk->rfkill);
+ rfk->rfkill = NULL;
}
return result;
}
-static int pega_rfkill_set(void *data, bool blocked)
+static int asus_rfkill_init(struct asus_laptop *asus)
{
- struct asus_pega_rfkill *pega_rfk = data;
+ int result = 0;
- int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked);
- pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret);
+ if (asus->is_pega_lucid)
+ return -ENODEV;
- return ret;
-}
+ if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
+ !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
+ result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
+ -1, RFKILL_TYPE_GPS,
+ &asus_gps_rfkill_ops);
+ if (result)
+ goto exit;
-static const struct rfkill_ops pega_rfkill_ops = {
- .set_block = pega_rfkill_set,
-};
-static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk)
-{
- pr_warn("Terminating %d\n", pega_rfk->control_id);
- if (pega_rfk->rfkill) {
- rfkill_unregister(pega_rfk->rfkill);
- rfkill_destroy(pega_rfk->rfkill);
- pega_rfk->rfkill = NULL;
- }
-}
+ if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
+ asus->wled_type == TYPE_RFKILL)
+ result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
+ WL_RSTS, RFKILL_TYPE_WLAN,
+ &asus_rfkill_ops);
+ if (result)
+ goto exit;
-static void pega_rfkill_exit(struct asus_laptop *asus)
-{
- pega_rfkill_terminate(&asus->wwanrfk);
- pega_rfkill_terminate(&asus->btrfk);
- pega_rfkill_terminate(&asus->wlanrfk);
+ if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
+ asus->bled_type == TYPE_RFKILL)
+ result = asus_rfkill_setup(asus, &asus->bluetooth,
+ "asus-bluetooth", BT_RSTS,
+ RFKILL_TYPE_BLUETOOTH,
+ &asus_rfkill_ops);
+ if (result)
+ goto exit;
+
+ if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
+ result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
+ WW_RSTS, RFKILL_TYPE_WWAN,
+ &asus_rfkill_ops);
+ if (result)
+ goto exit;
+
+ if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
+ result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
+ WM_RSTS, RFKILL_TYPE_WIMAX,
+ &asus_rfkill_ops);
+ if (result)
+ goto exit;
+
+exit:
+ if (result)
+ asus_rfkill_exit(asus);
+
+ return result;
}
-static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk,
- const char *name, int controlid, int rfkill_type)
+static int pega_rfkill_set(void *data, bool blocked)
{
- int result;
+ struct asus_rfkill *rfk = data;
- pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type);
- pega_rfk->control_id = controlid;
- pega_rfk->asus = asus;
- pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
- rfkill_type, &pega_rfkill_ops, pega_rfk);
- if (!pega_rfk->rfkill)
- return -EINVAL;
+ int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
+ return ret;
+}
- result = rfkill_register(pega_rfk->rfkill);
- if (result) {
- rfkill_destroy(pega_rfk->rfkill);
- pega_rfk->rfkill = NULL;
- }
+static const struct rfkill_ops pega_rfkill_ops = {
+ .set_block = pega_rfkill_set,
+};
- return result;
+static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
+ const char *name, int controlid, int rfkill_type)
+{
+ return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
+ &pega_rfkill_ops);
}
static int pega_rfkill_init(struct asus_laptop *asus)
@@ -1339,22 +1428,22 @@ static int pega_rfkill_init(struct asus_laptop *asus)
if(!asus->is_pega_lucid)
return -ENODEV;
- ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN);
- if(ret)
- return ret;
- ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
+ ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
+ PEGA_WLAN, RFKILL_TYPE_WLAN);
if(ret)
- goto err_btrfk;
- ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN);
+ goto exit;
+
+ ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
+ PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
if(ret)
- goto err_wwanrfk;
+ goto exit;
- pr_warn("Pega rfkill init succeeded\n");
- return 0;
-err_wwanrfk:
- pega_rfkill_terminate(&asus->btrfk);
-err_btrfk:
- pega_rfkill_terminate(&asus->wlanrfk);
+ ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
+ PEGA_WWAN, RFKILL_TYPE_WWAN);
+
+exit:
+ if (ret)
+ asus_rfkill_exit(asus);
return ret;
}
@@ -1364,8 +1453,10 @@ err_btrfk:
*/
static void asus_input_notify(struct asus_laptop *asus, int event)
{
- if (asus->inputdev)
- sparse_keymap_report_event(asus->inputdev, event, 1, true);
+ if (!asus->inputdev)
+ return ;
+ if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
+ pr_info("Unknown key %x pressed\n", event);
}
static int asus_input_init(struct asus_laptop *asus)
@@ -1375,7 +1466,7 @@ static int asus_input_init(struct asus_laptop *asus)
input = input_allocate_device();
if (!input) {
- pr_info("Unable to allocate input device\n");
+ pr_warn("Unable to allocate input device\n");
return -ENOMEM;
}
input->name = "Asus Laptop extra buttons";
@@ -1390,7 +1481,7 @@ static int asus_input_init(struct asus_laptop *asus)
}
error = input_register_device(input);
if (error) {
- pr_info("Unable to register input device\n");
+ pr_warn("Unable to register input device\n");
goto err_free_keymap;
}
@@ -1688,7 +1779,16 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
if (result)
return result;
- /* WLED and BLED are on by default */
+ if (!strcmp(bled_type, "led"))
+ asus->bled_type = TYPE_LED;
+ else if (!strcmp(bled_type, "rfkill"))
+ asus->bled_type = TYPE_RFKILL;
+
+ if (!strcmp(wled_type, "led"))
+ asus->wled_type = TYPE_LED;
+ else if (!strcmp(wled_type, "rfkill"))
+ asus->wled_type = TYPE_RFKILL;
+
if (bluetooth_status >= 0)
asus_bluetooth_set(asus, !!bluetooth_status);
@@ -1786,7 +1886,7 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
goto fail_led;
result = asus_rfkill_init(asus);
- if (result)
+ if (result && result != -ENODEV)
goto fail_rfkill;
result = pega_accel_init(asus);
@@ -1828,7 +1928,6 @@ static int asus_acpi_remove(struct acpi_device *device, int type)
asus_led_exit(asus);
asus_input_exit(asus);
pega_accel_exit(asus);
- pega_rfkill_exit(asus);
asus_platform_exit(asus);
kfree(asus->name);
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index b0859d4183e8..99a30b513137 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
+#include <linux/fb.h>
#include "asus-wmi.h"
@@ -51,9 +52,14 @@ static uint wapf;
module_param(wapf, uint, 0444);
MODULE_PARM_DESC(wapf, "WAPF value");
+static struct quirk_entry quirk_asus_unknown = {
+};
+
static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
{
- driver->wapf = wapf;
+ driver->quirks = &quirk_asus_unknown;
+ driver->quirks->wapf = wapf;
+ driver->panel_power = FB_BLANK_UNBLANK;
}
static const struct key_entry asus_nb_wmi_keymap[] = {
@@ -70,6 +76,8 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x50, { KEY_EMAIL } },
{ KE_KEY, 0x51, { KEY_WWW } },
{ KE_KEY, 0x55, { KEY_CALC } },
+ { KE_IGNORE, 0x57, }, /* Battery mode */
+ { KE_IGNORE, 0x58, }, /* AC mode */
{ KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */
{ KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
{ KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
@@ -99,7 +107,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
.keymap = asus_nb_wmi_keymap,
.input_name = "Asus WMI hotkeys",
.input_phys = ASUS_NB_WMI_FILE "/input0",
- .quirks = asus_nb_wmi_quirks,
+ .detect_quirks = asus_nb_wmi_quirks,
};
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 9929246895de..77aadde5281c 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -411,7 +411,7 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
if (retval >= 0) {
if (level)
- *level = retval & 0x80 ? retval & 0x7F : 0;
+ *level = retval & 0x7F;
if (env)
*env = (retval >> 8) & 0x7F;
retval = 0;
@@ -784,7 +784,8 @@ static int asus_new_rfkill(struct asus_wmi *asus,
arfkill->dev_id = dev_id;
arfkill->asus = asus;
- if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless)
+ if (dev_id == ASUS_WMI_DEVID_WLAN &&
+ asus->driver->quirks->hotplug_wireless)
*rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
&asus_rfkill_wlan_ops, arfkill);
else
@@ -895,7 +896,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
if (result && result != -ENODEV)
goto exit;
- if (!asus->driver->hotplug_wireless)
+ if (!asus->driver->quirks->hotplug_wireless)
goto exit;
result = asus_setup_pci_hotplug(asus);
@@ -1075,7 +1076,12 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
*/
static int read_backlight_power(struct asus_wmi *asus)
{
- int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT);
+ int ret;
+ if (asus->driver->quirks->store_backlight_power)
+ ret = !asus->driver->panel_power;
+ else
+ ret = asus_wmi_get_devstate_simple(asus,
+ ASUS_WMI_DEVID_BACKLIGHT);
if (ret < 0)
return ret;
@@ -1116,26 +1122,51 @@ static int read_brightness(struct backlight_device *bd)
return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
}
-static int update_bl_status(struct backlight_device *bd)
+static u32 get_scalar_command(struct backlight_device *bd)
{
struct asus_wmi *asus = bl_get_data(bd);
- u32 ctrl_param;
- int power, err;
+ u32 ctrl_param = 0;
- ctrl_param = bd->props.brightness;
+ if ((asus->driver->brightness < bd->props.brightness) ||
+ bd->props.brightness == bd->props.max_brightness)
+ ctrl_param = 0x00008001;
+ else if ((asus->driver->brightness > bd->props.brightness) ||
+ bd->props.brightness == 0)
+ ctrl_param = 0x00008000;
- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
- ctrl_param, NULL);
+ asus->driver->brightness = bd->props.brightness;
- if (err < 0)
- return err;
+ return ctrl_param;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ struct asus_wmi *asus = bl_get_data(bd);
+ u32 ctrl_param;
+ int power, err = 0;
power = read_backlight_power(asus);
if (power != -ENODEV && bd->props.power != power) {
ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
ctrl_param, NULL);
+ if (asus->driver->quirks->store_backlight_power)
+ asus->driver->panel_power = bd->props.power;
+
+ /* When using scalar brightness, updating the brightness
+ * will mess with the backlight power */
+ if (asus->driver->quirks->scalar_panel_brightness)
+ return err;
}
+
+ if (asus->driver->quirks->scalar_panel_brightness)
+ ctrl_param = get_scalar_command(bd);
+ else
+ ctrl_param = bd->props.brightness;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
+ ctrl_param, NULL);
+
return err;
}
@@ -1196,10 +1227,15 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
asus->backlight_device = bd;
+ if (asus->driver->quirks->store_backlight_power)
+ asus->driver->panel_power = power;
+
bd->props.brightness = read_brightness(bd);
bd->props.power = power;
backlight_update_status(bd);
+ asus->driver->brightness = bd->props.brightness;
+
return 0;
}
@@ -1441,9 +1477,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
/* CWAP allow to define the behavior of the Fn+F2 key,
* this method doesn't seems to be present on Eee PCs */
- if (asus->driver->wapf >= 0)
+ if (asus->driver->quirks->wapf >= 0)
asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
- asus->driver->wapf, NULL);
+ asus->driver->quirks->wapf, NULL);
return asus_wmi_sysfs_init(asus->platform_device);
}
@@ -1622,8 +1658,8 @@ static int asus_wmi_add(struct platform_device *pdev)
wdrv->platform_device = pdev;
platform_set_drvdata(asus->platform_device, asus);
- if (wdrv->quirks)
- wdrv->quirks(asus->driver);
+ if (wdrv->detect_quirks)
+ wdrv->detect_quirks(asus->driver);
err = asus_wmi_platform_init(asus);
if (err)
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 8147c10161cc..d43b66742004 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -35,9 +35,16 @@ struct module;
struct key_entry;
struct asus_wmi;
+struct quirk_entry {
+ bool hotplug_wireless;
+ bool scalar_panel_brightness;
+ bool store_backlight_power;
+ int wapf;
+};
+
struct asus_wmi_driver {
- bool hotplug_wireless;
- int wapf;
+ int brightness;
+ int panel_power;
const char *name;
struct module *owner;
@@ -47,13 +54,14 @@ struct asus_wmi_driver {
const struct key_entry *keymap;
const char *input_name;
const char *input_phys;
+ struct quirk_entry *quirks;
/* Returns new code, value, and autorelease values in arguments.
* Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
void (*key_filter) (struct asus_wmi_driver *driver, int *code,
unsigned int *value, bool *autorelease);
int (*probe) (struct platform_device *device);
- void (*quirks) (struct asus_wmi_driver *driver);
+ void (*detect_quirks) (struct asus_wmi_driver *driver);
struct platform_driver platform_driver;
struct platform_device *platform_device;
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
deleted file mode 100644
index 6f966d6c062b..000000000000
--- a/drivers/platform/x86/asus_acpi.c
+++ /dev/null
@@ -1,1513 +0,0 @@
-/*
- * asus_acpi.c - Asus Laptop ACPI Extras
- *
- *
- * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * The development page for this driver is located at
- * http://sourceforge.net/projects/acpi4asus/
- *
- * Credits:
- * Pontus Fuchs - Helper functions, cleanup
- * Johann Wiesner - Small compile fixes
- * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
- * �ic Burghard - LED display support for W1N
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/backlight.h>
-#include <acpi/acpi_drivers.h>
-#include <acpi/acpi_bus.h>
-#include <asm/uaccess.h>
-
-#define ASUS_ACPI_VERSION "0.30"
-
-#define PROC_ASUS "asus" /* The directory */
-#define PROC_MLED "mled"
-#define PROC_WLED "wled"
-#define PROC_TLED "tled"
-#define PROC_BT "bluetooth"
-#define PROC_LEDD "ledd"
-#define PROC_INFO "info"
-#define PROC_LCD "lcd"
-#define PROC_BRN "brn"
-#define PROC_DISP "disp"
-
-#define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver"
-#define ACPI_HOTK_CLASS "hotkey"
-#define ACPI_HOTK_DEVICE_NAME "Hotkey"
-
-/*
- * Some events we use, same for all Asus
- */
-#define BR_UP 0x10
-#define BR_DOWN 0x20
-
-/*
- * Flags for hotk status
- */
-#define MLED_ON 0x01 /* Mail LED */
-#define WLED_ON 0x02 /* Wireless LED */
-#define TLED_ON 0x04 /* Touchpad LED */
-#define BT_ON 0x08 /* Internal Bluetooth */
-
-MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
-MODULE_DESCRIPTION(ACPI_HOTK_NAME);
-MODULE_LICENSE("GPL");
-
-static uid_t asus_uid;
-static gid_t asus_gid;
-module_param(asus_uid, uint, 0);
-MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
-module_param(asus_gid, uint, 0);
-MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
-
-/* For each model, all features implemented,
- * those marked with R are relative to HOTK, A for absolute */
-struct model_data {
- char *name; /* name of the laptop________________A */
- char *mt_mled; /* method to handle mled_____________R */
- char *mled_status; /* node to handle mled reading_______A */
- char *mt_wled; /* method to handle wled_____________R */
- char *wled_status; /* node to handle wled reading_______A */
- char *mt_tled; /* method to handle tled_____________R */
- char *tled_status; /* node to handle tled reading_______A */
- char *mt_ledd; /* method to handle LED display______R */
- char *mt_bt_switch; /* method to switch Bluetooth on/off_R */
- char *bt_status; /* no model currently supports this__? */
- char *mt_lcd_switch; /* method to turn LCD on/off_________A */
- char *lcd_status; /* node to read LCD panel state______A */
- char *brightness_up; /* method to set brightness up_______A */
- char *brightness_down; /* method to set brightness down ____A */
- char *brightness_set; /* method to set absolute brightness_R */
- char *brightness_get; /* method to get absolute brightness_R */
- char *brightness_status;/* node to get brightness____________A */
- char *display_set; /* method to set video output________R */
- char *display_get; /* method to get video output________R */
-};
-
-/*
- * This is the main structure, we can use it to store anything interesting
- * about the hotk device
- */
-struct asus_hotk {
- struct acpi_device *device; /* the device we are in */
- acpi_handle handle; /* the handle of the hotk device */
- char status; /* status of the hotk, for LEDs */
- u32 ledd_status; /* status of the LED display */
- struct model_data *methods; /* methods available on the laptop */
- u8 brightness; /* brightness level */
- enum {
- A1x = 0, /* A1340D, A1300F */
- A2x, /* A2500H */
- A4G, /* A4700G */
- D1x, /* D1 */
- L2D, /* L2000D */
- L3C, /* L3800C */
- L3D, /* L3400D */
- L3H, /* L3H, L2000E, L5D */
- L4R, /* L4500R */
- L5x, /* L5800C */
- L8L, /* L8400L */
- M1A, /* M1300A */
- M2E, /* M2400E, L4400L */
- M6N, /* M6800N, W3400N */
- M6R, /* M6700R, A3000G */
- P30, /* Samsung P30 */
- S1x, /* S1300A, but also L1400B and M2400A (L84F) */
- S2x, /* S200 (J1 reported), Victor MP-XP7210 */
- W1N, /* W1000N */
- W5A, /* W5A */
- W3V, /* W3030V */
- xxN, /* M2400N, M3700N, M5200N, M6800N,
- S1300N, S5200N*/
- A4S, /* Z81sp */
- F3Sa, /* (Centrino) */
- R1F,
- END_MODEL
- } model; /* Models currently supported */
- u16 event_count[128]; /* Count for each event TODO make this better */
-};
-
-/* Here we go */
-#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
-#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
-#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
-#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
-#define S1x_PREFIX "\\_SB.PCI0.PX40."
-#define S2x_PREFIX A1x_PREFIX
-#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
-
-static struct model_data model_conf[END_MODEL] = {
- /*
- * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
- * it seems to be a kind of switch, but what for ?
- */
-
- {
- .name = "A1x",
- .mt_mled = "MLED",
- .mled_status = "\\MAIL",
- .mt_lcd_switch = A1x_PREFIX "_Q10",
- .lcd_status = "\\BKLI",
- .brightness_up = A1x_PREFIX "_Q0E",
- .brightness_down = A1x_PREFIX "_Q0F"},
-
- {
- .name = "A2x",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .wled_status = "\\SG66",
- .mt_lcd_switch = "\\Q10",
- .lcd_status = "\\BAOF",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "A4G",
- .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\ADVG"},
-
- {
- .name = "D1x",
- .mt_mled = "MLED",
- .mt_lcd_switch = "\\Q0D",
- .lcd_status = "\\GP11",
- .brightness_up = "\\Q0C",
- .brightness_down = "\\Q0B",
- .brightness_status = "\\BLVL",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "L2D",
- .mt_mled = "MLED",
- .mled_status = "\\SGP6",
- .mt_wled = "WLED",
- .wled_status = "\\RCP3",
- .mt_lcd_switch = "\\Q10",
- .lcd_status = "\\SGP0",
- .brightness_up = "\\Q0E",
- .brightness_down = "\\Q0F",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "L3C",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .mt_lcd_switch = L3C_PREFIX "_Q10",
- .lcd_status = "\\GL32",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP"},
-
- {
- .name = "L3D",
- .mt_mled = "MLED",
- .mled_status = "\\MALD",
- .mt_wled = "WLED",
- .mt_lcd_switch = "\\Q10",
- .lcd_status = "\\BKLG",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "L3H",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .mt_lcd_switch = "EHK",
- .lcd_status = "\\_SB.PCI0.PM.PBC",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "L4R",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .wled_status = "\\_SB.PCI0.SBRG.SG13",
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
- {
- .name = "L5x",
- .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
- .mt_tled = "TLED",
- .mt_lcd_switch = "\\Q0D",
- .lcd_status = "\\BAOF",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "L8L"
-/* No features, but at least support the hotkeys */
- },
-
- {
- .name = "M1A",
- .mt_mled = "MLED",
- .mt_lcd_switch = M1A_PREFIX "Q10",
- .lcd_status = "\\PNOF",
- .brightness_up = M1A_PREFIX "Q0E",
- .brightness_down = M1A_PREFIX "Q0F",
- .brightness_status = "\\BRIT",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "M2E",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .mt_lcd_switch = "\\Q10",
- .lcd_status = "\\GP06",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "M6N",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .wled_status = "\\_SB.PCI0.SBRG.SG13",
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .lcd_status = "\\_SB.BKLT",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\SSTE"},
-
- {
- .name = "M6R",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
- {
- .name = "P30",
- .mt_wled = "WLED",
- .mt_lcd_switch = P30_PREFIX "_Q0E",
- .lcd_status = "\\BKLT",
- .brightness_up = P30_PREFIX "_Q68",
- .brightness_down = P30_PREFIX "_Q69",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\DNXT"},
-
- {
- .name = "S1x",
- .mt_mled = "MLED",
- .mled_status = "\\EMLE",
- .mt_wled = "WLED",
- .mt_lcd_switch = S1x_PREFIX "Q10",
- .lcd_status = "\\PNOF",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV"},
-
- {
- .name = "S2x",
- .mt_mled = "MLED",
- .mled_status = "\\MAIL",
- .mt_lcd_switch = S2x_PREFIX "_Q10",
- .lcd_status = "\\BKLI",
- .brightness_up = S2x_PREFIX "_Q0B",
- .brightness_down = S2x_PREFIX "_Q0A"},
-
- {
- .name = "W1N",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .mt_ledd = "SLCM",
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .lcd_status = "\\BKLT",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\ADVG"},
-
- {
- .name = "W5A",
- .mt_bt_switch = "BLED",
- .mt_wled = "WLED",
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\ADVG"},
-
- {
- .name = "W3V",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .lcd_status = "\\BKLT",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\INFB"},
-
- {
- .name = "xxN",
- .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
- .mt_lcd_switch = xxN_PREFIX "_Q10",
- .lcd_status = "\\BKLT",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\ADVG"},
-
- {
- .name = "A4S",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .mt_bt_switch = "BLED",
- .mt_wled = "WLED"
- },
-
- {
- .name = "F3Sa",
- .mt_bt_switch = "BLED",
- .mt_wled = "WLED",
- .mt_mled = "MLED",
- .brightness_get = "GPLV",
- .brightness_set = "SPLV",
- .mt_lcd_switch = "\\_SB.PCI0.SBRG.EC0._Q10",
- .lcd_status = "\\_SB.PCI0.SBRG.EC0.RPIN",
- .display_get = "\\ADVG",
- .display_set = "SDSP",
- },
- {
- .name = "R1F",
- .mt_bt_switch = "BLED",
- .mt_mled = "MLED",
- .mt_wled = "WLED",
- .mt_lcd_switch = "\\Q10",
- .lcd_status = "\\GP06",
- .brightness_set = "SPLV",
- .brightness_get = "GPLV",
- .display_set = "SDSP",
- .display_get = "\\INFB"
- }
-};
-
-/* procdir we use */
-static struct proc_dir_entry *asus_proc_dir;
-
-static struct backlight_device *asus_backlight_device;
-
-/*
- * This header is made available to allow proper configuration given model,
- * revision number , ... this info cannot go in struct asus_hotk because it is
- * available before the hotk
- */
-static struct acpi_table_header *asus_info;
-
-/* The actual device the driver binds to */
-static struct asus_hotk *hotk;
-
-/*
- * The hotkey driver and autoloading declaration
- */
-static int asus_hotk_add(struct acpi_device *device);
-static int asus_hotk_remove(struct acpi_device *device, int type);
-static void asus_hotk_notify(struct acpi_device *device, u32 event);
-
-static const struct acpi_device_id asus_device_ids[] = {
- {"ATK0100", 0},
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, asus_device_ids);
-
-static struct acpi_driver asus_hotk_driver = {
- .name = "asus_acpi",
- .class = ACPI_HOTK_CLASS,
- .owner = THIS_MODULE,
- .ids = asus_device_ids,
- .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
- .ops = {
- .add = asus_hotk_add,
- .remove = asus_hotk_remove,
- .notify = asus_hotk_notify,
- },
-};
-
-/*
- * This function evaluates an ACPI method, given an int as parameter, the
- * method is searched within the scope of the handle, can be NULL. The output
- * of the method is written is output, which can also be NULL
- *
- * returns 1 if write is successful, 0 else.
- */
-static int write_acpi_int(acpi_handle handle, const char *method, int val,
- struct acpi_buffer *output)
-{
- struct acpi_object_list params; /* list of input parameters (int) */
- union acpi_object in_obj; /* the only param we use */
- acpi_status status;
-
- params.count = 1;
- params.pointer = &in_obj;
- in_obj.type = ACPI_TYPE_INTEGER;
- in_obj.integer.value = val;
-
- status = acpi_evaluate_object(handle, (char *)method, &params, output);
- return (status == AE_OK);
-}
-
-static int read_acpi_int(acpi_handle handle, const char *method, int *val)
-{
- struct acpi_buffer output;
- union acpi_object out_obj;
- acpi_status status;
-
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
-
- status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
- *val = out_obj.integer.value;
- return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
-static int asus_info_proc_show(struct seq_file *m, void *v)
-{
- int temp;
-
- seq_printf(m, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
- seq_printf(m, "Model reference : %s\n", hotk->methods->name);
- /*
- * The SFUN method probably allows the original driver to get the list
- * of features supported by a given model. For now, 0x0100 or 0x0800
- * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
- * The significance of others is yet to be found.
- */
- if (read_acpi_int(hotk->handle, "SFUN", &temp))
- seq_printf(m, "SFUN value : 0x%04x\n", temp);
- /*
- * Another value for userspace: the ASYM method returns 0x02 for
- * battery low and 0x04 for battery critical, its readings tend to be
- * more accurate than those provided by _BST.
- * Note: since not all the laptops provide this method, errors are
- * silently ignored.
- */
- if (read_acpi_int(hotk->handle, "ASYM", &temp))
- seq_printf(m, "ASYM value : 0x%04x\n", temp);
- if (asus_info) {
- seq_printf(m, "DSDT length : %d\n", asus_info->length);
- seq_printf(m, "DSDT checksum : %d\n", asus_info->checksum);
- seq_printf(m, "DSDT revision : %d\n", asus_info->revision);
- seq_printf(m, "OEM id : %.*s\n", ACPI_OEM_ID_SIZE, asus_info->oem_id);
- seq_printf(m, "OEM table id : %.*s\n", ACPI_OEM_TABLE_ID_SIZE, asus_info->oem_table_id);
- seq_printf(m, "OEM revision : 0x%x\n", asus_info->oem_revision);
- seq_printf(m, "ASL comp vendor id : %.*s\n", ACPI_NAME_SIZE, asus_info->asl_compiler_id);
- seq_printf(m, "ASL comp revision : 0x%x\n", asus_info->asl_compiler_revision);
- }
-
- return 0;
-}
-
-static int asus_info_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, asus_info_proc_show, NULL);
-}
-
-static const struct file_operations asus_info_proc_fops = {
- .owner = THIS_MODULE,
- .open = asus_info_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/*
- * /proc handlers
- * We write our info in page, we begin at offset off and cannot write more
- * than count bytes. We set eof to 1 if we handle those 2 values. We return the
- * number of bytes written in page
- */
-
-/* Generic LED functions */
-static int read_led(const char *ledname, int ledmask)
-{
- if (ledname) {
- int led_status;
-
- if (read_acpi_int(NULL, ledname, &led_status))
- return led_status;
- else
- pr_warn("Error reading LED status\n");
- }
- return (hotk->status & ledmask) ? 1 : 0;
-}
-
-static int parse_arg(const char __user *buf, unsigned long count, int *val)
-{
- char s[32];
- if (!count)
- return 0;
- if (count > 31)
- return -EINVAL;
- if (copy_from_user(s, buf, count))
- return -EFAULT;
- s[count] = 0;
- if (sscanf(s, "%i", val) != 1)
- return -EINVAL;
- return count;
-}
-
-/* FIXME: kill extraneous args so it can be called independently */
-static int
-write_led(const char __user *buffer, unsigned long count,
- char *ledname, int ledmask, int invert)
-{
- int rv, value;
- int led_out = 0;
-
- rv = parse_arg(buffer, count, &value);
- if (rv > 0)
- led_out = value ? 1 : 0;
-
- hotk->status =
- (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask);
-
- if (invert) /* invert target value */
- led_out = !led_out;
-
- if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
- pr_warn("LED (%s) write failed\n", ledname);
-
- return rv;
-}
-
-/*
- * Proc handlers for MLED
- */
-static int mled_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%d\n", read_led(hotk->methods->mled_status, MLED_ON));
- return 0;
-}
-
-static int mled_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mled_proc_show, NULL);
-}
-
-static ssize_t mled_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
-}
-
-static const struct file_operations mled_proc_fops = {
- .owner = THIS_MODULE,
- .open = mled_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = mled_proc_write,
-};
-
-/*
- * Proc handlers for LED display
- */
-static int ledd_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "0x%08x\n", hotk->ledd_status);
- return 0;
-}
-
-static int ledd_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ledd_proc_show, NULL);
-}
-
-static ssize_t ledd_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- int rv, value;
-
- rv = parse_arg(buffer, count, &value);
- if (rv > 0) {
- if (!write_acpi_int
- (hotk->handle, hotk->methods->mt_ledd, value, NULL))
- pr_warn("LED display write failed\n");
- else
- hotk->ledd_status = (u32) value;
- }
- return rv;
-}
-
-static const struct file_operations ledd_proc_fops = {
- .owner = THIS_MODULE,
- .open = ledd_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = ledd_proc_write,
-};
-
-/*
- * Proc handlers for WLED
- */
-static int wled_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%d\n", read_led(hotk->methods->wled_status, WLED_ON));
- return 0;
-}
-
-static int wled_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, wled_proc_show, NULL);
-}
-
-static ssize_t wled_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
-}
-
-static const struct file_operations wled_proc_fops = {
- .owner = THIS_MODULE,
- .open = wled_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = wled_proc_write,
-};
-
-/*
- * Proc handlers for Bluetooth
- */
-static int bluetooth_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
- return 0;
-}
-
-static int bluetooth_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, bluetooth_proc_show, NULL);
-}
-
-static ssize_t bluetooth_proc_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *pos)
-{
- /* Note: mt_bt_switch controls both internal Bluetooth adapter's
- presence and its LED */
- return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
-}
-
-static const struct file_operations bluetooth_proc_fops = {
- .owner = THIS_MODULE,
- .open = bluetooth_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = bluetooth_proc_write,
-};
-
-/*
- * Proc handlers for TLED
- */
-static int tled_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%d\n", read_led(hotk->methods->tled_status, TLED_ON));
- return 0;
-}
-
-static int tled_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tled_proc_show, NULL);
-}
-
-static ssize_t tled_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
-}
-
-static const struct file_operations tled_proc_fops = {
- .owner = THIS_MODULE,
- .open = tled_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = tled_proc_write,
-};
-
-static int get_lcd_state(void)
-{
- int lcd = 0;
-
- if (hotk->model == L3H) {
- /* L3H and the like have to be handled differently */
- acpi_status status = 0;
- struct acpi_object_list input;
- union acpi_object mt_params[2];
- struct acpi_buffer output;
- union acpi_object out_obj;
-
- input.count = 2;
- input.pointer = mt_params;
- /* Note: the following values are partly guessed up, but
- otherwise they seem to work */
- mt_params[0].type = ACPI_TYPE_INTEGER;
- mt_params[0].integer.value = 0x02;
- mt_params[1].type = ACPI_TYPE_INTEGER;
- mt_params[1].integer.value = 0x02;
-
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
-
- status =
- acpi_evaluate_object(NULL, hotk->methods->lcd_status,
- &input, &output);
- if (status != AE_OK)
- return -1;
- if (out_obj.type == ACPI_TYPE_INTEGER)
- /* That's what the AML code does */
- lcd = out_obj.integer.value >> 8;
- } else if (hotk->model == F3Sa) {
- unsigned long long tmp;
- union acpi_object param;
- struct acpi_object_list input;
- acpi_status status;
-
- /* Read pin 11 */
- param.type = ACPI_TYPE_INTEGER;
- param.integer.value = 0x11;
- input.count = 1;
- input.pointer = &param;
-
- status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
- &input, &tmp);
- if (status != AE_OK)
- return -1;
-
- lcd = tmp;
- } else {
- /* We don't have to check anything if we are here */
- if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
- pr_warn("Error reading LCD status\n");
-
- if (hotk->model == L2D)
- lcd = ~lcd;
- }
-
- return (lcd & 1);
-}
-
-static int set_lcd_state(int value)
-{
- int lcd = 0;
- acpi_status status = 0;
-
- lcd = value ? 1 : 0;
- if (lcd != get_lcd_state()) {
- /* switch */
- if (hotk->model != L3H) {
- status =
- acpi_evaluate_object(NULL,
- hotk->methods->mt_lcd_switch,
- NULL, NULL);
- } else {
- /* L3H and the like must be handled differently */
- if (!write_acpi_int
- (hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
- NULL))
- status = AE_ERROR;
- /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
- the exact behaviour is simulated here */
- }
- if (ACPI_FAILURE(status))
- pr_warn("Error switching LCD\n");
- }
- return 0;
-
-}
-
-static int lcd_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%d\n", get_lcd_state());
- return 0;
-}
-
-static int lcd_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, lcd_proc_show, NULL);
-}
-
-static ssize_t lcd_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- int rv, value;
-
- rv = parse_arg(buffer, count, &value);
- if (rv > 0)
- set_lcd_state(value);
- return rv;
-}
-
-static const struct file_operations lcd_proc_fops = {
- .owner = THIS_MODULE,
- .open = lcd_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = lcd_proc_write,
-};
-
-static int read_brightness(struct backlight_device *bd)
-{
- int value;
-
- if (hotk->methods->brightness_get) { /* SPLV/GPLV laptop */
- if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
- &value))
- pr_warn("Error reading brightness\n");
- } else if (hotk->methods->brightness_status) { /* For D1 for example */
- if (!read_acpi_int(NULL, hotk->methods->brightness_status,
- &value))
- pr_warn("Error reading brightness\n");
- } else /* No GPLV method */
- value = hotk->brightness;
- return value;
-}
-
-/*
- * Change the brightness level
- */
-static int set_brightness(int value)
-{
- acpi_status status = 0;
- int ret = 0;
-
- /* SPLV laptop */
- if (hotk->methods->brightness_set) {
- if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
- value, NULL)) {
- pr_warn("Error changing brightness\n");
- ret = -EIO;
- }
- goto out;
- }
-
- /* No SPLV method if we are here, act as appropriate */
- value -= read_brightness(NULL);
- while (value != 0) {
- status = acpi_evaluate_object(NULL, (value > 0) ?
- hotk->methods->brightness_up :
- hotk->methods->brightness_down,
- NULL, NULL);
- (value > 0) ? value-- : value++;
- if (ACPI_FAILURE(status)) {
- pr_warn("Error changing brightness\n");
- ret = -EIO;
- }
- }
-out:
- return ret;
-}
-
-static int set_brightness_status(struct backlight_device *bd)
-{
- return set_brightness(bd->props.brightness);
-}
-
-static int brn_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%d\n", read_brightness(NULL));
- return 0;
-}
-
-static int brn_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, brn_proc_show, NULL);
-}
-
-static ssize_t brn_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- int rv, value;
-
- rv = parse_arg(buffer, count, &value);
- if (rv > 0) {
- value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
- /* 0 <= value <= 15 */
- set_brightness(value);
- }
- return rv;
-}
-
-static const struct file_operations brn_proc_fops = {
- .owner = THIS_MODULE,
- .open = brn_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = brn_proc_write,
-};
-
-static void set_display(int value)
-{
- /* no sanity check needed for now */
- if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
- value, NULL))
- pr_warn("Error setting display\n");
- return;
-}
-
-/*
- * Now, *this* one could be more user-friendly, but so far, no-one has
- * complained. The significance of bits is the same as in proc_write_disp()
- */
-static int disp_proc_show(struct seq_file *m, void *v)
-{
- int value = 0;
-
- if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
- pr_warn("Error reading display status\n");
- value &= 0x07; /* needed for some models, shouldn't hurt others */
- seq_printf(m, "%d\n", value);
- return 0;
-}
-
-static int disp_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, disp_proc_show, NULL);
-}
-
-/*
- * Experimental support for display switching. As of now: 1 should activate
- * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
- * (bitwise) of these will suffice. I never actually tested 3 displays hooked
- * up simultaneously, so be warned. See the acpi4asus README for more info.
- */
-static ssize_t disp_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- int rv, value;
-
- rv = parse_arg(buffer, count, &value);
- if (rv > 0)
- set_display(value);
- return rv;
-}
-
-static const struct file_operations disp_proc_fops = {
- .owner = THIS_MODULE,
- .open = disp_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = disp_proc_write,
-};
-
-static int
-asus_proc_add(char *name, const struct file_operations *proc_fops, umode_t mode,
- struct acpi_device *device)
-{
- struct proc_dir_entry *proc;
-
- proc = proc_create_data(name, mode, acpi_device_dir(device),
- proc_fops, acpi_driver_data(device));
- if (!proc) {
- pr_warn(" Unable to create %s fs entry\n", name);
- return -1;
- }
- proc->uid = asus_uid;
- proc->gid = asus_gid;
- return 0;
-}
-
-static int asus_hotk_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *proc;
- umode_t mode;
-
- if ((asus_uid == 0) && (asus_gid == 0)) {
- mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP;
- } else {
- mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
- pr_warn(" asus_uid and asus_gid parameters are "
- "deprecated, use chown and chmod instead!\n");
- }
-
- acpi_device_dir(device) = asus_proc_dir;
- if (!acpi_device_dir(device))
- return -ENODEV;
-
- proc = proc_create(PROC_INFO, mode, acpi_device_dir(device),
- &asus_info_proc_fops);
- if (proc) {
- proc->uid = asus_uid;
- proc->gid = asus_gid;
- } else {
- pr_warn(" Unable to create " PROC_INFO " fs entry\n");
- }
-
- if (hotk->methods->mt_wled) {
- asus_proc_add(PROC_WLED, &wled_proc_fops, mode, device);
- }
-
- if (hotk->methods->mt_ledd) {
- asus_proc_add(PROC_LEDD, &ledd_proc_fops, mode, device);
- }
-
- if (hotk->methods->mt_mled) {
- asus_proc_add(PROC_MLED, &mled_proc_fops, mode, device);
- }
-
- if (hotk->methods->mt_tled) {
- asus_proc_add(PROC_TLED, &tled_proc_fops, mode, device);
- }
-
- if (hotk->methods->mt_bt_switch) {
- asus_proc_add(PROC_BT, &bluetooth_proc_fops, mode, device);
- }
-
- /*
- * We need both read node and write method as LCD switch is also
- * accessible from the keyboard
- */
- if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
- asus_proc_add(PROC_LCD, &lcd_proc_fops, mode, device);
- }
-
- if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
- (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
- asus_proc_add(PROC_BRN, &brn_proc_fops, mode, device);
- }
-
- if (hotk->methods->display_set) {
- asus_proc_add(PROC_DISP, &disp_proc_fops, mode, device);
- }
-
- return 0;
-}
-
-static int asus_hotk_remove_fs(struct acpi_device *device)
-{
- if (acpi_device_dir(device)) {
- remove_proc_entry(PROC_INFO, acpi_device_dir(device));
- if (hotk->methods->mt_wled)
- remove_proc_entry(PROC_WLED, acpi_device_dir(device));
- if (hotk->methods->mt_mled)
- remove_proc_entry(PROC_MLED, acpi_device_dir(device));
- if (hotk->methods->mt_tled)
- remove_proc_entry(PROC_TLED, acpi_device_dir(device));
- if (hotk->methods->mt_ledd)
- remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
- if (hotk->methods->mt_bt_switch)
- remove_proc_entry(PROC_BT, acpi_device_dir(device));
- if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
- remove_proc_entry(PROC_LCD, acpi_device_dir(device));
- if ((hotk->methods->brightness_up
- && hotk->methods->brightness_down)
- || (hotk->methods->brightness_get
- && hotk->methods->brightness_set))
- remove_proc_entry(PROC_BRN, acpi_device_dir(device));
- if (hotk->methods->display_set)
- remove_proc_entry(PROC_DISP, acpi_device_dir(device));
- }
- return 0;
-}
-
-static void asus_hotk_notify(struct acpi_device *device, u32 event)
-{
- /* TODO Find a better way to handle events count. */
- if (!hotk)
- return;
-
- /*
- * The BIOS *should* be sending us device events, but apparently
- * Asus uses system events instead, so just ignore any device
- * events we get.
- */
- if (event > ACPI_MAX_SYS_NOTIFY)
- return;
-
- if ((event & ~((u32) BR_UP)) < 16)
- hotk->brightness = (event & ~((u32) BR_UP));
- else if ((event & ~((u32) BR_DOWN)) < 16)
- hotk->brightness = (event & ~((u32) BR_DOWN));
-
- acpi_bus_generate_proc_event(hotk->device, event,
- hotk->event_count[event % 128]++);
-
- return;
-}
-
-/*
- * Match the model string to the list of supported models. Return END_MODEL if
- * no match or model is NULL.
- */
-static int asus_model_match(char *model)
-{
- if (model == NULL)
- return END_MODEL;
-
- if (strncmp(model, "L3D", 3) == 0)
- return L3D;
- else if (strncmp(model, "L2E", 3) == 0 ||
- strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
- return L3H;
- else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
- return L3C;
- else if (strncmp(model, "L8L", 3) == 0)
- return L8L;
- else if (strncmp(model, "L4R", 3) == 0)
- return L4R;
- else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
- return M6N;
- else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
- return M6R;
- else if (strncmp(model, "M2N", 3) == 0 ||
- strncmp(model, "M3N", 3) == 0 ||
- strncmp(model, "M5N", 3) == 0 ||
- strncmp(model, "S1N", 3) == 0 ||
- strncmp(model, "S5N", 3) == 0)
- return xxN;
- else if (strncmp(model, "M1", 2) == 0)
- return M1A;
- else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
- return M2E;
- else if (strncmp(model, "L2", 2) == 0)
- return L2D;
- else if (strncmp(model, "L8", 2) == 0)
- return S1x;
- else if (strncmp(model, "D1", 2) == 0)
- return D1x;
- else if (strncmp(model, "A1", 2) == 0)
- return A1x;
- else if (strncmp(model, "A2", 2) == 0)
- return A2x;
- else if (strncmp(model, "J1", 2) == 0)
- return S2x;
- else if (strncmp(model, "L5", 2) == 0)
- return L5x;
- else if (strncmp(model, "A4G", 3) == 0)
- return A4G;
- else if (strncmp(model, "W1N", 3) == 0)
- return W1N;
- else if (strncmp(model, "W3V", 3) == 0)
- return W3V;
- else if (strncmp(model, "W5A", 3) == 0)
- return W5A;
- else if (strncmp(model, "R1F", 3) == 0)
- return R1F;
- else if (strncmp(model, "A4S", 3) == 0)
- return A4S;
- else if (strncmp(model, "F3Sa", 4) == 0)
- return F3Sa;
- else
- return END_MODEL;
-}
-
-/*
- * This function is used to initialize the hotk with right values. In this
- * method, we can make all the detection we want, and modify the hotk struct
- */
-static int asus_hotk_get_info(void)
-{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *model = NULL;
- int bsts_result;
- char *string = NULL;
- acpi_status status;
-
- /*
- * Get DSDT headers early enough to allow for differentiating between
- * models, but late enough to allow acpi_bus_register_driver() to fail
- * before doing anything ACPI-specific. Should we encounter a machine,
- * which needs special handling (i.e. its hotkey device has a different
- * HID), this bit will be moved. A global variable asus_info contains
- * the DSDT header.
- */
- status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
- if (ACPI_FAILURE(status))
- pr_warn(" Couldn't get the DSDT table header\n");
-
- /* We have to write 0 on init this far for all ASUS models */
- if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
- pr_err(" Hotkey initialization failed\n");
- return -ENODEV;
- }
-
- /* This needs to be called for some laptops to init properly */
- if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
- pr_warn(" Error calling BSTS\n");
- else if (bsts_result)
- pr_notice(" BSTS called, 0x%02x returned\n", bsts_result);
-
- /*
- * Try to match the object returned by INIT to the specific model.
- * Handle every possible object (or the lack of thereof) the DSDT
- * writers might throw at us. When in trouble, we pass NULL to
- * asus_model_match() and try something completely different.
- */
- if (buffer.pointer) {
- model = buffer.pointer;
- switch (model->type) {
- case ACPI_TYPE_STRING:
- string = model->string.pointer;
- break;
- case ACPI_TYPE_BUFFER:
- string = model->buffer.pointer;
- break;
- default:
- kfree(model);
- model = NULL;
- break;
- }
- }
- hotk->model = asus_model_match(string);
- if (hotk->model == END_MODEL) { /* match failed */
- if (asus_info &&
- strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
- hotk->model = P30;
- pr_notice(" Samsung P30 detected, supported\n");
- hotk->methods = &model_conf[hotk->model];
- kfree(model);
- return 0;
- } else {
- hotk->model = M2E;
- pr_notice(" unsupported model %s, trying default values\n",
- string);
- pr_notice(" send /proc/acpi/dsdt to the developers\n");
- kfree(model);
- return -ENODEV;
- }
- }
- hotk->methods = &model_conf[hotk->model];
- pr_notice(" %s model detected, supported\n", string);
-
- /* Sort of per-model blacklist */
- if (strncmp(string, "L2B", 3) == 0)
- hotk->methods->lcd_status = NULL;
- /* L2B is similar enough to L3C to use its settings, with this only
- exception */
- else if (strncmp(string, "A3G", 3) == 0)
- hotk->methods->lcd_status = "\\BLFG";
- /* A3G is like M6R */
- else if (strncmp(string, "S5N", 3) == 0 ||
- strncmp(string, "M5N", 3) == 0 ||
- strncmp(string, "W3N", 3) == 0)
- hotk->methods->mt_mled = NULL;
- /* S5N, M5N and W3N have no MLED */
- else if (strncmp(string, "L5D", 3) == 0)
- hotk->methods->mt_wled = NULL;
- /* L5D's WLED is not controlled by ACPI */
- else if (strncmp(string, "M2N", 3) == 0 ||
- strncmp(string, "W3V", 3) == 0 ||
- strncmp(string, "S1N", 3) == 0)
- hotk->methods->mt_wled = "WLED";
- /* M2N, S1N and W3V have a usable WLED */
- else if (asus_info) {
- if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
- hotk->methods->mled_status = NULL;
- /* S1300A reports L84F, but L1400B too, account for that */
- }
-
- kfree(model);
-
- return 0;
-}
-
-static int asus_hotk_check(void)
-{
- int result = 0;
-
- result = acpi_bus_get_status(hotk->device);
- if (result)
- return result;
-
- if (hotk->device->status.present) {
- result = asus_hotk_get_info();
- } else {
- pr_err(" Hotkey device not present, aborting\n");
- return -EINVAL;
- }
-
- return result;
-}
-
-static int asus_hotk_found;
-
-static int asus_hotk_add(struct acpi_device *device)
-{
- acpi_status status = AE_OK;
- int result;
-
- pr_notice("Asus Laptop ACPI Extras version %s\n", ASUS_ACPI_VERSION);
-
- hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
- if (!hotk)
- return -ENOMEM;
-
- hotk->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
- device->driver_data = hotk;
- hotk->device = device;
-
- result = asus_hotk_check();
- if (result)
- goto end;
-
- result = asus_hotk_add_fs(device);
- if (result)
- goto end;
-
- /* For laptops without GPLV: init the hotk->brightness value */
- if ((!hotk->methods->brightness_get)
- && (!hotk->methods->brightness_status)
- && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
- status =
- acpi_evaluate_object(NULL, hotk->methods->brightness_down,
- NULL, NULL);
- if (ACPI_FAILURE(status))
- pr_warn(" Error changing brightness\n");
- else {
- status =
- acpi_evaluate_object(NULL,
- hotk->methods->brightness_up,
- NULL, NULL);
- if (ACPI_FAILURE(status))
- pr_warn(" Strange, error changing brightness\n");
- }
- }
-
- asus_hotk_found = 1;
-
- /* LED display is off by default */
- hotk->ledd_status = 0xFFF;
-
-end:
- if (result)
- kfree(hotk);
-
- return result;
-}
-
-static int asus_hotk_remove(struct acpi_device *device, int type)
-{
- asus_hotk_remove_fs(device);
-
- kfree(hotk);
-
- return 0;
-}
-
-static const struct backlight_ops asus_backlight_data = {
- .get_brightness = read_brightness,
- .update_status = set_brightness_status,
-};
-
-static void asus_acpi_exit(void)
-{
- if (asus_backlight_device)
- backlight_device_unregister(asus_backlight_device);
-
- acpi_bus_unregister_driver(&asus_hotk_driver);
- remove_proc_entry(PROC_ASUS, acpi_root_dir);
-
- return;
-}
-
-static int __init asus_acpi_init(void)
-{
- struct backlight_properties props;
- int result;
-
- result = acpi_bus_register_driver(&asus_hotk_driver);
- if (result < 0)
- return result;
-
- asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
- if (!asus_proc_dir) {
- pr_err("Unable to create /proc entry\n");
- acpi_bus_unregister_driver(&asus_hotk_driver);
- return -ENODEV;
- }
-
- /*
- * This is a bit of a kludge. We only want this module loaded
- * for ASUS systems, but there's currently no way to probe the
- * ACPI namespace for ASUS HIDs. So we just return failure if
- * we didn't find one, which will cause the module to be
- * unloaded.
- */
- if (!asus_hotk_found) {
- acpi_bus_unregister_driver(&asus_hotk_driver);
- remove_proc_entry(PROC_ASUS, acpi_root_dir);
- return -ENODEV;
- }
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_PLATFORM;
- props.max_brightness = 15;
- asus_backlight_device = backlight_device_register("asus", NULL, NULL,
- &asus_backlight_data,
- &props);
- if (IS_ERR(asus_backlight_device)) {
- pr_err("Could not register asus backlight device\n");
- asus_backlight_device = NULL;
- asus_acpi_exit();
- return -ENODEV;
- }
-
- return 0;
-}
-
-module_init(asus_acpi_init);
-module_exit(asus_acpi_exit);
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index d96734478324..1887e2f166a4 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -882,6 +882,7 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
},
{ }
};
+MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
static void initialize_power_supply_data(struct compal_data *data)
{
@@ -1097,16 +1098,3 @@ MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
MODULE_DESCRIPTION("Compal Laptop Support");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
-
-MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
-MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index d93e962f2610..a05fc9c955d8 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -117,6 +117,7 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
},
{ }
};
+MODULE_DEVICE_TABLE(dmi, dell_device_table);
static struct dmi_system_id __devinitdata dell_blacklist[] = {
/* Supported by compal-laptop */
@@ -184,6 +185,33 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
},
.driver_data = &quirk_dell_vostro_v130,
},
+ {
+ .callback = dmi_matched,
+ .ident = "Dell Vostro 3555",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"),
+ },
+ .driver_data = &quirk_dell_vostro_v130,
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Dell Inspiron N311z",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"),
+ },
+ .driver_data = &quirk_dell_vostro_v130,
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Dell Inspiron M5110",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
+ },
+ .driver_data = &quirk_dell_vostro_v130,
+ },
};
static struct calling_interface_buffer *buffer;
@@ -236,9 +264,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
{
switch (dm->type) {
case 0xd4: /* Indexed IO */
- break;
case 0xd5: /* Protected Area Type 1 */
- break;
case 0xd6: /* Protected Area Type 2 */
break;
case 0xda: /* Calling interface */
@@ -615,6 +641,7 @@ static void touchpad_led_set(struct led_classdev *led_cdev,
static struct led_classdev touchpad_led = {
.name = "dell-laptop::touchpad",
.brightness_set = touchpad_led_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static int __devinit touchpad_led_init(struct device *dev)
@@ -794,6 +821,3 @@ module_exit(dell_exit);
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_DESCRIPTION("Dell laptop driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
-MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*");
-MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index d9a9e2bedb30..dab91b48d22c 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1251,6 +1251,14 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
/*
* ACPI driver
*/
+static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
+{
+ if (!eeepc->inputdev)
+ return ;
+ if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
+ pr_info("Unknown key %x pressed\n", event);
+}
+
static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
{
struct eeepc_laptop *eeepc = acpi_driver_data(device);
@@ -1287,12 +1295,11 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
* event will be desired value (or else ignored)
*/
}
- sparse_keymap_report_event(eeepc->inputdev, event,
- 1, true);
+ eeepc_input_notify(eeepc, event);
}
} else {
/* Everything else is a bona-fide keypress event */
- sparse_keymap_report_event(eeepc->inputdev, event, 1, true);
+ eeepc_input_notify(eeepc, event);
}
}
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 9f6e64302b45..656761380342 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -32,6 +32,7 @@
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/dmi.h>
+#include <linux/fb.h>
#include <acpi/acpi_bus.h>
#include "asus-wmi.h"
@@ -84,9 +85,81 @@ static const struct key_entry eeepc_wmi_keymap[] = {
{ KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
{ KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
{ KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
+ { KE_KEY, 0xf3, { KEY_MENU } },
+ { KE_KEY, 0xf5, { KEY_HOMEPAGE } },
+ { KE_KEY, 0xf6, { KEY_ESC } },
{ KE_END, 0},
};
+static struct quirk_entry quirk_asus_unknown = {
+};
+
+static struct quirk_entry quirk_asus_1000h = {
+ .hotplug_wireless = true,
+};
+
+static struct quirk_entry quirk_asus_et2012_type1 = {
+ .store_backlight_power = true,
+};
+
+static struct quirk_entry quirk_asus_et2012_type3 = {
+ .scalar_panel_brightness = true,
+ .store_backlight_power = true,
+};
+
+static struct quirk_entry *quirks;
+
+static void et2012_quirks(void)
+{
+ const struct dmi_device *dev = NULL;
+ char oemstring[30];
+
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+ if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
+ if (oemstring[18] == '1')
+ quirks = &quirk_asus_et2012_type1;
+ else if (oemstring[18] == '3')
+ quirks = &quirk_asus_et2012_type3;
+ break;
+ }
+ }
+}
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+ char *model;
+
+ quirks = dmi->driver_data;
+
+ model = (char *)dmi->matches[1].substr;
+ if (unlikely(strncmp(model, "ET2012", 6) == 0))
+ et2012_quirks();
+
+ return 1;
+}
+
+static struct dmi_system_id asus_quirks[] = {
+ {
+ .callback = dmi_matched,
+ .ident = "ASUSTeK Computer INC. 1000H",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
+ },
+ .driver_data = &quirk_asus_1000h,
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "ASUSTeK Computer INC. ET2012E/I",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
+ },
+ .driver_data = &quirk_asus_unknown,
+ },
+ {},
+};
+
static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
unsigned int *value, bool *autorelease)
{
@@ -141,33 +214,16 @@ static int eeepc_wmi_probe(struct platform_device *pdev)
return 0;
}
-static void eeepc_dmi_check(struct asus_wmi_driver *driver)
-{
- const char *model;
-
- model = dmi_get_system_info(DMI_PRODUCT_NAME);
- if (!model)
- return;
-
- /*
- * Whitelist for wlan hotplug
- *
- * Asus 1000H needs the current hotplug code to handle
- * Fn+F2 correctly. We may add other Asus here later, but
- * it seems that most of the laptops supported by asus-wmi
- * don't need to be on this list
- */
- if (strcmp(model, "1000H") == 0) {
- driver->hotplug_wireless = true;
- pr_info("wlan hotplug enabled\n");
- }
-}
-
static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
{
- driver->hotplug_wireless = hotplug_wireless;
- driver->wapf = -1;
- eeepc_dmi_check(driver);
+ quirks = &quirk_asus_unknown;
+ quirks->hotplug_wireless = hotplug_wireless;
+
+ dmi_check_system(asus_quirks);
+
+ driver->quirks = quirks;
+ driver->quirks->wapf = -1;
+ driver->panel_power = FB_BLANK_UNBLANK;
}
static struct asus_wmi_driver asus_wmi_driver = {
@@ -179,7 +235,7 @@ static struct asus_wmi_driver asus_wmi_driver = {
.input_phys = EEEPC_WMI_FILE "/input0",
.key_filter = eeepc_wmi_key_filter,
.probe = eeepc_wmi_probe,
- .quirks = eeepc_wmi_quirks,
+ .detect_quirks = eeepc_wmi_quirks,
};
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c
index ba68d4e7a779..7387f97a2941 100644
--- a/drivers/platform/x86/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -375,7 +375,7 @@ static ssize_t hdaps_variance_show(struct device *dev,
static ssize_t hdaps_temp1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- u8 temp;
+ u8 uninitialized_var(temp);
int ret;
ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
@@ -388,7 +388,7 @@ static ssize_t hdaps_temp1_show(struct device *dev,
static ssize_t hdaps_temp2_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- u8 temp;
+ u8 uninitialized_var(temp);
int ret;
ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
index 0903a883e9f4..0a3594c7e912 100644
--- a/drivers/platform/x86/intel_mid_powerbtn.c
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
@@ -142,17 +142,7 @@ static struct platform_driver mfld_pb_driver = {
.remove = __devexit_p(mfld_pb_remove),
};
-static int __init mfld_pb_init(void)
-{
- return platform_driver_register(&mfld_pb_driver);
-}
-module_init(mfld_pb_init);
-
-static void __exit mfld_pb_exit(void)
-{
- platform_driver_unregister(&mfld_pb_driver);
-}
-module_exit(mfld_pb_exit);
+module_platform_driver(mfld_pb_driver);
MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index 2ee9766737ea..5ae9cd9c7e6e 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -549,6 +549,7 @@ static int mid_thermal_remove(struct platform_device *pdev)
static const struct platform_device_id therm_id_table[] = {
{ DRIVER_NAME, 1 },
+ { "msic_thermal", 1 },
{ }
};
@@ -564,18 +565,7 @@ static struct platform_driver mid_thermal_driver = {
.id_table = therm_id_table,
};
-static int __init mid_thermal_module_init(void)
-{
- return platform_driver_register(&mid_thermal_driver);
-}
-
-static void __exit mid_thermal_module_exit(void)
-{
- platform_driver_unregister(&mid_thermal_driver);
-}
-
-module_init(mid_thermal_module_init);
-module_exit(mid_thermal_module_exit);
+module_platform_driver(mid_thermal_driver);
MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c
index 6ee0b5c90933..79a0c2f6be53 100644
--- a/drivers/platform/x86/intel_oaktrail.c
+++ b/drivers/platform/x86/intel_oaktrail.c
@@ -313,6 +313,7 @@ static struct dmi_system_id __initdata oaktrail_dmi_table[] = {
},
{ }
};
+MODULE_DEVICE_TABLE(dmi, oaktrail_dmi_table);
static int __init oaktrail_init(void)
{
@@ -394,4 +395,3 @@ MODULE_AUTHOR("Yin Kangkai (kangkai.yin@intel.com)");
MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
-MODULE_ALIAS("dmi:*:svnIntelCorporation:pnOakTrailplatform:*");
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index fd73ea89b857..e2a34b42ddc1 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -17,10 +17,18 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/backlight.h>
+#include <linux/leds.h>
#include <linux/fb.h>
#include <linux/dmi.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
+#include <linux/acpi.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/ctype.h>
+#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+#include <acpi/video.h>
+#endif
/*
* This driver is needed because a number of Samsung laptops do not hook
@@ -41,9 +49,20 @@
#define SABI_IFACE_COMPLETE 0x04
#define SABI_IFACE_DATA 0x05
-/* Structure to get data back to the calling function */
-struct sabi_retval {
- u8 retval[20];
+#define WL_STATUS_WLAN 0x0
+#define WL_STATUS_BT 0x2
+
+/* Structure get/set data using sabi */
+struct sabi_data {
+ union {
+ struct {
+ u32 d0;
+ u32 d1;
+ u16 d2;
+ u8 d3;
+ };
+ u8 data[11];
+ };
};
struct sabi_header_offsets {
@@ -60,8 +79,8 @@ struct sabi_commands {
* Brightness is 0 - 8, as described above.
* Value 0 is for the BIOS to use
*/
- u8 get_brightness;
- u8 set_brightness;
+ u16 get_brightness;
+ u16 set_brightness;
/*
* first byte:
@@ -72,40 +91,56 @@ struct sabi_commands {
* 0x03 - 3G is on
* TODO, verify 3G is correct, that doesn't seem right...
*/
- u8 get_wireless_button;
- u8 set_wireless_button;
+ u16 get_wireless_button;
+ u16 set_wireless_button;
/* 0 is off, 1 is on */
- u8 get_backlight;
- u8 set_backlight;
+ u16 get_backlight;
+ u16 set_backlight;
/*
* 0x80 or 0x00 - no action
* 0x81 - recovery key pressed
*/
- u8 get_recovery_mode;
- u8 set_recovery_mode;
+ u16 get_recovery_mode;
+ u16 set_recovery_mode;
/*
* on seclinux: 0 is low, 1 is high,
* on swsmi: 0 is normal, 1 is silent, 2 is turbo
*/
- u8 get_performance_level;
- u8 set_performance_level;
+ u16 get_performance_level;
+ u16 set_performance_level;
+
+ /* 0x80 is off, 0x81 is on */
+ u16 get_battery_life_extender;
+ u16 set_battery_life_extender;
+
+ /* 0x80 is off, 0x81 is on */
+ u16 get_usb_charge;
+ u16 set_usb_charge;
+
+ /* the first byte is for bluetooth and the third one is for wlan */
+ u16 get_wireless_status;
+ u16 set_wireless_status;
+
+ /* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
+ u16 kbd_backlight;
/*
* Tell the BIOS that Linux is running on this machine.
* 81 is on, 80 is off
*/
- u8 set_linux;
+ u16 set_linux;
};
struct sabi_performance_level {
const char *name;
- u8 value;
+ u16 value;
};
struct sabi_config {
+ int sabi_version;
const char *test_string;
u16 main_function;
const struct sabi_header_offsets header_offsets;
@@ -117,6 +152,10 @@ struct sabi_config {
static const struct sabi_config sabi_configs[] = {
{
+ /* I don't know if it is really 2, but it it is
+ * less than 3 anyway */
+ .sabi_version = 2,
+
.test_string = "SECLINUX",
.main_function = 0x4c49,
@@ -146,6 +185,17 @@ static const struct sabi_config sabi_configs[] = {
.get_performance_level = 0x08,
.set_performance_level = 0x09,
+ .get_battery_life_extender = 0xFFFF,
+ .set_battery_life_extender = 0xFFFF,
+
+ .get_usb_charge = 0xFFFF,
+ .set_usb_charge = 0xFFFF,
+
+ .get_wireless_status = 0xFFFF,
+ .set_wireless_status = 0xFFFF,
+
+ .kbd_backlight = 0xFFFF,
+
.set_linux = 0x0a,
},
@@ -164,6 +214,8 @@ static const struct sabi_config sabi_configs[] = {
.max_brightness = 8,
},
{
+ .sabi_version = 3,
+
.test_string = "SwSmi@",
.main_function = 0x5843,
@@ -193,6 +245,17 @@ static const struct sabi_config sabi_configs[] = {
.get_performance_level = 0x31,
.set_performance_level = 0x32,
+ .get_battery_life_extender = 0x65,
+ .set_battery_life_extender = 0x66,
+
+ .get_usb_charge = 0x67,
+ .set_usb_charge = 0x68,
+
+ .get_wireless_status = 0x69,
+ .set_wireless_status = 0x6a,
+
+ .kbd_backlight = 0x78,
+
.set_linux = 0xff,
},
@@ -217,16 +280,82 @@ static const struct sabi_config sabi_configs[] = {
{ },
};
-static const struct sabi_config *sabi_config;
+/*
+ * samsung-laptop/ - debugfs root directory
+ * f0000_segment - dump f0000 segment
+ * command - current command
+ * data - current data
+ * d0, d1, d2, d3 - data fields
+ * call - call SABI using command and data
+ *
+ * This allow to call arbitrary sabi commands wihout
+ * modifying the driver at all.
+ * For example, setting the keyboard backlight brightness to 5
+ *
+ * echo 0x78 > command
+ * echo 0x0582 > d0
+ * echo 0 > d1
+ * echo 0 > d2
+ * echo 0 > d3
+ * cat call
+ */
+
+struct samsung_laptop_debug {
+ struct dentry *root;
+ struct sabi_data data;
+ u16 command;
+
+ struct debugfs_blob_wrapper f0000_wrapper;
+ struct debugfs_blob_wrapper data_wrapper;
+ struct debugfs_blob_wrapper sdiag_wrapper;
+};
+
+struct samsung_laptop;
+
+struct samsung_rfkill {
+ struct samsung_laptop *samsung;
+ struct rfkill *rfkill;
+ enum rfkill_type type;
+};
+
+struct samsung_laptop {
+ const struct sabi_config *config;
+
+ void __iomem *sabi;
+ void __iomem *sabi_iface;
+ void __iomem *f0000_segment;
+
+ struct mutex sabi_mutex;
+
+ struct platform_device *platform_device;
+ struct backlight_device *backlight_device;
+
+ struct samsung_rfkill wlan;
+ struct samsung_rfkill bluetooth;
+
+ struct led_classdev kbd_led;
+ int kbd_led_wk;
+ struct workqueue_struct *led_workqueue;
+ struct work_struct kbd_led_work;
+
+ struct samsung_laptop_debug debug;
+ struct samsung_quirks *quirks;
+
+ bool handle_backlight;
+ bool has_stepping_quirk;
+
+ char sdiag[64];
+};
+
+struct samsung_quirks {
+ bool broken_acpi_video;
+};
+
+static struct samsung_quirks samsung_unknown = {};
-static void __iomem *sabi;
-static void __iomem *sabi_iface;
-static void __iomem *f0000_segment;
-static struct backlight_device *backlight_device;
-static struct mutex sabi_mutex;
-static struct platform_device *sdev;
-static struct rfkill *rfk;
-static bool has_stepping_quirk;
+static struct samsung_quirks samsung_broken_acpi_video = {
+ .broken_acpi_video = true,
+};
static bool force;
module_param(force, bool, 0);
@@ -237,176 +366,143 @@ static bool debug;
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+static int sabi_command(struct samsung_laptop *samsung, u16 command,
+ struct sabi_data *in,
+ struct sabi_data *out)
{
- int retval = 0;
- u16 port = readw(sabi + sabi_config->header_offsets.port);
+ const struct sabi_config *config = samsung->config;
+ int ret = 0;
+ u16 port = readw(samsung->sabi + config->header_offsets.port);
u8 complete, iface_data;
- mutex_lock(&sabi_mutex);
-
- /* enable memory to be able to write to it */
- outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
-
- /* write out the command */
- writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
- writew(command, sabi_iface + SABI_IFACE_SUB);
- writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
- outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
-
- /* write protect memory to make it safe */
- outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+ mutex_lock(&samsung->sabi_mutex);
- /* see if the command actually succeeded */
- complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
- iface_data = readb(sabi_iface + SABI_IFACE_DATA);
- if (complete != 0xaa || iface_data == 0xff) {
- pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
- command, complete, iface_data);
- retval = -EINVAL;
- goto exit;
+ if (debug) {
+ if (in)
+ pr_info("SABI command:0x%04x "
+ "data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
+ command, in->d0, in->d1, in->d2, in->d3);
+ else
+ pr_info("SABI command:0x%04x", command);
}
- /*
- * Save off the data into a structure so the caller use it.
- * Right now we only want the first 4 bytes,
- * There are commands that need more, but not for the ones we
- * currently care about.
- */
- sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
- sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
- sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
- sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
-
-exit:
- mutex_unlock(&sabi_mutex);
- return retval;
-
-}
-
-static int sabi_set_command(u8 command, u8 data)
-{
- int retval = 0;
- u16 port = readw(sabi + sabi_config->header_offsets.port);
- u8 complete, iface_data;
-
- mutex_lock(&sabi_mutex);
/* enable memory to be able to write to it */
- outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+ outb(readb(samsung->sabi + config->header_offsets.en_mem), port);
/* write out the command */
- writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
- writew(command, sabi_iface + SABI_IFACE_SUB);
- writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
- writeb(data, sabi_iface + SABI_IFACE_DATA);
- outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+ writew(config->main_function, samsung->sabi_iface + SABI_IFACE_MAIN);
+ writew(command, samsung->sabi_iface + SABI_IFACE_SUB);
+ writeb(0, samsung->sabi_iface + SABI_IFACE_COMPLETE);
+ if (in) {
+ writel(in->d0, samsung->sabi_iface + SABI_IFACE_DATA);
+ writel(in->d1, samsung->sabi_iface + SABI_IFACE_DATA + 4);
+ writew(in->d2, samsung->sabi_iface + SABI_IFACE_DATA + 8);
+ writeb(in->d3, samsung->sabi_iface + SABI_IFACE_DATA + 10);
+ }
+ outb(readb(samsung->sabi + config->header_offsets.iface_func), port);
/* write protect memory to make it safe */
- outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+ outb(readb(samsung->sabi + config->header_offsets.re_mem), port);
/* see if the command actually succeeded */
- complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
- iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+ complete = readb(samsung->sabi_iface + SABI_IFACE_COMPLETE);
+ iface_data = readb(samsung->sabi_iface + SABI_IFACE_DATA);
+
+ /* iface_data = 0xFF happens when a command is not known
+ * so we only add a warning in debug mode since we will
+ * probably issue some unknown command at startup to find
+ * out which features are supported */
+ if (complete != 0xaa || (iface_data == 0xff && debug))
+ pr_warn("SABI command 0x%04x failed with"
+ " completion flag 0x%02x and interface data 0x%02x",
+ command, complete, iface_data);
+
if (complete != 0xaa || iface_data == 0xff) {
- pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
- command, complete, iface_data);
- retval = -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
- mutex_unlock(&sabi_mutex);
- return retval;
-}
-
-static void test_backlight(void)
-{
- struct sabi_retval sretval;
-
- sabi_get_command(sabi_config->commands.get_backlight, &sretval);
- printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
- sabi_set_command(sabi_config->commands.set_backlight, 0);
- printk(KERN_DEBUG "backlight should be off\n");
-
- sabi_get_command(sabi_config->commands.get_backlight, &sretval);
- printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
- msleep(1000);
+ if (out) {
+ out->d0 = readl(samsung->sabi_iface + SABI_IFACE_DATA);
+ out->d1 = readl(samsung->sabi_iface + SABI_IFACE_DATA + 4);
+ out->d2 = readw(samsung->sabi_iface + SABI_IFACE_DATA + 2);
+ out->d3 = readb(samsung->sabi_iface + SABI_IFACE_DATA + 1);
+ }
- sabi_set_command(sabi_config->commands.set_backlight, 1);
- printk(KERN_DEBUG "backlight should be on\n");
+ if (debug && out) {
+ pr_info("SABI return data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
+ out->d0, out->d1, out->d2, out->d3);
+ }
- sabi_get_command(sabi_config->commands.get_backlight, &sretval);
- printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+exit:
+ mutex_unlock(&samsung->sabi_mutex);
+ return ret;
}
-static void test_wireless(void)
+/* simple wrappers usable with most commands */
+static int sabi_set_commandb(struct samsung_laptop *samsung,
+ u16 command, u8 data)
{
- struct sabi_retval sretval;
-
- sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
- printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-
- sabi_set_command(sabi_config->commands.set_wireless_button, 0);
- printk(KERN_DEBUG "wireless led should be off\n");
-
- sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
- printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+ struct sabi_data in = { { { .d0 = 0, .d1 = 0, .d2 = 0, .d3 = 0 } } };
- msleep(1000);
-
- sabi_set_command(sabi_config->commands.set_wireless_button, 1);
- printk(KERN_DEBUG "wireless led should be on\n");
-
- sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
- printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+ in.data[0] = data;
+ return sabi_command(samsung, command, &in, NULL);
}
-static u8 read_brightness(void)
+static int read_brightness(struct samsung_laptop *samsung)
{
- struct sabi_retval sretval;
+ const struct sabi_config *config = samsung->config;
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data sretval;
int user_brightness = 0;
int retval;
- retval = sabi_get_command(sabi_config->commands.get_brightness,
- &sretval);
- if (!retval) {
- user_brightness = sretval.retval[0];
- if (user_brightness > sabi_config->min_brightness)
- user_brightness -= sabi_config->min_brightness;
- else
- user_brightness = 0;
- }
+ retval = sabi_command(samsung, commands->get_brightness,
+ NULL, &sretval);
+ if (retval)
+ return retval;
+
+ user_brightness = sretval.data[0];
+ if (user_brightness > config->min_brightness)
+ user_brightness -= config->min_brightness;
+ else
+ user_brightness = 0;
+
return user_brightness;
}
-static void set_brightness(u8 user_brightness)
+static void set_brightness(struct samsung_laptop *samsung, u8 user_brightness)
{
- u8 user_level = user_brightness + sabi_config->min_brightness;
+ const struct sabi_config *config = samsung->config;
+ const struct sabi_commands *commands = &samsung->config->commands;
+ u8 user_level = user_brightness + config->min_brightness;
- if (has_stepping_quirk && user_level != 0) {
+ if (samsung->has_stepping_quirk && user_level != 0) {
/*
* short circuit if the specified level is what's already set
* to prevent the screen from flickering needlessly
*/
- if (user_brightness == read_brightness())
+ if (user_brightness == read_brightness(samsung))
return;
- sabi_set_command(sabi_config->commands.set_brightness, 0);
+ sabi_set_commandb(samsung, commands->set_brightness, 0);
}
- sabi_set_command(sabi_config->commands.set_brightness, user_level);
+ sabi_set_commandb(samsung, commands->set_brightness, user_level);
}
static int get_brightness(struct backlight_device *bd)
{
- return (int)read_brightness();
+ struct samsung_laptop *samsung = bl_get_data(bd);
+
+ return read_brightness(samsung);
}
-static void check_for_stepping_quirk(void)
+static void check_for_stepping_quirk(struct samsung_laptop *samsung)
{
- u8 initial_level;
- u8 check_level;
- u8 orig_level = read_brightness();
+ int initial_level;
+ int check_level;
+ int orig_level = read_brightness(samsung);
/*
* Some laptops exhibit the strange behaviour of stepping toward
@@ -416,34 +512,38 @@ static void check_for_stepping_quirk(void)
*/
if (orig_level == 0)
- set_brightness(1);
+ set_brightness(samsung, 1);
- initial_level = read_brightness();
+ initial_level = read_brightness(samsung);
if (initial_level <= 2)
check_level = initial_level + 2;
else
check_level = initial_level - 2;
- has_stepping_quirk = false;
- set_brightness(check_level);
+ samsung->has_stepping_quirk = false;
+ set_brightness(samsung, check_level);
- if (read_brightness() != check_level) {
- has_stepping_quirk = true;
+ if (read_brightness(samsung) != check_level) {
+ samsung->has_stepping_quirk = true;
pr_info("enabled workaround for brightness stepping quirk\n");
}
- set_brightness(orig_level);
+ set_brightness(samsung, orig_level);
}
static int update_status(struct backlight_device *bd)
{
- set_brightness(bd->props.brightness);
+ struct samsung_laptop *samsung = bl_get_data(bd);
+ const struct sabi_commands *commands = &samsung->config->commands;
+
+ set_brightness(samsung, bd->props.brightness);
if (bd->props.power == FB_BLANK_UNBLANK)
- sabi_set_command(sabi_config->commands.set_backlight, 1);
+ sabi_set_commandb(samsung, commands->set_backlight, 1);
else
- sabi_set_command(sabi_config->commands.set_backlight, 0);
+ sabi_set_commandb(samsung, commands->set_backlight, 0);
+
return 0;
}
@@ -452,66 +552,101 @@ static const struct backlight_ops backlight_ops = {
.update_status = update_status,
};
-static int rfkill_set(void *data, bool blocked)
+static int seclinux_rfkill_set(void *data, bool blocked)
{
- /* Do something with blocked...*/
- /*
- * blocked == false is on
- * blocked == true is off
- */
- if (blocked)
- sabi_set_command(sabi_config->commands.set_wireless_button, 0);
- else
- sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+ struct samsung_rfkill *srfkill = data;
+ struct samsung_laptop *samsung = srfkill->samsung;
+ const struct sabi_commands *commands = &samsung->config->commands;
- return 0;
+ return sabi_set_commandb(samsung, commands->set_wireless_button,
+ !blocked);
}
-static struct rfkill_ops rfkill_ops = {
- .set_block = rfkill_set,
+static struct rfkill_ops seclinux_rfkill_ops = {
+ .set_block = seclinux_rfkill_set,
};
-static int init_wireless(struct platform_device *sdev)
+static int swsmi_wireless_status(struct samsung_laptop *samsung,
+ struct sabi_data *data)
{
- int retval;
+ const struct sabi_commands *commands = &samsung->config->commands;
- rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
- &rfkill_ops, NULL);
- if (!rfk)
- return -ENOMEM;
-
- retval = rfkill_register(rfk);
- if (retval) {
- rfkill_destroy(rfk);
- return -ENODEV;
- }
+ return sabi_command(samsung, commands->get_wireless_status,
+ NULL, data);
+}
- return 0;
+static int swsmi_rfkill_set(void *priv, bool blocked)
+{
+ struct samsung_rfkill *srfkill = priv;
+ struct samsung_laptop *samsung = srfkill->samsung;
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+ int ret, i;
+
+ ret = swsmi_wireless_status(samsung, &data);
+ if (ret)
+ return ret;
+
+ /* Don't set the state for non-present devices */
+ for (i = 0; i < 4; i++)
+ if (data.data[i] == 0x02)
+ data.data[1] = 0;
+
+ if (srfkill->type == RFKILL_TYPE_WLAN)
+ data.data[WL_STATUS_WLAN] = !blocked;
+ else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
+ data.data[WL_STATUS_BT] = !blocked;
+
+ return sabi_command(samsung, commands->set_wireless_status,
+ &data, &data);
}
-static void destroy_wireless(void)
+static void swsmi_rfkill_query(struct rfkill *rfkill, void *priv)
{
- rfkill_unregister(rfk);
- rfkill_destroy(rfk);
+ struct samsung_rfkill *srfkill = priv;
+ struct samsung_laptop *samsung = srfkill->samsung;
+ struct sabi_data data;
+ int ret;
+
+ ret = swsmi_wireless_status(samsung, &data);
+ if (ret)
+ return ;
+
+ if (srfkill->type == RFKILL_TYPE_WLAN)
+ ret = data.data[WL_STATUS_WLAN];
+ else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
+ ret = data.data[WL_STATUS_BT];
+ else
+ return ;
+
+ rfkill_set_sw_state(rfkill, !ret);
}
+static struct rfkill_ops swsmi_rfkill_ops = {
+ .set_block = swsmi_rfkill_set,
+ .query = swsmi_rfkill_query,
+};
+
static ssize_t get_performance_level(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct sabi_retval sretval;
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ const struct sabi_config *config = samsung->config;
+ const struct sabi_commands *commands = &config->commands;
+ struct sabi_data sretval;
int retval;
int i;
/* Read the state */
- retval = sabi_get_command(sabi_config->commands.get_performance_level,
- &sretval);
+ retval = sabi_command(samsung, commands->get_performance_level,
+ NULL, &sretval);
if (retval)
return retval;
/* The logic is backwards, yeah, lots of fun... */
- for (i = 0; sabi_config->performance_levels[i].name; ++i) {
- if (sretval.retval[0] == sabi_config->performance_levels[i].value)
- return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+ for (i = 0; config->performance_levels[i].name; ++i) {
+ if (sretval.data[0] == config->performance_levels[i].value)
+ return sprintf(buf, "%s\n", config->performance_levels[i].name);
}
return sprintf(buf, "%s\n", "unknown");
}
@@ -520,269 +655,178 @@ static ssize_t set_performance_level(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- if (count >= 1) {
- int i;
- for (i = 0; sabi_config->performance_levels[i].name; ++i) {
- const struct sabi_performance_level *level =
- &sabi_config->performance_levels[i];
- if (!strncasecmp(level->name, buf, strlen(level->name))) {
- sabi_set_command(sabi_config->commands.set_performance_level,
- level->value);
- break;
- }
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ const struct sabi_config *config = samsung->config;
+ const struct sabi_commands *commands = &config->commands;
+ int i;
+
+ if (count < 1)
+ return count;
+
+ for (i = 0; config->performance_levels[i].name; ++i) {
+ const struct sabi_performance_level *level =
+ &config->performance_levels[i];
+ if (!strncasecmp(level->name, buf, strlen(level->name))) {
+ sabi_set_commandb(samsung,
+ commands->set_performance_level,
+ level->value);
+ break;
}
- if (!sabi_config->performance_levels[i].name)
- return -EINVAL;
}
+
+ if (!config->performance_levels[i].name)
+ return -EINVAL;
+
return count;
}
+
static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
get_performance_level, set_performance_level);
+static int read_battery_life_extender(struct samsung_laptop *samsung)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+ int retval;
+
+ if (commands->get_battery_life_extender == 0xFFFF)
+ return -ENODEV;
+
+ memset(&data, 0, sizeof(data));
+ data.data[0] = 0x80;
+ retval = sabi_command(samsung, commands->get_battery_life_extender,
+ &data, &data);
-static int __init dmi_check_cb(const struct dmi_system_id *id)
+ if (retval)
+ return retval;
+
+ if (data.data[0] != 0 && data.data[0] != 1)
+ return -ENODEV;
+
+ return data.data[0];
+}
+
+static int write_battery_life_extender(struct samsung_laptop *samsung,
+ int enabled)
{
- pr_info("found laptop model '%s'\n",
- id->ident);
- return 1;
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.data[0] = 0x80 | enabled;
+ return sabi_command(samsung, commands->set_battery_life_extender,
+ &data, NULL);
}
-static struct dmi_system_id __initdata samsung_dmi_table[] = {
- {
- .ident = "N128",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
- DMI_MATCH(DMI_BOARD_NAME, "N128"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "N130",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
- DMI_MATCH(DMI_BOARD_NAME, "N130"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "N510",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N510"),
- DMI_MATCH(DMI_BOARD_NAME, "N510"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "X125",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
- DMI_MATCH(DMI_BOARD_NAME, "X125"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "X120/X170",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
- DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "NC10",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
- DMI_MATCH(DMI_BOARD_NAME, "NC10"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "NP-Q45",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
- DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "X360",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
- DMI_MATCH(DMI_BOARD_NAME, "X360"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "R410 Plus",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
- DMI_MATCH(DMI_BOARD_NAME, "R460"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "R518",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
- DMI_MATCH(DMI_BOARD_NAME, "R518"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "R519/R719",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
- DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "N150/N210/N220",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
- DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "N220",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N220"),
- DMI_MATCH(DMI_BOARD_NAME, "N220"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "N150/N210/N220/N230",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
- DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "N150P/N210P/N220P",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
- DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "R700",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
- DMI_MATCH(DMI_BOARD_NAME, "SR700"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "R530/R730",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
- DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "NF110/NF210/NF310",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
- DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "N145P/N250P/N260P",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
- DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "R70/R71",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR,
- "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
- DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "P460",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
- DMI_MATCH(DMI_BOARD_NAME, "P460"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "R528/R728",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
- DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "NC210/NC110",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
- DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
- },
- .callback = dmi_check_cb,
- },
- {
- .ident = "X520",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
- DMI_MATCH(DMI_BOARD_NAME, "X520"),
- },
- .callback = dmi_check_cb,
- },
- { },
+static ssize_t get_battery_life_extender(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ int ret;
+
+ ret = read_battery_life_extender(samsung);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t set_battery_life_extender(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ int ret, value;
+
+ if (!count || sscanf(buf, "%i", &value) != 1)
+ return -EINVAL;
+
+ ret = write_battery_life_extender(samsung, !!value);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(battery_life_extender, S_IWUSR | S_IRUGO,
+ get_battery_life_extender, set_battery_life_extender);
+
+static int read_usb_charge(struct samsung_laptop *samsung)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+ int retval;
+
+ if (commands->get_usb_charge == 0xFFFF)
+ return -ENODEV;
+
+ memset(&data, 0, sizeof(data));
+ data.data[0] = 0x80;
+ retval = sabi_command(samsung, commands->get_usb_charge,
+ &data, &data);
+
+ if (retval)
+ return retval;
+
+ if (data.data[0] != 0 && data.data[0] != 1)
+ return -ENODEV;
+
+ return data.data[0];
+}
+
+static int write_usb_charge(struct samsung_laptop *samsung,
+ int enabled)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.data[0] = 0x80 | enabled;
+ return sabi_command(samsung, commands->set_usb_charge,
+ &data, NULL);
+}
+
+static ssize_t get_usb_charge(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ int ret;
+
+ ret = read_usb_charge(samsung);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t set_usb_charge(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ int ret, value;
+
+ if (!count || sscanf(buf, "%i", &value) != 1)
+ return -EINVAL;
+
+ ret = write_usb_charge(samsung, !!value);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
+ get_usb_charge, set_usb_charge);
+
+static struct attribute *platform_attributes[] = {
+ &dev_attr_performance_level.attr,
+ &dev_attr_battery_life_extender.attr,
+ &dev_attr_usb_charge.attr,
+ NULL
};
-MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
static int find_signature(void __iomem *memcheck, const char *testStr)
{
@@ -803,153 +847,772 @@ static int find_signature(void __iomem *memcheck, const char *testStr)
return loca;
}
-static int __init samsung_init(void)
+static void samsung_rfkill_exit(struct samsung_laptop *samsung)
{
- struct backlight_properties props;
- struct sabi_retval sretval;
- unsigned int ifaceP;
- int i;
- int loca;
+ if (samsung->wlan.rfkill) {
+ rfkill_unregister(samsung->wlan.rfkill);
+ rfkill_destroy(samsung->wlan.rfkill);
+ samsung->wlan.rfkill = NULL;
+ }
+ if (samsung->bluetooth.rfkill) {
+ rfkill_unregister(samsung->bluetooth.rfkill);
+ rfkill_destroy(samsung->bluetooth.rfkill);
+ samsung->bluetooth.rfkill = NULL;
+ }
+}
+
+static int samsung_new_rfkill(struct samsung_laptop *samsung,
+ struct samsung_rfkill *arfkill,
+ const char *name, enum rfkill_type type,
+ const struct rfkill_ops *ops,
+ int blocked)
+{
+ struct rfkill **rfkill = &arfkill->rfkill;
+ int ret;
+
+ arfkill->type = type;
+ arfkill->samsung = samsung;
+
+ *rfkill = rfkill_alloc(name, &samsung->platform_device->dev,
+ type, ops, arfkill);
+
+ if (!*rfkill)
+ return -EINVAL;
+
+ if (blocked != -1)
+ rfkill_init_sw_state(*rfkill, blocked);
+
+ ret = rfkill_register(*rfkill);
+ if (ret) {
+ rfkill_destroy(*rfkill);
+ *rfkill = NULL;
+ return ret;
+ }
+ return 0;
+}
+
+static int __init samsung_rfkill_init_seclinux(struct samsung_laptop *samsung)
+{
+ return samsung_new_rfkill(samsung, &samsung->wlan, "samsung-wlan",
+ RFKILL_TYPE_WLAN, &seclinux_rfkill_ops, -1);
+}
+
+static int __init samsung_rfkill_init_swsmi(struct samsung_laptop *samsung)
+{
+ struct sabi_data data;
+ int ret;
+
+ ret = swsmi_wireless_status(samsung, &data);
+ if (ret) {
+ /* Some swsmi laptops use the old seclinux way to control
+ * wireless devices */
+ if (ret == -EINVAL)
+ ret = samsung_rfkill_init_seclinux(samsung);
+ return ret;
+ }
+
+ /* 0x02 seems to mean that the device is no present/available */
+
+ if (data.data[WL_STATUS_WLAN] != 0x02)
+ ret = samsung_new_rfkill(samsung, &samsung->wlan,
+ "samsung-wlan",
+ RFKILL_TYPE_WLAN,
+ &swsmi_rfkill_ops,
+ !data.data[WL_STATUS_WLAN]);
+ if (ret)
+ goto exit;
+
+ if (data.data[WL_STATUS_BT] != 0x02)
+ ret = samsung_new_rfkill(samsung, &samsung->bluetooth,
+ "samsung-bluetooth",
+ RFKILL_TYPE_BLUETOOTH,
+ &swsmi_rfkill_ops,
+ !data.data[WL_STATUS_BT]);
+ if (ret)
+ goto exit;
+
+exit:
+ if (ret)
+ samsung_rfkill_exit(samsung);
+
+ return ret;
+}
+
+static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
+{
+ if (samsung->config->sabi_version == 2)
+ return samsung_rfkill_init_seclinux(samsung);
+ if (samsung->config->sabi_version == 3)
+ return samsung_rfkill_init_swsmi(samsung);
+ return 0;
+}
+
+static int kbd_backlight_enable(struct samsung_laptop *samsung)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
int retval;
- mutex_init(&sabi_mutex);
+ if (commands->kbd_backlight == 0xFFFF)
+ return -ENODEV;
+
+ memset(&data, 0, sizeof(data));
+ data.d0 = 0xaabb;
+ retval = sabi_command(samsung, commands->kbd_backlight,
+ &data, &data);
- if (!force && !dmi_check_system(samsung_dmi_table))
+ if (retval)
+ return retval;
+
+ if (data.d0 != 0xccdd)
return -ENODEV;
+ return 0;
+}
- f0000_segment = ioremap_nocache(0xf0000, 0xffff);
- if (!f0000_segment) {
- pr_err("Can't map the segment at 0xf0000\n");
- return -EINVAL;
+static int kbd_backlight_read(struct samsung_laptop *samsung)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+ int retval;
+
+ memset(&data, 0, sizeof(data));
+ data.data[0] = 0x81;
+ retval = sabi_command(samsung, commands->kbd_backlight,
+ &data, &data);
+
+ if (retval)
+ return retval;
+
+ return data.data[0];
+}
+
+static int kbd_backlight_write(struct samsung_laptop *samsung, int brightness)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.d0 = 0x82 | ((brightness & 0xFF) << 8);
+ return sabi_command(samsung, commands->kbd_backlight,
+ &data, NULL);
+}
+
+static void kbd_led_update(struct work_struct *work)
+{
+ struct samsung_laptop *samsung;
+
+ samsung = container_of(work, struct samsung_laptop, kbd_led_work);
+ kbd_backlight_write(samsung, samsung->kbd_led_wk);
+}
+
+static void kbd_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct samsung_laptop *samsung;
+
+ samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
+
+ if (value > samsung->kbd_led.max_brightness)
+ value = samsung->kbd_led.max_brightness;
+ else if (value < 0)
+ value = 0;
+
+ samsung->kbd_led_wk = value;
+ queue_work(samsung->led_workqueue, &samsung->kbd_led_work);
+}
+
+static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
+{
+ struct samsung_laptop *samsung;
+
+ samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
+ return kbd_backlight_read(samsung);
+}
+
+static void samsung_leds_exit(struct samsung_laptop *samsung)
+{
+ if (!IS_ERR_OR_NULL(samsung->kbd_led.dev))
+ led_classdev_unregister(&samsung->kbd_led);
+ if (samsung->led_workqueue)
+ destroy_workqueue(samsung->led_workqueue);
+}
+
+static int __init samsung_leds_init(struct samsung_laptop *samsung)
+{
+ int ret = 0;
+
+ samsung->led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!samsung->led_workqueue)
+ return -ENOMEM;
+
+ if (kbd_backlight_enable(samsung) >= 0) {
+ INIT_WORK(&samsung->kbd_led_work, kbd_led_update);
+
+ samsung->kbd_led.name = "samsung::kbd_backlight";
+ samsung->kbd_led.brightness_set = kbd_led_set;
+ samsung->kbd_led.brightness_get = kbd_led_get;
+ samsung->kbd_led.max_brightness = 8;
+
+ ret = led_classdev_register(&samsung->platform_device->dev,
+ &samsung->kbd_led);
+ }
+
+ if (ret)
+ samsung_leds_exit(samsung);
+
+ return ret;
+}
+
+static void samsung_backlight_exit(struct samsung_laptop *samsung)
+{
+ if (samsung->backlight_device) {
+ backlight_device_unregister(samsung->backlight_device);
+ samsung->backlight_device = NULL;
+ }
+}
+
+static int __init samsung_backlight_init(struct samsung_laptop *samsung)
+{
+ struct backlight_device *bd;
+ struct backlight_properties props;
+
+ if (!samsung->handle_backlight)
+ return 0;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_PLATFORM;
+ props.max_brightness = samsung->config->max_brightness -
+ samsung->config->min_brightness;
+
+ bd = backlight_device_register("samsung",
+ &samsung->platform_device->dev,
+ samsung, &backlight_ops,
+ &props);
+ if (IS_ERR(bd))
+ return PTR_ERR(bd);
+
+ samsung->backlight_device = bd;
+ samsung->backlight_device->props.brightness = read_brightness(samsung);
+ samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(samsung->backlight_device);
+
+ return 0;
+}
+
+static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
+ struct attribute *attr, int idx)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct samsung_laptop *samsung = platform_get_drvdata(pdev);
+ bool ok = true;
+
+ if (attr == &dev_attr_performance_level.attr)
+ ok = !!samsung->config->performance_levels[0].name;
+ if (attr == &dev_attr_battery_life_extender.attr)
+ ok = !!(read_battery_life_extender(samsung) >= 0);
+ if (attr == &dev_attr_usb_charge.attr)
+ ok = !!(read_usb_charge(samsung) >= 0);
+
+ return ok ? attr->mode : 0;
+}
+
+static struct attribute_group platform_attribute_group = {
+ .is_visible = samsung_sysfs_is_visible,
+ .attrs = platform_attributes
+};
+
+static void samsung_sysfs_exit(struct samsung_laptop *samsung)
+{
+ struct platform_device *device = samsung->platform_device;
+
+ sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
+}
+
+static int __init samsung_sysfs_init(struct samsung_laptop *samsung)
+{
+ struct platform_device *device = samsung->platform_device;
+
+ return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
+
+}
+
+static int show_call(struct seq_file *m, void *data)
+{
+ struct samsung_laptop *samsung = m->private;
+ struct sabi_data *sdata = &samsung->debug.data;
+ int ret;
+
+ seq_printf(m, "SABI 0x%04x {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
+ samsung->debug.command,
+ sdata->d0, sdata->d1, sdata->d2, sdata->d3);
+
+ ret = sabi_command(samsung, samsung->debug.command, sdata, sdata);
+
+ if (ret) {
+ seq_printf(m, "SABI command 0x%04x failed\n",
+ samsung->debug.command);
+ return ret;
+ }
+
+ seq_printf(m, "SABI {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
+ sdata->d0, sdata->d1, sdata->d2, sdata->d3);
+ return 0;
+}
+
+static int samsung_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, show_call, inode->i_private);
+}
+
+static const struct file_operations samsung_laptop_call_io_ops = {
+ .owner = THIS_MODULE,
+ .open = samsung_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void samsung_debugfs_exit(struct samsung_laptop *samsung)
+{
+ debugfs_remove_recursive(samsung->debug.root);
+}
+
+static int samsung_debugfs_init(struct samsung_laptop *samsung)
+{
+ struct dentry *dent;
+
+ samsung->debug.root = debugfs_create_dir("samsung-laptop", NULL);
+ if (!samsung->debug.root) {
+ pr_err("failed to create debugfs directory");
+ goto error_debugfs;
+ }
+
+ samsung->debug.f0000_wrapper.data = samsung->f0000_segment;
+ samsung->debug.f0000_wrapper.size = 0xffff;
+
+ samsung->debug.data_wrapper.data = &samsung->debug.data;
+ samsung->debug.data_wrapper.size = sizeof(samsung->debug.data);
+
+ samsung->debug.sdiag_wrapper.data = samsung->sdiag;
+ samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
+
+ dent = debugfs_create_u16("command", S_IRUGO | S_IWUSR,
+ samsung->debug.root, &samsung->debug.command);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_u32("d0", S_IRUGO | S_IWUSR, samsung->debug.root,
+ &samsung->debug.data.d0);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_u32("d1", S_IRUGO | S_IWUSR, samsung->debug.root,
+ &samsung->debug.data.d1);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_u16("d2", S_IRUGO | S_IWUSR, samsung->debug.root,
+ &samsung->debug.data.d2);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_u8("d3", S_IRUGO | S_IWUSR, samsung->debug.root,
+ &samsung->debug.data.d3);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_blob("data", S_IRUGO | S_IWUSR,
+ samsung->debug.root,
+ &samsung->debug.data_wrapper);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR,
+ samsung->debug.root,
+ &samsung->debug.f0000_wrapper);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_file("call", S_IFREG | S_IRUGO,
+ samsung->debug.root, samsung,
+ &samsung_laptop_call_io_ops);
+ if (!dent)
+ goto error_debugfs;
+
+ dent = debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR,
+ samsung->debug.root,
+ &samsung->debug.sdiag_wrapper);
+ if (!dent)
+ goto error_debugfs;
+
+ return 0;
+
+error_debugfs:
+ samsung_debugfs_exit(samsung);
+ return -ENOMEM;
+}
+
+static void samsung_sabi_exit(struct samsung_laptop *samsung)
+{
+ const struct sabi_config *config = samsung->config;
+
+ /* Turn off "Linux" mode in the BIOS */
+ if (config && config->commands.set_linux != 0xff)
+ sabi_set_commandb(samsung, config->commands.set_linux, 0x80);
+
+ if (samsung->sabi_iface) {
+ iounmap(samsung->sabi_iface);
+ samsung->sabi_iface = NULL;
+ }
+ if (samsung->f0000_segment) {
+ iounmap(samsung->f0000_segment);
+ samsung->f0000_segment = NULL;
+ }
+
+ samsung->config = NULL;
+}
+
+static __init void samsung_sabi_infos(struct samsung_laptop *samsung, int loca,
+ unsigned int ifaceP)
+{
+ const struct sabi_config *config = samsung->config;
+
+ printk(KERN_DEBUG "This computer supports SABI==%x\n",
+ loca + 0xf0000 - 6);
+
+ printk(KERN_DEBUG "SABI header:\n");
+ printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+ readw(samsung->sabi + config->header_offsets.port));
+ printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+ readb(samsung->sabi + config->header_offsets.iface_func));
+ printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+ readb(samsung->sabi + config->header_offsets.en_mem));
+ printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+ readb(samsung->sabi + config->header_offsets.re_mem));
+ printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+ readw(samsung->sabi + config->header_offsets.data_offset));
+ printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+ readw(samsung->sabi + config->header_offsets.data_segment));
+
+ printk(KERN_DEBUG " SABI pointer = 0x%08x\n", ifaceP);
+}
+
+static void __init samsung_sabi_diag(struct samsung_laptop *samsung)
+{
+ int loca = find_signature(samsung->f0000_segment, "SDiaG@");
+ int i;
+
+ if (loca == 0xffff)
+ return ;
+
+ /* Example:
+ * Ident: @SDiaG@686XX-N90X3A/966-SEC-07HL-S90X3A
+ *
+ * Product name: 90X3A
+ * BIOS Version: 07HL
+ */
+ loca += 1;
+ for (i = 0; loca < 0xffff && i < sizeof(samsung->sdiag) - 1; loca++) {
+ char temp = readb(samsung->f0000_segment + loca);
+
+ if (isalnum(temp) || temp == '/' || temp == '-')
+ samsung->sdiag[i++] = temp;
+ else
+ break ;
}
+ if (debug && samsung->sdiag[0])
+ pr_info("sdiag: %s", samsung->sdiag);
+}
+
+static int __init samsung_sabi_init(struct samsung_laptop *samsung)
+{
+ const struct sabi_config *config = NULL;
+ const struct sabi_commands *commands;
+ unsigned int ifaceP;
+ int ret = 0;
+ int i;
+ int loca;
+
+ samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff);
+ if (!samsung->f0000_segment) {
+ if (debug || force)
+ pr_err("Can't map the segment at 0xf0000\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ samsung_sabi_diag(samsung);
+
/* Try to find one of the signatures in memory to find the header */
for (i = 0; sabi_configs[i].test_string != 0; ++i) {
- sabi_config = &sabi_configs[i];
- loca = find_signature(f0000_segment, sabi_config->test_string);
+ samsung->config = &sabi_configs[i];
+ loca = find_signature(samsung->f0000_segment,
+ samsung->config->test_string);
if (loca != 0xffff)
break;
}
if (loca == 0xffff) {
- pr_err("This computer does not support SABI\n");
- goto error_no_signature;
+ if (debug || force)
+ pr_err("This computer does not support SABI\n");
+ ret = -ENODEV;
+ goto exit;
}
+ config = samsung->config;
+ commands = &config->commands;
+
/* point to the SMI port Number */
loca += 1;
- sabi = (f0000_segment + loca);
-
- if (debug) {
- printk(KERN_DEBUG "This computer supports SABI==%x\n",
- loca + 0xf0000 - 6);
- printk(KERN_DEBUG "SABI header:\n");
- printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
- readw(sabi + sabi_config->header_offsets.port));
- printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
- readb(sabi + sabi_config->header_offsets.iface_func));
- printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
- readb(sabi + sabi_config->header_offsets.en_mem));
- printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
- readb(sabi + sabi_config->header_offsets.re_mem));
- printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
- readw(sabi + sabi_config->header_offsets.data_offset));
- printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
- readw(sabi + sabi_config->header_offsets.data_segment));
- }
+ samsung->sabi = (samsung->f0000_segment + loca);
/* Get a pointer to the SABI Interface */
- ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
- ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
- sabi_iface = ioremap_nocache(ifaceP, 16);
- if (!sabi_iface) {
- pr_err("Can't remap %x\n", ifaceP);
- goto error_no_signature;
- }
- if (debug) {
- printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
- printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
+ ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4;
+ ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff;
- test_backlight();
- test_wireless();
+ if (debug)
+ samsung_sabi_infos(samsung, loca, ifaceP);
- retval = sabi_get_command(sabi_config->commands.get_brightness,
- &sretval);
- printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+ samsung->sabi_iface = ioremap_nocache(ifaceP, 16);
+ if (!samsung->sabi_iface) {
+ pr_err("Can't remap %x\n", ifaceP);
+ ret = -EINVAL;
+ goto exit;
}
/* Turn on "Linux" mode in the BIOS */
- if (sabi_config->commands.set_linux != 0xff) {
- retval = sabi_set_command(sabi_config->commands.set_linux,
- 0x81);
+ if (commands->set_linux != 0xff) {
+ int retval = sabi_set_commandb(samsung,
+ commands->set_linux, 0x81);
if (retval) {
pr_warn("Linux mode was not set!\n");
- goto error_no_platform;
+ ret = -ENODEV;
+ goto exit;
}
}
/* Check for stepping quirk */
- check_for_stepping_quirk();
+ if (samsung->handle_backlight)
+ check_for_stepping_quirk(samsung);
- /* knock up a platform device to hang stuff off of */
- sdev = platform_device_register_simple("samsung", -1, NULL, 0);
- if (IS_ERR(sdev))
- goto error_no_platform;
+ pr_info("detected SABI interface: %s\n",
+ samsung->config->test_string);
- /* create a backlight device to talk to this one */
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_PLATFORM;
- props.max_brightness = sabi_config->max_brightness -
- sabi_config->min_brightness;
- backlight_device = backlight_device_register("samsung", &sdev->dev,
- NULL, &backlight_ops,
- &props);
- if (IS_ERR(backlight_device))
- goto error_no_backlight;
-
- backlight_device->props.brightness = read_brightness();
- backlight_device->props.power = FB_BLANK_UNBLANK;
- backlight_update_status(backlight_device);
-
- retval = init_wireless(sdev);
- if (retval)
- goto error_no_rfk;
+exit:
+ if (ret)
+ samsung_sabi_exit(samsung);
- retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
- if (retval)
- goto error_file_create;
+ return ret;
+}
+
+static void samsung_platform_exit(struct samsung_laptop *samsung)
+{
+ if (samsung->platform_device) {
+ platform_device_unregister(samsung->platform_device);
+ samsung->platform_device = NULL;
+ }
+}
+
+static int __init samsung_platform_init(struct samsung_laptop *samsung)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_simple("samsung", -1, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+ samsung->platform_device = pdev;
+ platform_set_drvdata(samsung->platform_device, samsung);
return 0;
+}
+
+static struct samsung_quirks *quirks;
+
+static int __init samsung_dmi_matched(const struct dmi_system_id *d)
+{
+ quirks = d->driver_data;
+ return 0;
+}
+
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
+ },
+ },
+ /* Specific DMI ids for laptop with quirks */
+ {
+ .callback = samsung_dmi_matched,
+ .ident = "N150P",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
+ DMI_MATCH(DMI_BOARD_NAME, "N150P"),
+ },
+ .driver_data = &samsung_broken_acpi_video,
+ },
+ {
+ .callback = samsung_dmi_matched,
+ .ident = "N145P/N250P/N260P",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+ DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+ },
+ .driver_data = &samsung_broken_acpi_video,
+ },
+ {
+ .callback = samsung_dmi_matched,
+ .ident = "N150/N210/N220",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+ DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+ },
+ .driver_data = &samsung_broken_acpi_video,
+ },
+ {
+ .callback = samsung_dmi_matched,
+ .ident = "NF110/NF210/NF310",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+ DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+ },
+ .driver_data = &samsung_broken_acpi_video,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
-error_file_create:
- destroy_wireless();
+static struct platform_device *samsung_platform_device;
-error_no_rfk:
- backlight_device_unregister(backlight_device);
+static int __init samsung_init(void)
+{
+ struct samsung_laptop *samsung;
+ int ret;
-error_no_backlight:
- platform_device_unregister(sdev);
+ quirks = &samsung_unknown;
+ if (!force && !dmi_check_system(samsung_dmi_table))
+ return -ENODEV;
+
+ samsung = kzalloc(sizeof(*samsung), GFP_KERNEL);
+ if (!samsung)
+ return -ENOMEM;
-error_no_platform:
- iounmap(sabi_iface);
+ mutex_init(&samsung->sabi_mutex);
+ samsung->handle_backlight = true;
+ samsung->quirks = quirks;
-error_no_signature:
- iounmap(f0000_segment);
- return -EINVAL;
+
+#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+ /* Don't handle backlight here if the acpi video already handle it */
+ if (acpi_video_backlight_support()) {
+ if (samsung->quirks->broken_acpi_video) {
+ pr_info("Disabling ACPI video driver\n");
+ acpi_video_unregister();
+ } else {
+ samsung->handle_backlight = false;
+ }
+ }
+#endif
+
+ ret = samsung_platform_init(samsung);
+ if (ret)
+ goto error_platform;
+
+ ret = samsung_sabi_init(samsung);
+ if (ret)
+ goto error_sabi;
+
+#ifdef CONFIG_ACPI
+ /* Only log that if we are really on a sabi platform */
+ if (acpi_video_backlight_support() &&
+ !samsung->quirks->broken_acpi_video)
+ pr_info("Backlight controlled by ACPI video driver\n");
+#endif
+
+ ret = samsung_sysfs_init(samsung);
+ if (ret)
+ goto error_sysfs;
+
+ ret = samsung_backlight_init(samsung);
+ if (ret)
+ goto error_backlight;
+
+ ret = samsung_rfkill_init(samsung);
+ if (ret)
+ goto error_rfkill;
+
+ ret = samsung_leds_init(samsung);
+ if (ret)
+ goto error_leds;
+
+ ret = samsung_debugfs_init(samsung);
+ if (ret)
+ goto error_debugfs;
+
+ samsung_platform_device = samsung->platform_device;
+ return ret;
+
+error_debugfs:
+ samsung_leds_exit(samsung);
+error_leds:
+ samsung_rfkill_exit(samsung);
+error_rfkill:
+ samsung_backlight_exit(samsung);
+error_backlight:
+ samsung_sysfs_exit(samsung);
+error_sysfs:
+ samsung_sabi_exit(samsung);
+error_sabi:
+ samsung_platform_exit(samsung);
+error_platform:
+ kfree(samsung);
+ return ret;
}
static void __exit samsung_exit(void)
{
- /* Turn off "Linux" mode in the BIOS */
- if (sabi_config->commands.set_linux != 0xff)
- sabi_set_command(sabi_config->commands.set_linux, 0x80);
-
- device_remove_file(&sdev->dev, &dev_attr_performance_level);
- backlight_device_unregister(backlight_device);
- destroy_wireless();
- iounmap(sabi_iface);
- iounmap(f0000_segment);
- platform_device_unregister(sdev);
+ struct samsung_laptop *samsung;
+
+ samsung = platform_get_drvdata(samsung_platform_device);
+
+ samsung_debugfs_exit(samsung);
+ samsung_leds_exit(samsung);
+ samsung_rfkill_exit(samsung);
+ samsung_backlight_exit(samsung);
+ samsung_sysfs_exit(samsung);
+ samsung_sabi_exit(samsung);
+ samsung_platform_exit(samsung);
+
+ kfree(samsung);
+ samsung_platform_device = NULL;
}
module_init(samsung_init);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index c006dee5ebfe..8a51795aa02a 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -127,7 +127,7 @@ MODULE_PARM_DESC(minor,
"default is -1 (automatic)");
#endif
-static int kbd_backlight; /* = 1 */
+static int kbd_backlight = 1;
module_param(kbd_backlight, int, 0444);
MODULE_PARM_DESC(kbd_backlight,
"set this to 0 to disable keyboard backlight, "
@@ -347,6 +347,7 @@ static void sony_laptop_report_input_event(u8 event)
struct input_dev *jog_dev = sony_laptop_input.jog_dev;
struct input_dev *key_dev = sony_laptop_input.key_dev;
struct sony_laptop_keypress kp = { NULL };
+ int scancode = -1;
if (event == SONYPI_EVENT_FNKEY_RELEASED ||
event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
@@ -380,8 +381,8 @@ static void sony_laptop_report_input_event(u8 event)
dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
break;
}
- if (sony_laptop_input_index[event] != -1) {
- kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+ if ((scancode = sony_laptop_input_index[event]) != -1) {
+ kp.key = sony_laptop_input_keycode_map[scancode];
if (kp.key != KEY_UNKNOWN)
kp.dev = key_dev;
}
@@ -389,9 +390,11 @@ static void sony_laptop_report_input_event(u8 event)
}
if (kp.dev) {
+ /* if we have a scancode we emit it so we can always
+ remap the key */
+ if (scancode != -1)
+ input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
input_report_key(kp.dev, kp.key, 1);
- /* we emit the scancode so we can always remap the key */
- input_event(kp.dev, EV_MSC, MSC_SCAN, event);
input_sync(kp.dev);
/* schedule key release */
@@ -466,7 +469,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
jog_dev->name = "Sony Vaio Jogdial";
jog_dev->id.bustype = BUS_ISA;
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
- key_dev->dev.parent = &acpi_device->dev;
+ jog_dev->dev.parent = &acpi_device->dev;
input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
input_set_capability(jog_dev, EV_REL, REL_WHEEL);
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index ea0c6075b720..d68c0002f4a2 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -8658,7 +8658,7 @@ static int __must_check __init get_thinkpad_model_data(
}
s = dmi_get_system_info(DMI_PRODUCT_VERSION);
- if (s && !strnicmp(s, "ThinkPad", 8)) {
+ if (s && !(strnicmp(s, "ThinkPad", 8) && strnicmp(s, "Lenovo", 6))) {
tp->model_str = kstrdup(s, GFP_KERNEL);
if (!tp->model_str)
return -ENOMEM;
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index dcdc1f4a4624..ee79ce64d9df 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -52,6 +52,8 @@
#include <linux/input/sparse-keymap.h>
#include <linux/leds.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/i8042.h>
#include <asm/uaccess.h>
@@ -61,6 +63,11 @@ MODULE_AUTHOR("John Belmonte");
MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
MODULE_LICENSE("GPL");
+#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
+
+/* Scan code for Fn key on TOS1900 models */
+#define TOS1900_FN_SCAN 0x6e
+
/* Toshiba ACPI method paths */
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
@@ -95,6 +102,8 @@ MODULE_LICENSE("GPL");
#define HCI_WIRELESS 0x0056
/* field definitions */
+#define HCI_HOTKEY_DISABLE 0x0b
+#define HCI_HOTKEY_ENABLE 0x09
#define HCI_LCD_BRIGHTNESS_BITS 3
#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
@@ -111,6 +120,7 @@ struct toshiba_acpi_dev {
const char *method_hci;
struct rfkill *bt_rfk;
struct input_dev *hotkey_dev;
+ struct work_struct hotkey_work;
struct backlight_device *backlight_dev;
struct led_classdev led_dev;
@@ -118,14 +128,18 @@ struct toshiba_acpi_dev {
int last_key_event;
int key_event_valid;
- int illumination_supported:1;
- int video_supported:1;
- int fan_supported:1;
- int system_event_supported:1;
+ unsigned int illumination_supported:1;
+ unsigned int video_supported:1;
+ unsigned int fan_supported:1;
+ unsigned int system_event_supported:1;
+ unsigned int ntfy_supported:1;
+ unsigned int info_supported:1;
struct mutex mutex;
};
+static struct toshiba_acpi_dev *toshiba_acpi;
+
static const struct acpi_device_id toshiba_device_ids[] = {
{"TOS6200", 0},
{"TOS6208", 0},
@@ -138,6 +152,8 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
{ KE_KEY, 0x101, { KEY_MUTE } },
{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
{ KE_KEY, 0x103, { KEY_ZOOMIN } },
+ { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
+ { KE_KEY, 0x139, { KEY_ZOOMRESET } },
{ KE_KEY, 0x13b, { KEY_COFFEE } },
{ KE_KEY, 0x13c, { KEY_BATTERY } },
{ KE_KEY, 0x13d, { KEY_SLEEP } },
@@ -146,7 +162,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
{ KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
{ KE_KEY, 0x142, { KEY_WLAN } },
- { KE_KEY, 0x143, { KEY_PROG1 } },
+ { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
{ KE_KEY, 0x17f, { KEY_FN } },
{ KE_KEY, 0xb05, { KEY_PROG2 } },
{ KE_KEY, 0xb06, { KEY_WWW } },
@@ -156,6 +172,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
{ KE_KEY, 0xb32, { KEY_NEXTSONG } },
{ KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
{ KE_KEY, 0xb5a, { KEY_MEDIA } },
+ { KE_IGNORE, 0x1430, { KEY_RESERVED } },
{ KE_END, 0 },
};
@@ -847,10 +864,78 @@ static const struct backlight_ops toshiba_backlight_data = {
.update_status = set_lcd_status,
};
+static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
+ struct serio *port)
+{
+ if (str & 0x20)
+ return false;
+
+ if (unlikely(data == 0xe0))
+ return false;
+
+ if ((data & 0x7f) == TOS1900_FN_SCAN) {
+ schedule_work(&toshiba_acpi->hotkey_work);
+ return true;
+ }
+
+ return false;
+}
+
+static void toshiba_acpi_hotkey_work(struct work_struct *work)
+{
+ acpi_handle ec_handle = ec_get_handle();
+ acpi_status status;
+
+ if (!ec_handle)
+ return;
+
+ status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
+ if (ACPI_FAILURE(status))
+ pr_err("ACPI NTFY method execution failed\n");
+}
+
+/*
+ * Returns hotkey scancode, or < 0 on failure.
+ */
+static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
+{
+ struct acpi_buffer buf;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ buf.pointer = &out_obj;
+ buf.length = sizeof(out_obj);
+
+ status = acpi_evaluate_object(dev->acpi_dev->handle, "INFO",
+ NULL, &buf);
+ if (ACPI_FAILURE(status) || out_obj.type != ACPI_TYPE_INTEGER) {
+ pr_err("ACPI INFO method execution failed\n");
+ return -EIO;
+ }
+
+ return out_obj.integer.value;
+}
+
+static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
+ int scancode)
+{
+ if (scancode == 0x100)
+ return;
+
+ /* act on key press; ignore key release */
+ if (scancode & 0x80)
+ return;
+
+ if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
+ pr_info("Unknown key %x\n", scancode);
+}
+
static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
{
acpi_status status;
+ acpi_handle ec_handle, handle;
int error;
+ u32 hci_result;
dev->hotkey_dev = input_allocate_device();
if (!dev->hotkey_dev) {
@@ -866,21 +951,67 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
if (error)
goto err_free_dev;
+ /*
+ * For some machines the SCI responsible for providing hotkey
+ * notification doesn't fire. We can trigger the notification
+ * whenever the Fn key is pressed using the NTFY method, if
+ * supported, so if it's present set up an i8042 key filter
+ * for this purpose.
+ */
+ status = AE_ERROR;
+ ec_handle = ec_get_handle();
+ if (ec_handle)
+ status = acpi_get_handle(ec_handle, "NTFY", &handle);
+
+ if (ACPI_SUCCESS(status)) {
+ INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
+
+ error = i8042_install_filter(toshiba_acpi_i8042_filter);
+ if (error) {
+ pr_err("Error installing key filter\n");
+ goto err_free_keymap;
+ }
+
+ dev->ntfy_supported = 1;
+ }
+
+ /*
+ * Determine hotkey query interface. Prefer using the INFO
+ * method when it is available.
+ */
+ status = acpi_get_handle(dev->acpi_dev->handle, "INFO", &handle);
+ if (ACPI_SUCCESS(status)) {
+ dev->info_supported = 1;
+ } else {
+ hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
+ if (hci_result == HCI_SUCCESS)
+ dev->system_event_supported = 1;
+ }
+
+ if (!dev->info_supported && !dev->system_event_supported) {
+ pr_warn("No hotkey query interface found\n");
+ goto err_remove_filter;
+ }
+
status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
if (ACPI_FAILURE(status)) {
pr_info("Unable to enable hotkeys\n");
error = -ENODEV;
- goto err_free_keymap;
+ goto err_remove_filter;
}
error = input_register_device(dev->hotkey_dev);
if (error) {
pr_info("Unable to register input device\n");
- goto err_free_keymap;
+ goto err_remove_filter;
}
+ hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
return 0;
+ err_remove_filter:
+ if (dev->ntfy_supported)
+ i8042_remove_filter(toshiba_acpi_i8042_filter);
err_free_keymap:
sparse_keymap_free(dev->hotkey_dev);
err_free_dev:
@@ -895,6 +1026,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
remove_toshiba_proc_entries(dev);
+ if (dev->ntfy_supported) {
+ i8042_remove_filter(toshiba_acpi_i8042_filter);
+ cancel_work_sync(&dev->hotkey_work);
+ }
+
if (dev->hotkey_dev) {
input_unregister_device(dev->hotkey_dev);
sparse_keymap_free(dev->hotkey_dev);
@@ -911,6 +1047,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
if (dev->illumination_supported)
led_classdev_unregister(&dev->led_dev);
+ if (toshiba_acpi)
+ toshiba_acpi = NULL;
+
kfree(dev);
return 0;
@@ -936,12 +1075,14 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
{
struct toshiba_acpi_dev *dev;
const char *hci_method;
- u32 hci_result;
u32 dummy;
bool bt_present;
int ret = 0;
struct backlight_properties props;
+ if (toshiba_acpi)
+ return -EBUSY;
+
pr_info("Toshiba Laptop ACPI Extras version %s\n",
TOSHIBA_ACPI_VERSION);
@@ -963,11 +1104,6 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
mutex_init(&dev->mutex);
- /* enable event fifo */
- hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
- if (hci_result == HCI_SUCCESS)
- dev->system_event_supported = 1;
-
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
dev->backlight_dev = backlight_device_register("toshiba",
@@ -1024,6 +1160,8 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
create_toshiba_proc_entries(dev);
+ toshiba_acpi = dev;
+
return 0;
error:
@@ -1036,40 +1174,64 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
u32 hci_result, value;
int retries = 3;
+ int scancode;
- if (!dev->system_event_supported || event != 0x80)
+ if (event != 0x80)
return;
- do {
- hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
- switch (hci_result) {
- case HCI_SUCCESS:
- if (value == 0x100)
- continue;
- /* act on key press; ignore key release */
- if (value & 0x80)
- continue;
-
- if (!sparse_keymap_report_event(dev->hotkey_dev,
- value, 1, true)) {
- pr_info("Unknown key %x\n",
- value);
+ if (dev->info_supported) {
+ scancode = toshiba_acpi_query_hotkey(dev);
+ if (scancode < 0)
+ pr_err("Failed to query hotkey event\n");
+ else if (scancode != 0)
+ toshiba_acpi_report_hotkey(dev, scancode);
+ } else if (dev->system_event_supported) {
+ do {
+ hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
+ switch (hci_result) {
+ case HCI_SUCCESS:
+ toshiba_acpi_report_hotkey(dev, (int)value);
+ break;
+ case HCI_NOT_SUPPORTED:
+ /*
+ * This is a workaround for an unresolved
+ * issue on some machines where system events
+ * sporadically become disabled.
+ */
+ hci_write1(dev, HCI_SYSTEM_EVENT, 1,
+ &hci_result);
+ pr_notice("Re-enabled hotkeys\n");
+ /* fall through */
+ default:
+ retries--;
+ break;
}
- break;
- case HCI_NOT_SUPPORTED:
- /* This is a workaround for an unresolved issue on
- * some machines where system events sporadically
- * become disabled. */
- hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
- pr_notice("Re-enabled hotkeys\n");
- /* fall through */
- default:
- retries--;
- break;
- }
- } while (retries && hci_result != HCI_EMPTY);
+ } while (retries && hci_result != HCI_EMPTY);
+ }
+}
+
+static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
+ pm_message_t state)
+{
+ struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+ u32 result;
+
+ if (dev->hotkey_dev)
+ hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
+
+ return 0;
}
+static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
+{
+ struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+ u32 result;
+
+ if (dev->hotkey_dev)
+ hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
+
+ return 0;
+}
static struct acpi_driver toshiba_acpi_driver = {
.name = "Toshiba ACPI driver",
@@ -1080,6 +1242,8 @@ static struct acpi_driver toshiba_acpi_driver = {
.add = toshiba_acpi_add,
.remove = toshiba_acpi_remove,
.notify = toshiba_acpi_notify,
+ .suspend = toshiba_acpi_suspend,
+ .resume = toshiba_acpi_resume,
},
};
@@ -1087,6 +1251,14 @@ static int __init toshiba_acpi_init(void)
{
int ret;
+ /*
+ * Machines with this WMI guid aren't supported due to bugs in
+ * their AML. This check relies on wmi initializing before
+ * toshiba_acpi to guarantee guids have been identified.
+ */
+ if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+ return -ENODEV;
+
toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
if (!toshiba_proc_dir) {
pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c
index e549eeeda121..41781ed8301c 100644
--- a/drivers/platform/x86/xo1-rfkill.c
+++ b/drivers/platform/x86/xo1-rfkill.c
@@ -67,19 +67,8 @@ static struct platform_driver xo1_rfkill_driver = {
.remove = __devexit_p(xo1_rfkill_remove),
};
-static int __init xo1_rfkill_init(void)
-{
- return platform_driver_register(&xo1_rfkill_driver);
-}
-
-static void __exit xo1_rfkill_exit(void)
-{
- platform_driver_unregister(&xo1_rfkill_driver);
-}
+module_platform_driver(xo1_rfkill_driver);
MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:xo1-rfkill");
-
-module_init(xo1_rfkill_init);
-module_exit(xo1_rfkill_exit);
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index b859d16cf78c..769d265b221b 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -17,7 +17,6 @@
#include <asm/page.h>
#include <asm/desc.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include "pnpbios.h"
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index cfe86853feb2..9d4222648640 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -65,7 +65,6 @@
#include <asm/page.h>
#include <asm/desc.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include "../base.h"
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index dc87eda65814..eb415bd76494 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -458,6 +458,11 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
if (rtc->uie_rtctimer.enabled == enabled)
goto out;
+ if (rtc->uie_unsupported) {
+ err = -EINVAL;
+ goto out;
+ }
+
if (enabled) {
struct rtc_time tm;
ktime_t now, onesec;
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index f04761e6622d..afee0e8ae714 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -376,6 +376,9 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
#endif /* VRTC_CALIBRATION */
+
+ device_init_wakeup(&pdev->dev, 1);
+
return 0;
out_rtc:
free_irq(info->irq, info);
@@ -401,10 +404,34 @@ static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_rtc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev))
+ chip->wakeup_flag |= 1 << PM8607_IRQ_RTC;
+ return 0;
+}
+static int pm860x_rtc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev))
+ chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume);
+
static struct platform_driver pm860x_rtc_driver = {
.driver = {
.name = "88pm860x-rtc",
.owner = THIS_MODULE,
+ .pm = &pm860x_rtc_pm_ops,
},
.probe = pm860x_rtc_probe,
.remove = __devexit_p(pm860x_rtc_remove),
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index e954a759ba85..42f5f829b3ee 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -360,6 +360,8 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op)
&mpc5200_rtc_ops, THIS_MODULE);
}
+ rtc->rtc->uie_unsupported = 1;
+
if (IS_ERR(rtc->rtc)) {
err = PTR_ERR(rtc->rtc);
goto out_free_irq;
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index 1300962486d1..b2185f4255aa 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -12,6 +12,7 @@
#include <linux/bcd.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/module.h>
@@ -294,11 +295,19 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static struct of_device_id rtc_mv_of_match_table[] = {
+ { .compatible = "mrvl,orion-rtc", },
+ {}
+};
+#endif
+
static struct platform_driver mv_rtc_driver = {
.remove = __exit_p(mv_rtc_remove),
.driver = {
.name = "rtc-mv",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rtc_mv_of_match_table),
},
};
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 4940fa8c4e10..50a5c4adee48 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -33,6 +33,7 @@
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/bitops.h>
+#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 168525a9c292..231a1d85127b 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -21,6 +21,7 @@
#include <asm/chpid.h>
#include <asm/sclp.h>
#include <asm/setup.h>
+#include <asm/ctl_reg.h>
#include "sclp.h"
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
index 425f741a280c..d0a2dff43fb4 100644
--- a/drivers/s390/cio/crw.c
+++ b/drivers/s390/cio/crw.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/wait.h>
#include <asm/crw.h>
+#include <asm/ctl_reg.h>
static DEFINE_MUTEX(crw_handler_mutex);
static crw_handler_t crw_handlers[NR_RSCS];
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 12ae1817b172..7e9a72eb2fe0 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -42,10 +42,10 @@
#include <asm/reset.h>
#include <asm/airq.h>
#include <linux/atomic.h>
-#include <asm/system.h>
#include <asm/isc.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
+#include <asm/facility.h>
#include "ap_bus.h"
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 826157f38694..327657e2e264 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -16,7 +16,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 8d6e508222b8..2236aea3ca2f 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -40,7 +40,6 @@
#include <linux/fs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/openpromio.h>
#ifdef CONFIG_PCI
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 0b31658ccde5..a9e468cc1cac 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -19,7 +19,6 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index f672491774eb..a3adfb4357f5 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -129,7 +129,6 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/byteorder.h>
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index f66c33b9ab41..d4da3708763b 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -47,7 +47,6 @@
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index bfd618a69499..374c4edf4fcb 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -41,7 +41,6 @@
#include <linux/firmware.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/dma.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index f17c92cf808b..19a36945e6fd 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -239,7 +239,6 @@
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/blkdev.h>
-#include <asm/system.h>
#include <linux/completion.h>
#include <linux/errno.h>
#include <linux/string.h>
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index ed119cedaae0..ede91f378000 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -42,7 +42,6 @@
#include <linux/slab.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/io.h>
#include "scsi.h"
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 1c10b796c1a2..a3e6ed353917 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -53,7 +53,6 @@
#include <linux/gfp.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/io.h>
#include "scsi.h"
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 2fe9e90e53d9..cbde1dca45ad 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -61,7 +61,6 @@
#include <linux/aer.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi.h>
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index c454e44cf51c..b330438ac662 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -138,7 +138,6 @@
#include <linux/stringify.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <asm/ecard.h>
#include "../scsi.h"
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index a3398fe70a9c..c3b99c93637a 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -12,7 +12,6 @@
#include <asm/ecard.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "../scsi.h"
#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 849cdf89f7bb..d25f944b59c2 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -13,7 +13,6 @@
#include <asm/ecard.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "../scsi.h"
#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 7e6eca4a125e..f29d5121d5ed 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -30,7 +30,6 @@
#include <linux/blkdev.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <scsi/scsi.h>
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index c2677ba29c74..4b11bb04f5c4 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -72,7 +72,6 @@
#endif
-#include <asm/system.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index a2c6135d337e..53bfcaa86f09 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -93,7 +93,6 @@
#include <linux/mca-legacy.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 643f6d500fe7..1a2a1e5824e3 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -282,7 +282,6 @@
#include <linux/slab.h>
#include <scsi/scsicam.h>
-#include <asm/system.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 81182badfeb1..1a5954f0915a 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -100,7 +100,6 @@
#undef NCR5380_STAT_LIMIT
#endif
-#include <asm/system.h>
#include <asm/io.h>
#include <linux/signal.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index d42ec921de46..5d72274c507f 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -129,7 +129,6 @@
#include <linux/reboot.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/spinlock.h>
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 67fc8ffd52e6..cd09132d5d7d 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -32,7 +32,6 @@
#include <linux/spinlock.h>
#include <linux/init.h>
-#include <asm/system.h>
#include <asm/io.h>
#include "scsi.h"
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index bdfa223a7dbb..134a0ae85bb7 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -4890,11 +4890,8 @@ static struct vio_driver ibmvfc_driver = {
.probe = ibmvfc_probe,
.remove = ibmvfc_remove,
.get_desired_dma = ibmvfc_get_desired_dma,
- .driver = {
- .name = IBMVFC_NAME,
- .owner = THIS_MODULE,
- .pm = &ibmvfc_pm_ops,
- }
+ .name = IBMVFC_NAME,
+ .pm = &ibmvfc_pm_ops,
};
static struct fc_function_template ibmvfc_transport_functions = {
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index e984951baeb6..3a6c4742951e 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -2061,11 +2061,8 @@ static struct vio_driver ibmvscsi_driver = {
.probe = ibmvscsi_probe,
.remove = ibmvscsi_remove,
.get_desired_dma = ibmvscsi_get_desired_dma,
- .driver = {
- .name = "ibmvscsi",
- .owner = THIS_MODULE,
- .pm = &ibmvscsi_pm_ops,
- }
+ .name = "ibmvscsi",
+ .pm = &ibmvscsi_pm_ops,
};
static struct srp_function_template ibmvscsi_transport_functions = {
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 2256babe0474..aa7ed81e9237 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -918,10 +918,7 @@ static struct vio_driver ibmvstgt_driver = {
.id_table = ibmvstgt_device_table,
.probe = ibmvstgt_probe,
.remove = ibmvstgt_remove,
- .driver = {
- .name = "ibmvscsis",
- .owner = THIS_MODULE,
- }
+ .name = "ibmvscsis",
};
static int get_system_info(void)
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 112f1bec7756..deb5b6d8398e 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -123,7 +123,6 @@
#include <linux/stat.h>
#include <asm/io.h>
-#include <asm/system.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index e6173376605d..e5cd8d8d4ce7 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -22,7 +22,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
-#include <asm/system.h>
#include <asm/pci-bridge.h>
#include <asm/macio.h>
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 2bccfbe5661e..24828b54773a 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -43,7 +43,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 494474779532..e8a04ae3276a 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -33,7 +33,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/hydra.h>
#include <asm/processor.h>
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 4b3b4755945c..5982a587babc 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -115,7 +115,6 @@
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 002924963cd8..62b616891a33 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -38,7 +38,6 @@
#include <linux/dma-mapping.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <scsi/scsi.h>
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index de0b1a704fb5..21883a2d6324 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -54,7 +54,6 @@ static const char * osst_version = "0.99.4";
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
-#include <asm/system.h>
/* The driver prints some debugging information on the console if DEBUG
is defined and non-zero. */
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index f2018b46f494..2f72c9807b12 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -113,7 +113,6 @@
#include <linux/module.h>
-#include <asm/system.h>
#include <linux/signal.h>
#include <linux/proc_fs.h>
#include <asm/io.h>
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index d838205ab169..6c6486f626ee 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -359,7 +359,6 @@
#include <asm/byteorder.h>
#include <asm/processor.h>
#include <asm/types.h>
-#include <asm/system.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index e40dc1cb09a0..b191dd549207 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -35,7 +35,6 @@
#include "qlogicpti.h"
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/ptrace.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 9262cdfa4b23..a15f691f9d34 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -42,7 +42,6 @@ static const char *verstr = "20101219";
#include <asm/uaccess.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index baf7328de956..6e25889db9d4 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -63,7 +63,6 @@
#include <linux/blkdev.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sun3ints.h>
#include <asm/dvma.h>
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index fbba78e5722e..a3dd55d1d2fd 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -25,7 +25,6 @@
#include <linux/blkdev.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/sun3ints.h>
#include <asm/dvma.h>
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 012c86edd59f..ac4eca6a5328 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -37,7 +37,6 @@
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <linux/blkdev.h>
#include <linux/isapnp.h>
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 041eaaace2c3..d672d97fb84a 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -106,7 +106,6 @@
* $Log: t128.c,v $
*/
-#include <asm/system.h>
#include <linux/signal.h>
#include <linux/io.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 90e104d6b558..9c216e563568 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -410,7 +410,6 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 7e22b737dfd8..14e0c40a68c9 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -141,7 +141,6 @@
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/dma.h>
#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 9ee0afef2d16..d89a5dfd3ade 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -179,7 +179,6 @@
#include <linux/stat.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <asm/dma.h>
#include <scsi/scsi.h>
diff --git a/drivers/sh/intc/balancing.c b/drivers/sh/intc/balancing.c
index cec7a96f2c09..bc780807ccb0 100644
--- a/drivers/sh/intc/balancing.c
+++ b/drivers/sh/intc/balancing.c
@@ -9,7 +9,7 @@
*/
#include "internals.h"
-static unsigned long dist_handle[NR_IRQS];
+static unsigned long dist_handle[INTC_NR_IRQS];
void intc_balancing_enable(unsigned int irq)
{
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index 8e1fcd5e5f0d..7e562ccb6997 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -43,7 +43,7 @@ static unsigned int nr_intc_controllers;
* - this needs to be at least 2 for 5-bit priorities on 7780
*/
static unsigned int default_prio_level = 2; /* 2 - 16 */
-static unsigned int intc_prio_level[NR_IRQS]; /* for now */
+static unsigned int intc_prio_level[INTC_NR_IRQS]; /* for now */
unsigned int intc_get_dfl_prio_level(void)
{
diff --git a/drivers/sh/intc/handle.c b/drivers/sh/intc/handle.c
index d80799f111df..7863a44918a2 100644
--- a/drivers/sh/intc/handle.c
+++ b/drivers/sh/intc/handle.c
@@ -13,7 +13,7 @@
#include <linux/spinlock.h>
#include "internals.h"
-static unsigned long ack_handle[NR_IRQS];
+static unsigned long ack_handle[INTC_NR_IRQS];
static intc_enum __init intc_grp_id(struct intc_desc *desc,
intc_enum enum_id)
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
index c7ec49ffd9f6..93cec21e788b 100644
--- a/drivers/sh/intc/virq.c
+++ b/drivers/sh/intc/virq.c
@@ -17,7 +17,7 @@
#include <linux/export.h>
#include "internals.h"
-static struct intc_map_entry intc_irq_xlate[NR_IRQS];
+static struct intc_map_entry intc_irq_xlate[INTC_NR_IRQS];
struct intc_virq_list {
unsigned int irq;
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 8418eb036651..b9f0192758d6 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
+#include <linux/types.h>
#include "spi-dw.h"
@@ -136,6 +137,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
txconf.dst_maxburst = LNW_DMA_MSIZE_16;
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ txconf.device_fc = false;
txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
(unsigned long) &txconf);
@@ -144,7 +146,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
dws->tx_sgl.dma_address = dws->tx_dma;
dws->tx_sgl.length = dws->len;
- txdesc = txchan->device->device_prep_slave_sg(txchan,
+ txdesc = dmaengine_prep_slave_sg(txchan,
&dws->tx_sgl,
1,
DMA_MEM_TO_DEV,
@@ -158,6 +160,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
rxconf.src_maxburst = LNW_DMA_MSIZE_16;
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ rxconf.device_fc = false;
rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
(unsigned long) &rxconf);
@@ -166,7 +169,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
dws->rx_sgl.dma_address = dws->rx_dma;
dws->rx_sgl.length = dws->len;
- rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+ rxdesc = dmaengine_prep_slave_sg(rxchan,
&dws->rx_sgl,
1,
DMA_DEV_TO_MEM,
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index d46e55c720b7..6db2887852d6 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -633,8 +633,8 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
if (!nents)
return ERR_PTR(-ENOMEM);
- txd = chan->device->device_prep_slave_sg(chan, sgt->sgl, nents,
- slave_dirn, DMA_CTRL_ACK);
+ txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents,
+ slave_dirn, DMA_CTRL_ACK);
if (!txd) {
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
return ERR_PTR(-ENOMEM);
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 610f7391456e..9b0d71696039 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -47,7 +47,6 @@
#include <linux/spi/spi_bitbang.h>
#include <linux/module.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <asm/io.h>
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 13448c832c44..e496f799b7a9 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -359,11 +359,6 @@ static int orion_spi_setup(struct spi_device *spi)
orion_spi = spi_master_get_devdata(spi->master);
- /* Fix ac timing if required. */
- if (orion_spi->spi_info->enable_clock_fix)
- orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
- (1 << 14));
-
if ((spi->max_speed_hz == 0)
|| (spi->max_speed_hz > orion_spi->max_speed))
spi->max_speed_hz = orion_spi->max_speed;
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index dc8485d1e883..96f0da66b185 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -880,10 +880,12 @@ static int configure_dma(struct pl022 *pl022)
struct dma_slave_config rx_conf = {
.src_addr = SSP_DR(pl022->phybase),
.direction = DMA_DEV_TO_MEM,
+ .device_fc = false,
};
struct dma_slave_config tx_conf = {
.dst_addr = SSP_DR(pl022->phybase),
.direction = DMA_MEM_TO_DEV,
+ .device_fc = false,
};
unsigned int pages;
int ret;
@@ -1017,7 +1019,7 @@ static int configure_dma(struct pl022 *pl022)
goto err_tx_sgmap;
/* Send both scatterlists */
- rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+ rxdesc = dmaengine_prep_slave_sg(rxchan,
pl022->sgt_rx.sgl,
rx_sglen,
DMA_DEV_TO_MEM,
@@ -1025,7 +1027,7 @@ static int configure_dma(struct pl022 *pl022)
if (!rxdesc)
goto err_rxdesc;
- txdesc = txchan->device->device_prep_slave_sg(txchan,
+ txdesc = dmaengine_prep_slave_sg(txchan,
pl022->sgt_tx.sgl,
tx_sglen,
DMA_MEM_TO_DEV,
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 5c6fa5ed3366..ec47d3bdfd13 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1099,7 +1099,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
sg_dma_address(sg) = dma->rx_buf_dma + sg->offset;
}
sg = dma->sg_rx_p;
- desc_rx = dma->chan_rx->device->device_prep_slave_sg(dma->chan_rx, sg,
+ desc_rx = dmaengine_prep_slave_sg(dma->chan_rx, sg,
num, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) {
@@ -1158,7 +1158,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
sg_dma_address(sg) = dma->tx_buf_dma + sg->offset;
}
sg = dma->sg_tx_p;
- desc_tx = dma->chan_tx->device->device_prep_slave_sg(dma->chan_tx,
+ desc_tx = dmaengine_prep_slave_sg(dma->chan_tx,
sg, num, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 59e095362c81..c2832124bb3e 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -381,8 +381,7 @@ int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
repeat:
fdt = files_fdtable(files);
- fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
- files->next_fd);
+ fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, files->next_fd);
/*
* N.B. For clone tasks sharing a files structure, this test
@@ -410,11 +409,11 @@ repeat:
goto repeat;
}
- FD_SET(fd, fdt->open_fds);
+ __set_open_fd(fd, fdt);
if (flags & O_CLOEXEC)
- FD_SET(fd, fdt->close_on_exec);
+ __set_close_on_exec(fd, fdt);
else
- FD_CLR(fd, fdt->close_on_exec);
+ __clear_close_on_exec(fd, fdt);
files->next_fd = fd + 1;
#if 1
/* Sanity check */
@@ -455,7 +454,7 @@ static void task_fd_install(
static void __put_unused_fd(struct files_struct *files, unsigned int fd)
{
struct fdtable *fdt = files_fdtable(files);
- __FD_CLR(fd, fdt->open_fds);
+ __clear_open_fd(fd, fdt);
if (fd < files->next_fd)
files->next_fd = fd;
}
@@ -481,7 +480,7 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd)
if (!filp)
goto out_unlock;
rcu_assign_pointer(fdt->fd[fd], NULL);
- FD_CLR(fd, fdt->close_on_exec);
+ __clear_close_on_exec(fd, fdt);
__put_unused_fd(files, fd);
spin_unlock(&files->file_lock);
retval = filp_close(filp, files);
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index db1fd63aaab3..bf185e2807d1 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -42,7 +42,6 @@
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
-#include <asm/system.h>
#include "comedidev.h"
#include "internal.h"
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index c9e8c4785768..915157d47805 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -86,7 +86,6 @@ TODO:
#include "../comedidev.h"
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <asm/system.h>
#include "comedi_pci.h"
#include "8253.h"
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index fd274e9c7b78..13e9c8071696 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -55,7 +55,6 @@
#include "comedi_pci.h"
#include "../comedidev.h"
-#include <asm/system.h>
#define PCI_MITE_SIZE 4096
#define PCI_DAQ_SIZE 4096
diff --git a/drivers/staging/crystalhd/bc_dts_defs.h b/drivers/staging/crystalhd/bc_dts_defs.h
index 8cd51a7aad8e..647e116e10de 100644
--- a/drivers/staging/crystalhd/bc_dts_defs.h
+++ b/drivers/staging/crystalhd/bc_dts_defs.h
@@ -26,6 +26,8 @@
#ifndef _BC_DTS_DEFS_H_
#define _BC_DTS_DEFS_H_
+#include <linux/types.h>
+
/* BIT Mask */
#define BC_BIT(_x) (1 << (_x))
diff --git a/drivers/staging/crystalhd/crystalhd.h b/drivers/staging/crystalhd/crystalhd.h
index 3f4d79515026..b3a550bd5b06 100644
--- a/drivers/staging/crystalhd/crystalhd.h
+++ b/drivers/staging/crystalhd/crystalhd.h
@@ -1,7 +1,6 @@
#ifndef _CRYSTALHD_H_
#define _CRYSTALHD_H_
-#include <asm/system.h>
#include "bc_dts_defs.h"
#include "crystalhd_misc.h"
#include "bc_dts_glob_lnx.h"
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.h b/drivers/staging/crystalhd/crystalhd_lnx.h
index a81f9298b0a1..a9e36336d097 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.h
+++ b/drivers/staging/crystalhd/crystalhd_lnx.h
@@ -45,7 +45,6 @@
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include "crystalhd.h"
diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h
index 84c87938a831..8cdaa7a34814 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.h
+++ b/drivers/staging/crystalhd/crystalhd_misc.h
@@ -37,6 +37,7 @@
#include <linux/ioctl.h>
#include <linux/dma-mapping.h>
#include <linux/sched.h>
+#include "bc_dts_glob_lnx.h"
/* Global log level variable defined in crystal_misc.c file */
extern uint32_t g_linklog_level;
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 3f919babe79b..886f5650444e 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -70,7 +70,6 @@
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
index 7569aa0f24d1..c4a8a0a26eb5 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
@@ -29,7 +29,6 @@
#include <linux/interrupt.h>
#include <linux/in.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/netdevice.h>
diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c
index 6c9279a6d606..ece2dd146487 100644
--- a/drivers/staging/media/go7007/go7007-driver.c
+++ b/drivers/staging/media/go7007/go7007-driver.c
@@ -30,7 +30,6 @@
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c
index b8cfa1a6eaeb..6bc82aaeef11 100644
--- a/drivers/staging/media/go7007/go7007-i2c.c
+++ b/drivers/staging/media/go7007/go7007-i2c.c
@@ -26,7 +26,6 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include "go7007-priv.h"
#include "wis-i2c.h"
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index f91658670e34..3ef4cd8b4de3 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -34,7 +34,6 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include "go7007.h"
#include "go7007-priv.h"
diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c
index d071c838ac2a..5af29ff68bfd 100644
--- a/drivers/staging/media/go7007/snd-go7007.c
+++ b/drivers/staging/media/go7007/snd-go7007.c
@@ -29,7 +29,6 @@
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <asm/system.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c
index 97352cf6bd98..3295ea63f3eb 100644
--- a/drivers/staging/media/lirc/lirc_serial.c
+++ b/drivers/staging/media/lirc/lirc_serial.c
@@ -66,7 +66,6 @@
#include <linux/poll.h>
#include <linux/platform_device.h>
-#include <asm/system.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/fcntl.h>
diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c
index c94382b917ac..945d9623550b 100644
--- a/drivers/staging/media/lirc/lirc_sir.c
+++ b/drivers/staging/media/lirc/lirc_sir.c
@@ -49,7 +49,6 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/poll.h>
-#include <asm/system.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <linux/fcntl.h>
diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c
index a6910da78a64..cf4c29d10e7f 100644
--- a/drivers/staging/mei/wd.c
+++ b/drivers/staging/mei/wd.c
@@ -323,6 +323,7 @@ static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int t
mutex_lock(&dev->device_lock);
dev->wd_timeout = timeout;
+ wd_dev->timeout = timeout;
mei_wd_set_start_timeout(dev, dev->wd_timeout);
mutex_unlock(&dev->device_lock);
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 4683d5f355c0..6183573f112f 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -58,7 +58,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define LCD_MINOR 156
#define KEYPAD_MINOR 185
diff --git a/drivers/staging/sbe-2t3e3/io.c b/drivers/staging/sbe-2t3e3/io.c
index b458ff034067..9a50bcc59594 100644
--- a/drivers/staging/sbe-2t3e3/io.c
+++ b/drivers/staging/sbe-2t3e3/io.c
@@ -11,7 +11,6 @@
*/
#include <linux/ip.h>
-#include <asm/system.h>
#include "2t3e3.h"
#include "ctrl.h"
diff --git a/drivers/staging/ste_rmi4/Makefile b/drivers/staging/ste_rmi4/Makefile
index 176f46900571..e4c03351420f 100644
--- a/drivers/staging/ste_rmi4/Makefile
+++ b/drivers/staging/ste_rmi4/Makefile
@@ -2,4 +2,4 @@
# Makefile for the RMI4 touchscreen driver.
#
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
-obj-$(CONFIG_MACH_U8500) += board-mop500-u8500uib-rmi4.o
+obj-$(CONFIG_MACH_MOP500) += board-mop500-u8500uib-rmi4.o
diff --git a/drivers/staging/telephony/phonedev.c b/drivers/staging/telephony/phonedev.c
index 1915af201175..1dd0b6717ccc 100644
--- a/drivers/staging/telephony/phonedev.c
+++ b/drivers/staging/telephony/phonedev.c
@@ -24,7 +24,6 @@
#include <linux/phonedev.h>
#include <linux/init.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <linux/kmod.h>
#include <linux/sem.h>
diff --git a/drivers/staging/tidspbridge/include/dspbridge/host_os.h b/drivers/staging/tidspbridge/include/dspbridge/host_os.h
index a2f31c69d12e..ed00d3da3205 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/host_os.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/host_os.h
@@ -17,7 +17,6 @@
#ifndef _HOST_OS_H_
#define _HOST_OS_H_
-#include <asm/system.h>
#include <linux/atomic.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index a2cbb29c3f59..7084f414846e 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -74,7 +74,6 @@
#include <linux/in.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/netdevice.h>
diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c
index dab603e0f452..d5bf0a7012f2 100644
--- a/drivers/staging/wlags49_h2/wl_main.c
+++ b/drivers/staging/wlags49_h2/wl_main.c
@@ -86,8 +86,7 @@
// #include <linux/in.h>
// #include <linux/delay.h>
// #include <asm/io.h>
-// #include <asm/system.h>
-// #include <asm/bitops.h>
+// // #include <asm/bitops.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 9c16f5478a75..90820ff1aced 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -79,8 +79,7 @@
// #include <linux/delay.h>
// #include <linux/skbuff.h>
// #include <asm/io.h>
-// #include <asm/system.h>
-// #include <asm/bitops.h>
+// // #include <asm/bitops.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 2bd9b84ace8e..3df990c7306a 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -77,7 +77,6 @@
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/delay.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index b748a3ff7954..f104e6f1e980 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -73,8 +73,7 @@
// #include <linux/in.h>
// #include <linux/delay.h>
// #include <asm/io.h>
-// #include <asm/system.h>
-// #include <asm/bitops.h>
+// // #include <asm/bitops.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index afadcd43d14e..24145c30c9b0 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -85,7 +85,6 @@ static char *serial_version = "4.30";
#include <asm/setup.h>
-#include <asm/system.h>
#include <asm/irq.h>
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 3a0d53d6368f..ee307799271a 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -310,11 +310,8 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev)
static struct vio_driver hvc_vio_driver = {
.id_table = hvc_driver_table,
.probe = hvc_vio_probe,
- .remove = __devexit_p(hvc_vio_remove),
- .driver = {
- .name = hvc_driver_name,
- .owner = THIS_MODULE,
- }
+ .remove = hvc_vio_remove,
+ .name = hvc_driver_name,
};
static int __init hvc_vio_init(void)
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index d23759183b47..3436436fe2d7 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -879,10 +879,7 @@ static struct vio_driver hvcs_vio_driver = {
.id_table = hvcs_driver_table,
.probe = hvcs_probe,
.remove = __devexit_p(hvcs_remove),
- .driver = {
- .name = hvcs_driver_name,
- .owner = THIS_MODULE,
- }
+ .name = hvcs_driver_name,
};
/* Only called from hvcs_get_pi please */
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 03c14979accf..794ecb40017c 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -133,7 +133,6 @@
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <linux/pci.h>
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 8a8d0440bab0..324467d28a54 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -46,7 +46,6 @@
#include <linux/slab.h>
#include <linux/ratelimit.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 17ff377e4129..c6f372dd5623 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -41,7 +41,6 @@
#include <linux/slab.h>
#include <linux/ratelimit.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index a09ce3ef5d74..1b2db9a3038c 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -102,7 +102,6 @@
#include <linux/if.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/termios.h>
#include <asm/uaccess.h>
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index d2256d08ee7e..94b6eda87afd 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -50,7 +50,6 @@
#include <linux/uaccess.h>
#include <linux/module.h>
-#include <asm/system.h>
/* number of characters left in xmit buffer before select has we have room */
#define WAKEUP_CHARS 256
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index f96ecaec24f8..eeae7fafe9a7 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -27,7 +27,6 @@
#include <linux/devpts_fs.h>
#include <linux/slab.h>
-#include <asm/system.h>
#ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver;
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
index f899996b4363..a44345a2dbb4 100644
--- a/drivers/tty/serial/21285.c
+++ b/drivers/tty/serial/21285.c
@@ -16,6 +16,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
+#include <asm/system_info.h>
#include <asm/hardware/dec21285.h>
#include <mach/hardware.h>
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 7398390e7e65..5ce782529d65 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -39,7 +39,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 86090605a84e..29b695d041ec 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -43,7 +43,6 @@
#include <linux/delay.h>
#include <linux/major.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 20d795d9b591..0c65c9e66986 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -51,6 +51,7 @@
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/delay.h>
+#include <linux/types.h>
#include <asm/io.h>
#include <asm/sizes.h>
@@ -271,6 +272,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.direction = DMA_MEM_TO_DEV,
.dst_maxburst = uap->fifosize >> 1,
+ .device_fc = false,
};
struct dma_chan *chan;
dma_cap_mask_t mask;
@@ -304,6 +306,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.direction = DMA_DEV_TO_MEM,
.src_maxburst = uap->fifosize >> 1,
+ .device_fc = false,
};
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
@@ -481,7 +484,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
return -EBUSY;
}
- desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV,
+ desc = dmaengine_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
@@ -664,7 +667,6 @@ static void pl011_dma_rx_callback(void *data);
static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
{
struct dma_chan *rxchan = uap->dmarx.chan;
- struct dma_device *dma_dev;
struct pl011_dmarx_data *dmarx = &uap->dmarx;
struct dma_async_tx_descriptor *desc;
struct pl011_sgbuf *sgbuf;
@@ -675,8 +677,7 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
/* Start the RX DMA job */
sgbuf = uap->dmarx.use_buf_b ?
&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
- dma_dev = rxchan->device;
- desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
+ desc = dmaengine_prep_slave_sg(rxchan, &sgbuf->sg, 1,
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
/*
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 23d791696879..5b07c0c3a10c 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -34,9 +34,9 @@ static char *serial_version = "$Revision: 1.25 $";
#include <asm/irq.h>
#include <asm/dma.h>
-#include <asm/system.h>
#include <arch/svinto.h>
+#include <arch/system.h>
/* non-arch dependent serial structures are in linux/serial.h */
#include <linux/serial.h>
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
index e3699a84049f..6491b8644a7f 100644
--- a/drivers/tty/serial/dz.c
+++ b/drivers/tty/serial/dz.c
@@ -52,7 +52,6 @@
#include <linux/atomic.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/dec/interrupts.h>
#include <asm/dec/kn01.h>
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index d55709a7a75a..defc4e3393a3 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -52,7 +52,6 @@
#include <linux/firmware.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 5e85e1e14c44..fca13dc73e23 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -50,7 +50,6 @@
#include <linux/atomic.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <mach/hardware.h>
#include <mach/dma.h>
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 332f2eb8abbc..e825460478be 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -844,7 +844,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
sg_dma_address(sg) = priv->rx_buf_dma;
- desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
+ desc = dmaengine_prep_slave_sg(priv->chan_rx,
sg, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -1003,7 +1003,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
sg_dma_len(sg) = size;
}
- desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
+ desc = dmaengine_prep_slave_sg(priv->chan_tx,
priv->sg_tx_p, nent, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 9ec6d4e7d9e5..bf461cf99616 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1341,7 +1341,7 @@ static void sci_submit_rx(struct sci_port *s)
struct scatterlist *sg = &s->sg_rx[i];
struct dma_async_tx_descriptor *desc;
- desc = chan->device->device_prep_slave_sg(chan,
+ desc = dmaengine_prep_slave_sg(chan,
sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (desc) {
@@ -1456,7 +1456,7 @@ static void work_fn_tx(struct work_struct *work)
BUG_ON(!sg_dma_len(sg));
- desc = chan->device->device_prep_slave_sg(chan,
+ desc = dmaengine_prep_slave_sg(chan,
sg, s->sg_len_tx, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 3ba5d285c2d0..505961cfd934 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -23,6 +23,7 @@
#include <asm/spitfire.h>
#include <asm/prom.h>
#include <asm/irq.h>
+#include <asm/setup.h>
#if defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 62dacd0ba526..f0d93eb7e6ec 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -37,6 +37,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
+#include <asm/setup.h>
#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index d3ca6da129fe..675303b8ed84 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -41,6 +41,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
+#include <asm/setup.h>
#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index da4415842a43..b3b70b0bf85b 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -37,6 +37,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
+#include <asm/setup.h>
#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index b7455b526080..4001eee6c08d 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -67,7 +67,6 @@
#include <linux/types.h>
#include <linux/atomic.h>
-#include <asm/system.h>
#include <asm/dec/interrupts.h>
#include <asm/dec/ioasic_addrs.h>
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 8e518da85fd5..593d40ad0a6b 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -86,7 +86,6 @@
#include <linux/ioctl.h>
#include <linux/synclink.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 34b1a3c43066..aa1debf97cc7 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -73,7 +73,6 @@
#include <linux/hdlc.h>
#include <linux/synclink.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 4fb6c4b31b79..a3dddc12d2fe 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -58,7 +58,6 @@
#include <linux/delay.h>
#include <linux/ioctl.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index dd8a938510ca..d939bd705c71 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -97,7 +97,6 @@
#include <linux/ratelimit.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 9314d93c1a20..a1b9a2f68567 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -23,7 +23,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#undef TTY_DEBUG_WAIT_UNTIL_SENT
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 84c4a7d5603e..3bdd4b19dd06 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -99,7 +99,6 @@
#include <linux/notifier.h>
#include <linux/device.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include <linux/kdb.h>
#include <linux/ctype.h>
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 48ac6e781ba2..cbd8f5f80596 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -44,7 +44,7 @@ config USB_ARCH_HAS_EHCI
default y if PPC_MPC512x
default y if ARCH_IXP4XX
default y if ARCH_W90X900
- default y if ARCH_AT91SAM9G45
+ default y if ARCH_AT91
default y if ARCH_MXC
default y if ARCH_OMAP3
default y if ARCH_CNS3XXX
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 26c0b75f152e..2633f7595116 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -137,7 +137,7 @@ choice
config USB_AT91
tristate "Atmel AT91 USB Device Port"
- depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91SAM9G45
+ depends on ARCH_AT91
help
Many Atmel AT91 processors (such as the AT91RM2000) have a
full speed USB Device Port with support for five configurable
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 2204a4c68d85..77779271f487 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -54,7 +54,6 @@
#include <linux/prefetch.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
/* gadget stack */
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 2db5f68f7960..0c935d7c65bd 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -29,12 +29,13 @@
#include <linux/clk.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <asm/byteorder.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/gpio.h>
#include <mach/board.h>
@@ -1707,7 +1708,27 @@ static void at91udc_shutdown(struct platform_device *dev)
spin_unlock_irqrestore(&udc->lock, flags);
}
-static int __init at91udc_probe(struct platform_device *pdev)
+static void __devinit at91udc_of_init(struct at91_udc *udc,
+ struct device_node *np)
+{
+ struct at91_udc_data *board = &udc->board;
+ u32 val;
+ enum of_gpio_flags flags;
+
+ if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
+ board->vbus_polled = 1;
+
+ board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
+ &flags);
+ board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+ board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0,
+ &flags);
+
+ board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct at91_udc *udc;
@@ -1742,7 +1763,11 @@ static int __init at91udc_probe(struct platform_device *pdev)
/* init software state */
udc = &controller;
udc->gadget.dev.parent = dev;
- udc->board = *(struct at91_udc_data *) dev->platform_data;
+ if (pdev->dev.of_node)
+ at91udc_of_init(udc, pdev->dev.of_node);
+ else
+ memcpy(&udc->board, dev->platform_data,
+ sizeof(struct at91_udc_data));
udc->pdev = pdev;
udc->enabled = 0;
spin_lock_init(&udc->lock);
@@ -1971,6 +1996,15 @@ static int at91udc_resume(struct platform_device *pdev)
#define at91udc_resume NULL
#endif
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_udc_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-udc" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
+#endif
+
static struct platform_driver at91_udc_driver = {
.remove = __exit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
@@ -1979,6 +2013,7 @@ static struct platform_driver at91_udc_driver = {
.driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_udc_dt_ids),
},
};
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index e1cd56c5e2a8..a6dfd2164166 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -44,7 +44,6 @@
#include <asm/byteorder.h>
#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#define DRIVER_DESC "USB Host+Gadget Emulator"
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index b30e21fdbb1b..5f94e79cd6b9 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -43,7 +43,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/dma.h>
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index e1dfd32dc805..e151d6b87dee 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -43,7 +43,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index edd52d963f14..f9cedd52cf20 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -32,7 +32,6 @@
#include <linux/pm.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include "langwell_udc.h"
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 19bbe80c2f8c..a73cf406e2a4 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -34,7 +34,6 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/platform_data/mv_usb.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include "mv_udc.h"
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index 01ae56f47174..43ac7482fa91 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -42,7 +42,6 @@
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include "net2272.h"
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index a5ccabc37f30..ac335af154ba 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -59,7 +59,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index b44830df593e..3b4b6dd0f95a 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -40,7 +40,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/mach-types.h>
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index d83134b0f78a..4e4dc1f5f388 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -34,7 +34,6 @@
#include <asm/byteorder.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 1b33634f2736..41ed69c96d8c 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -41,7 +41,6 @@
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/gpio.h>
-#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index d3cdffea9c8a..73a934a170d1 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -34,7 +34,6 @@
#include <asm/io.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index ab9c65e2c1d5..195524cde6c3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -37,7 +37,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <mach/irqs.h>
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index a5a3ef1f0096..19f318ababa2 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
/* interface and function clocks */
static struct clk *iclk, *fclk;
@@ -115,6 +116,8 @@ static const struct hc_driver ehci_atmel_hc_driver = {
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
+static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
+
static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -137,6 +140,13 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
goto fail_create_hcd;
}
+ /* Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &at91_ehci_dma_mask;
+
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
@@ -225,9 +235,21 @@ static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ehci_dt_ids[] = {
+ { .compatible = "atmel,at91sam9g45-ehci" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
+#endif
+
static struct platform_driver ehci_atmel_driver = {
.probe = ehci_atmel_drv_probe,
.remove = __devexit_p(ehci_atmel_drv_remove),
.shutdown = usb_hcd_platform_shutdown,
- .driver.name = "atmel-ehci",
+ .driver = {
+ .name = "atmel-ehci",
+ .of_match_table = of_match_ptr(atmel_ehci_dt_ids),
+ },
};
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index aede6374e4b6..057cdda7a489 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -45,7 +45,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#if defined(CONFIG_PPC_PS3)
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 924880087a74..9e65e3091c8a 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -70,7 +70,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include "isp116x.h"
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 9e63cdf1ab75..2ed112d3e159 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -84,7 +84,6 @@
#include <linux/prefetch.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 8e855eb0bf89..db8963f5fbce 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -14,6 +14,8 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
#include <mach/hardware.h>
#include <asm/gpio.h>
@@ -477,13 +479,109 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
+static const struct of_device_id at91_ohci_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-ohci" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids);
+
+static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int i, ret, gpio;
+ enum of_gpio_flags flags;
+ struct at91_usbh_data *pdata;
+ u32 ports;
+
+ if (!np)
+ return 0;
+
+ /* Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &at91_ohci_dma_mask;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (!of_property_read_u32(np, "num-ports", &ports))
+ pdata->ports = ports;
+
+ for (i = 0; i < 2; i++) {
+ gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags);
+ pdata->vbus_pin[i] = gpio;
+ if (!gpio_is_valid(gpio))
+ continue;
+ pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW;
+ ret = gpio_request(gpio, "ohci_vbus");
+ if (ret) {
+ dev_warn(&pdev->dev, "can't request vbus gpio %d", gpio);
+ continue;
+ }
+ ret = gpio_direction_output(gpio, !(flags & OF_GPIO_ACTIVE_LOW) ^ 1);
+ if (ret)
+ dev_warn(&pdev->dev, "can't put vbus gpio %d as output %d",
+ !(flags & OF_GPIO_ACTIVE_LOW) ^ 1, gpio);
+ }
+
+ for (i = 0; i < 2; i++) {
+ gpio = of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags);
+ pdata->overcurrent_pin[i] = gpio;
+ if (!gpio_is_valid(gpio))
+ continue;
+ ret = gpio_request(gpio, "ohci_overcurrent");
+ if (ret) {
+ dev_err(&pdev->dev, "can't request overcurrent gpio %d", gpio);
+ continue;
+ }
+
+ ret = gpio_direction_input(gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "can't configure overcurrent gpio %d as input", gpio);
+ continue;
+ }
+
+ ret = request_irq(gpio_to_irq(gpio),
+ ohci_hcd_at91_overcurrent_irq,
+ IRQF_SHARED, "ohci_overcurrent", pdev);
+ if (ret) {
+ gpio_free(gpio);
+ dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n");
+ }
+ }
+
+ pdev->dev.platform_data = pdata;
+
+ return 0;
+}
+#else
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
/*-------------------------------------------------------------------------*/
static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
{
- struct at91_usbh_data *pdata = pdev->dev.platform_data;
+ struct at91_usbh_data *pdata;
int i;
+ i = ohci_at91_of_init(pdev);
+
+ if (i)
+ return i;
+
+ pdata = pdev->dev.platform_data;
+
if (pdata) {
for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
if (!gpio_is_valid(pdata->vbus_pin[i]))
@@ -596,5 +694,6 @@ static struct platform_driver ohci_hcd_at91_driver = {
.driver = {
.name = "at91_ohci",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_ohci_dt_ids),
},
};
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 543e90e336b8..235171f29460 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -42,7 +42,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 015c7c62ed49..3b38030b02a8 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -40,7 +40,6 @@
#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <linux/irq.h>
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 2a2cce2d2fa7..91ce1c02e617 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -51,7 +51,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 16dd6a6abf00..dbbd1ba25224 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -55,7 +55,6 @@
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
/* FIXME ohci.h is ONLY for internal use by the OHCI driver.
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e37dea87bb56..e4db350602b8 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -45,7 +45,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include "uhci-hcd.h"
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 97cb45916c43..d05c7fbbb703 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -115,12 +115,12 @@ static bool ux500_configure_channel(struct dma_channel *channel,
slave_conf.dst_addr = usb_fifo_addr;
slave_conf.dst_addr_width = addr_width;
slave_conf.dst_maxburst = 16;
+ slave_conf.device_fc = false;
dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG,
(unsigned long) &slave_conf);
- dma_desc = dma_chan->device->
- device_prep_slave_sg(dma_chan, &sg, 1, direction,
+ dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!dma_desc)
return false;
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 3648c82a17fe..6ec7f838d7fa 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -786,9 +786,8 @@ static void xfer_work(struct work_struct *work)
sg_dma_address(&sg) = pkt->dma + pkt->actual;
sg_dma_len(&sg) = pkt->trans;
- desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir,
- DMA_PREP_INTERRUPT |
- DMA_CTRL_ACK);
+ desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
return;
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index f23cae094f1b..887df9d81422 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -53,7 +53,6 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index 915943af3f21..f49181c73113 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -67,6 +67,28 @@ static inline int wled_idc(int port)
return ret;
}
+static int backlight_power_set(struct pm860x_chip *chip, int port,
+ int on)
+{
+ int ret = -EINVAL;
+
+ switch (port) {
+ case PM8606_BACKLIGHT1:
+ ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) :
+ pm8606_osc_disable(chip, WLED1_DUTY);
+ break;
+ case PM8606_BACKLIGHT2:
+ ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) :
+ pm8606_osc_disable(chip, WLED2_DUTY);
+ break;
+ case PM8606_BACKLIGHT3:
+ ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) :
+ pm8606_osc_disable(chip, WLED3_DUTY);
+ break;
+ }
+ return ret;
+}
+
static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
{
struct pm860x_backlight_data *data = bl_get_data(bl);
@@ -79,6 +101,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
else
value = brightness;
+ if (brightness)
+ backlight_power_set(chip, data->port, 1);
+
ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
if (ret < 0)
goto out;
@@ -115,6 +140,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
if (ret < 0)
goto out;
+ if (brightness == 0)
+ backlight_power_set(chip, data->port, 0);
+
dev_dbg(chip->dev, "set brightness %d\n", value);
data->current_brightness = value;
return 0;
@@ -170,7 +198,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
struct backlight_device *bl;
struct resource *res;
struct backlight_properties props;
- unsigned char value;
char name[MFD_NAME_SIZE];
int ret;
@@ -217,26 +244,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bl);
- /* Enable reference VSYS */
- ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
- if (ret < 0)
- goto out;
- if ((ret & PM8606_VSYS_EN) == 0) {
- value = ret | PM8606_VSYS_EN;
- ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
- if (ret < 0)
- goto out;
- }
- /* Enable reference OSC */
- ret = pm860x_reg_read(data->i2c, PM8606_MISC);
- if (ret < 0)
- goto out;
- if ((ret & PM8606_MISC_OSC_EN) == 0) {
- value = ret | PM8606_MISC_OSC_EN;
- ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
- if (ret < 0)
- goto out;
- }
/* read current backlight */
ret = pm860x_backlight_get_brightness(bl);
if (ret < 0)
diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c
index be98d152b7fd..a523b255e124 100644
--- a/drivers/video/backlight/apple_bl.c
+++ b/drivers/video/backlight/apple_bl.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/acpi.h>
+#include <linux/atomic.h>
static struct backlight_device *apple_backlight_device;
@@ -221,14 +222,32 @@ static struct acpi_driver apple_bl_driver = {
},
};
+static atomic_t apple_bl_registered = ATOMIC_INIT(0);
+
+int apple_bl_register(void)
+{
+ if (atomic_xchg(&apple_bl_registered, 1) == 0)
+ return acpi_bus_register_driver(&apple_bl_driver);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(apple_bl_register);
+
+void apple_bl_unregister(void)
+{
+ if (atomic_xchg(&apple_bl_registered, 0) == 1)
+ acpi_bus_unregister_driver(&apple_bl_driver);
+}
+EXPORT_SYMBOL_GPL(apple_bl_unregister);
+
static int __init apple_bl_init(void)
{
- return acpi_bus_register_driver(&apple_bl_driver);
+ return apple_bl_register();
}
static void __exit apple_bl_exit(void)
{
- acpi_bus_unregister_driver(&apple_bl_driver);
+ apple_bl_unregister();
}
module_init(apple_bl_init);
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index a2161f631a83..2231aec23918 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -271,7 +271,7 @@ static int tosa_lcd_resume(struct spi_device *spi)
}
#else
#define tosa_lcd_suspend NULL
-#define tosa_lcd_reume NULL
+#define tosa_lcd_resume NULL
#endif
static struct spi_driver tosa_lcd_driver = {
diff --git a/drivers/video/bt431.h b/drivers/video/bt431.h
index c826f2787bad..04e0cfbba538 100644
--- a/drivers/video/bt431.h
+++ b/drivers/video/bt431.h
@@ -8,7 +8,6 @@
* archive for more details.
*/
#include <linux/types.h>
-#include <asm/system.h>
/*
* Bt431 cursor generator registers, 32-bit aligned.
diff --git a/drivers/video/bt455.h b/drivers/video/bt455.h
index b7591fea7add..80f61b03e9ae 100644
--- a/drivers/video/bt455.h
+++ b/drivers/video/bt455.h
@@ -8,7 +8,6 @@
* archive for more details.
*/
#include <linux/types.h>
-#include <asm/system.h>
/*
* Bt455 byte-wide registers, 32-bit aligned.
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 8745637e4b7e..2e471c22abf5 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -77,7 +77,6 @@
#include <linux/crc32.h> /* For counting font checksums */
#include <asm/fb.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include "fbcon.h"
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index a122d9287d16..6d1596629040 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -22,7 +22,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/gio_device.h>
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 850380795b05..c1527f5b47ee 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -51,7 +51,6 @@
#include <linux/i2c-algo-bit.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#ifdef __arm__
#include <asm/mach-types.h>
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index ec56d2544c73..49e3dda1a361 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -7,7 +7,6 @@
#include <linux/platform_device.h>
#include <asm/setup.h>
-#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 727a5149d818..eec0d7b748eb 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -337,7 +337,7 @@ static void sdc_enable_channel(struct mx3fb_info *mx3_fbi)
/* This enables the channel */
if (mx3_fbi->cookie < 0) {
- mx3_fbi->txd = dma_chan->device->device_prep_slave_sg(dma_chan,
+ mx3_fbi->txd = dmaengine_prep_slave_sg(dma_chan,
&mx3_fbi->sg[0], 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!mx3_fbi->txd) {
dev_err(mx3fb->dev, "Cannot allocate descriptor on %d\n",
@@ -1091,7 +1091,7 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,
if (mx3_fbi->txd)
async_tx_ack(mx3_fbi->txd);
- txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg +
+ txd = dmaengine_prep_slave_sg(dma_chan, sg +
mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!txd) {
dev_err(fbi->device,
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index fb3f67391105..afc9521173ef 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -71,7 +71,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
index fd2271600370..4e5b960c32c8 100644
--- a/drivers/video/omap2/vrfb.c
+++ b/drivers/video/omap2/vrfb.c
@@ -27,7 +27,6 @@
#include <linux/bitops.h>
#include <linux/mutex.h>
-#include <mach/io.h>
#include <plat/vrfb.h>
#include <plat/sdrc.h>
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index 0c69fa20251b..9b4a60b52a4c 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -33,7 +33,6 @@
#include <linux/types.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <video/pmag-ba-fb.h>
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index 22fcb9a3d5c0..4e7a9c46e112 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -29,7 +29,6 @@
#include <linux/types.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <video/pmagb-b-fb.h>
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index f5a39f5aa900..a104e8cd2f54 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -20,7 +20,6 @@
#include <asm/uaccess.h>
#include <asm/setup.h>
-#include <asm/system.h>
#include <asm/q40_master.h>
#include <linux/fb.h>
#include <linux/module.h>
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index beb495044b24..cee7803a0a1c 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -56,7 +56,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
diff --git a/drivers/virtio/config.c b/drivers/virtio/config.c
index 983d482fba40..f70bcd2ff98f 100644
--- a/drivers/virtio/config.c
+++ b/drivers/virtio/config.c
@@ -9,5 +9,4 @@
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/bug.h>
-#include <asm/system.h>
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 0e7366dfc901..37096246c937 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -55,6 +55,7 @@ comment "Watchdog Device Drivers"
config SOFT_WATCHDOG
tristate "Software watchdog"
+ select WATCHDOG_CORE
help
A software monitoring watchdog. This will fail to reboot your system
from some situations that the hardware watchdog will recover
@@ -74,6 +75,7 @@ config WM831X_WATCHDOG
config WM8350_WATCHDOG
tristate "WM8350 watchdog"
depends on MFD_WM8350
+ select WATCHDOG_CORE
help
Support for the watchdog in the WM8350 AudioPlus PMIC. When
the watchdog triggers the system will be reset.
@@ -217,6 +219,7 @@ config MPCORE_WATCHDOG
config EP93XX_WATCHDOG
tristate "EP93xx Watchdog"
depends on ARCH_EP93XX
+ select WATCHDOG_CORE
help
Say Y here if to include support for the watchdog timer
embedded in the Cirrus Logic EP93xx family of devices.
@@ -234,6 +237,7 @@ config OMAP_WATCHDOG
config PNX4008_WATCHDOG
tristate "PNX4008 and LPC32XX Watchdog"
depends on ARCH_PNX4008 || ARCH_LPC32XX
+ select WATCHDOG_CORE
help
Say Y here if to include support for the watchdog timer
in the PNX4008 or LPC32XX processor.
@@ -283,6 +287,7 @@ config COH901327_WATCHDOG
bool "ST-Ericsson COH 901 327 watchdog"
depends on ARCH_U300
default y if MACH_U300
+ select WATCHDOG_CORE
help
Say Y here to include Watchdog timer support for the
watchdog embedded into the ST-Ericsson U300 series platforms.
@@ -328,6 +333,7 @@ config TS72XX_WATCHDOG
config MAX63XX_WATCHDOG
tristate "Max63xx watchdog"
depends on ARM && HAS_IOMEM
+ select WATCHDOG_CORE
help
Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
@@ -955,6 +961,7 @@ config INDYDOG
config JZ4740_WDT
tristate "Ingenic jz4740 SoC hardware watchdog"
depends on MACH_JZ4740
+ select WATCHDOG_CORE
help
Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs.
@@ -996,6 +1003,7 @@ config AR7_WDT
config TXX9_WDT
tristate "Toshiba TXx9 Watchdog Timer"
depends on CPU_TX39XX || CPU_TX49XX
+ select WATCHDOG_CORE
help
Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c
index b6a2b58cbe64..4397881c83f4 100644
--- a/drivers/watchdog/acquirewdt.c
+++ b/drivers/watchdog/acquirewdt.c
@@ -52,6 +52,8 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
/* Includes */
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
@@ -70,7 +72,6 @@
/* Module information */
#define DRV_NAME "acquirewdt"
-#define PFX DRV_NAME ": "
#define WATCHDOG_NAME "Acquire WDT"
/* There is no way to see what the correct time-out period is */
#define WATCHDOG_HEARTBEAT 0
@@ -92,8 +93,8 @@ static int wdt_start = 0x443;
module_param(wdt_start, int, 0);
MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -208,8 +209,7 @@ static int acq_close(struct inode *inode, struct file *file)
if (expect_close == 42) {
acq_stop();
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
acq_keepalive();
}
clear_bit(0, &acq_is_open);
@@ -246,27 +246,24 @@ static int __devinit acq_probe(struct platform_device *dev)
if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX
- "I/O address 0x%04x already in use\n", wdt_stop);
+ pr_err("I/O address 0x%04x already in use\n", wdt_stop);
ret = -EIO;
goto out;
}
}
if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- wdt_start);
+ pr_err("I/O address 0x%04x already in use\n", wdt_start);
ret = -EIO;
goto unreg_stop;
}
ret = misc_register(&acq_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_regions;
}
- printk(KERN_INFO PFX "initialized. (nowayout=%d)\n", nowayout);
+ pr_info("initialized. (nowayout=%d)\n", nowayout);
return 0;
unreg_regions:
@@ -308,8 +305,7 @@ static int __init acq_init(void)
{
int err;
- printk(KERN_INFO
- "WDT driver for Acquire single board computer initialising.\n");
+ pr_info("WDT driver for Acquire single board computer initialising\n");
err = platform_driver_register(&acquirewdt_driver);
if (err)
@@ -332,7 +328,7 @@ static void __exit acq_exit(void)
{
platform_device_unregister(acq_platform_device);
platform_driver_unregister(&acquirewdt_driver);
- printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+ pr_info("Watchdog Module Unloaded\n");
}
module_init(acq_init);
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c
index 4d40965d2c9f..64ae9e9fed94 100644
--- a/drivers/watchdog/advantechwdt.c
+++ b/drivers/watchdog/advantechwdt.c
@@ -28,6 +28,8 @@
* add wdt_start and wdt_stop as parameters.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -40,10 +42,8 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define DRV_NAME "advantechwdt"
-#define PFX DRV_NAME ": "
#define WATCHDOG_NAME "Advantech WDT"
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
@@ -77,8 +77,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=63, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -207,8 +207,7 @@ static int advwdt_close(struct inode *inode, struct file *file)
if (adv_expect_close == 42) {
advwdt_disable();
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
advwdt_ping();
}
clear_bit(0, &advwdt_is_open);
@@ -245,18 +244,15 @@ static int __devinit advwdt_probe(struct platform_device *dev)
if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX
- "I/O address 0x%04x already in use\n",
- wdt_stop);
+ pr_err("I/O address 0x%04x already in use\n",
+ wdt_stop);
ret = -EIO;
goto out;
}
}
if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX
- "I/O address 0x%04x already in use\n",
- wdt_start);
+ pr_err("I/O address 0x%04x already in use\n", wdt_start);
ret = -EIO;
goto unreg_stop;
}
@@ -265,18 +261,16 @@ static int __devinit advwdt_probe(struct platform_device *dev)
* if not reset to the default */
if (advwdt_set_heartbeat(timeout)) {
advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 1<=x<=63, using %d\n", timeout);
+ pr_info("timeout value must be 1<=x<=63, using %d\n", timeout);
}
ret = misc_register(&advwdt_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_regions;
}
- printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+ pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
out:
return ret;
@@ -318,8 +312,7 @@ static int __init advwdt_init(void)
{
int err;
- printk(KERN_INFO
- "WDT driver for Advantech single board computer initialising.\n");
+ pr_info("WDT driver for Advantech single board computer initialising\n");
err = platform_driver_register(&advwdt_driver);
if (err)
@@ -343,7 +336,7 @@ static void __exit advwdt_exit(void)
{
platform_device_unregister(advwdt_platform_device);
platform_driver_unregister(&advwdt_driver);
- printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+ pr_info("Watchdog Module Unloaded\n");
}
module_init(advwdt_init);
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index f16dcbd475fb..41b84936a521 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -7,6 +7,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -22,7 +24,6 @@
#include <linux/io.h>
#define WATCHDOG_NAME "ALi_M1535"
-#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
/* internal variables */
@@ -39,8 +40,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (0 < timeout < 18000, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -268,8 +269,7 @@ static int ali_release(struct inode *inode, struct file *file)
if (ali_expect_release == 42)
ali_stop();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
ali_keepalive();
}
clear_bit(0, &ali_is_open);
@@ -399,9 +399,8 @@ static int __init watchdog_init(void)
if not reset to the default */
if (timeout < 1 || timeout >= 18000) {
timeout = WATCHDOG_TIMEOUT;
- printk(KERN_INFO PFX
- "timeout value must be 0 < timeout < 18000, using %d\n",
- timeout);
+ pr_info("timeout value must be 0 < timeout < 18000, using %d\n",
+ timeout);
}
/* Calculate the watchdog's timeout */
@@ -409,20 +408,18 @@ static int __init watchdog_init(void)
ret = register_reboot_notifier(&ali_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto out;
}
ret = misc_register(&ali_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_reboot;
}
- printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+ pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
out:
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 46f4b85b46de..5eee55012e33 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -19,6 +19,8 @@
* -- Mike Waychison <michael.waychison@sun.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -34,10 +36,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#define OUR_NAME "alim7101_wdt"
-#define PFX OUR_NAME ": "
#define WDT_ENABLE 0x9C
#define WDT_DISABLE 0x8C
@@ -79,8 +77,8 @@ static unsigned long wdt_is_open;
static char wdt_expect_close;
static struct pci_dev *alim7101_pmu;
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -112,8 +110,7 @@ static void wdt_timer_ping(unsigned long data)
ALI_7101_GPIO_O, tmp & ~0x20);
}
} else {
- printk(KERN_WARNING PFX
- "Heartbeat lost! Will not ping the watchdog\n");
+ pr_warn("Heartbeat lost! Will not ping the watchdog\n");
}
/* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL);
@@ -162,7 +159,7 @@ static void wdt_startup(void)
/* Start the timer */
mod_timer(&timer, jiffies + WDT_INTERVAL);
- printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+ pr_info("Watchdog timer is now enabled\n");
}
static void wdt_turnoff(void)
@@ -170,7 +167,7 @@ static void wdt_turnoff(void)
/* Stop the timer */
del_timer_sync(&timer);
wdt_change(WDT_DISABLE);
- printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+ pr_info("Watchdog timer is now disabled...\n");
}
static void wdt_keepalive(void)
@@ -226,8 +223,7 @@ static int fop_close(struct inode *inode, struct file *file)
wdt_turnoff();
else {
/* wim: shouldn't there be a: del_timer(&timer); */
- printk(KERN_CRIT PFX
- "device file closed unexpectedly. Will not stop the WDT!\n");
+ pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
}
clear_bit(0, &wdt_is_open);
wdt_expect_close = 0;
@@ -322,8 +318,7 @@ static int wdt_notify_sys(struct notifier_block *this,
* watchdog on reboot with no heartbeat
*/
wdt_change(WDT_ENABLE);
- printk(KERN_INFO PFX "Watchdog timer is now enabled "
- "with no heartbeat - should reboot in ~1 second.\n");
+ pr_info("Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second\n");
}
return NOTIFY_DONE;
}
@@ -352,12 +347,11 @@ static int __init alim7101_wdt_init(void)
struct pci_dev *ali1543_south;
char tmp;
- printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
+ pr_info("Steve Hill <steve@navaho.co.uk>\n");
alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
NULL);
if (!alim7101_pmu) {
- printk(KERN_INFO PFX
- "ALi M7101 PMU not present - WDT not set\n");
+ pr_info("ALi M7101 PMU not present - WDT not set\n");
return -EBUSY;
}
@@ -367,56 +361,46 @@ static int __init alim7101_wdt_init(void)
ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
NULL);
if (!ali1543_south) {
- printk(KERN_INFO PFX
- "ALi 1543 South-Bridge not present - WDT not set\n");
+ pr_info("ALi 1543 South-Bridge not present - WDT not set\n");
goto err_out;
}
pci_read_config_byte(ali1543_south, 0x5e, &tmp);
pci_dev_put(ali1543_south);
if ((tmp & 0x1e) == 0x00) {
if (!use_gpio) {
- printk(KERN_INFO PFX
- "Detected old alim7101 revision 'a1d'. "
- "If this is a cobalt board, set the 'use_gpio' "
- "module parameter.\n");
+ pr_info("Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
goto err_out;
}
nowayout = 1;
} else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
- printk(KERN_INFO PFX
- "ALi 1543 South-Bridge does not have the correct "
- "revision number (???1001?) - WDT not set\n");
+ pr_info("ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
goto err_out;
}
if (timeout < 1 || timeout > 3600) {
/* arbitrary upper limit */
timeout = WATCHDOG_TIMEOUT;
- printk(KERN_INFO PFX
- "timeout value must be 1 <= x <= 3600, using %d\n",
- timeout);
+ pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+ timeout);
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("cannot register reboot notifier (err=%d)\n", rc);
goto err_out;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
goto err_out_reboot;
}
if (nowayout)
__module_get(THIS_MODULE);
- printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. "
- "timeout=%d sec (nowayout=%d)\n",
+ pr_info("WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0;
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 502773ad5acd..639ae9a23fbc 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -23,6 +23,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
@@ -39,7 +41,6 @@
#include <asm/addrspace.h>
#include <asm/mach-ar7/ar7.h>
-#define DRVNAME "ar7_wdt"
#define LONGNAME "TI AR7 Watchdog Timer"
MODULE_AUTHOR("Nicolas Thill <nico@openwrt.org>");
@@ -51,8 +52,8 @@ static int margin = 60;
module_param(margin, int, 0);
MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
#define READ_REG(x) readl((void __iomem *)&(x))
@@ -93,7 +94,7 @@ static void ar7_wdt_kick(u32 value)
return;
}
}
- printk(KERN_ERR DRVNAME ": failed to unlock WDT kick reg\n");
+ pr_err("failed to unlock WDT kick reg\n");
}
static void ar7_wdt_prescale(u32 value)
@@ -106,7 +107,7 @@ static void ar7_wdt_prescale(u32 value)
return;
}
}
- printk(KERN_ERR DRVNAME ": failed to unlock WDT prescale reg\n");
+ pr_err("failed to unlock WDT prescale reg\n");
}
static void ar7_wdt_change(u32 value)
@@ -119,7 +120,7 @@ static void ar7_wdt_change(u32 value)
return;
}
}
- printk(KERN_ERR DRVNAME ": failed to unlock WDT change reg\n");
+ pr_err("failed to unlock WDT change reg\n");
}
static void ar7_wdt_disable(u32 value)
@@ -135,7 +136,7 @@ static void ar7_wdt_disable(u32 value)
}
}
}
- printk(KERN_ERR DRVNAME ": failed to unlock WDT disable reg\n");
+ pr_err("failed to unlock WDT disable reg\n");
}
static void ar7_wdt_update_margin(int new_margin)
@@ -151,21 +152,20 @@ static void ar7_wdt_update_margin(int new_margin)
change = 0xffff;
ar7_wdt_change(change);
margin = change * prescale_value / vbus_rate;
- printk(KERN_INFO DRVNAME
- ": timer margin %d seconds (prescale %d, change %d, freq %d)\n",
- margin, prescale_value, change, vbus_rate);
+ pr_info("timer margin %d seconds (prescale %d, change %d, freq %d)\n",
+ margin, prescale_value, change, vbus_rate);
}
static void ar7_wdt_enable_wdt(void)
{
- printk(KERN_DEBUG DRVNAME ": enabling watchdog timer\n");
+ pr_debug("enabling watchdog timer\n");
ar7_wdt_disable(1);
ar7_wdt_kick(1);
}
static void ar7_wdt_disable_wdt(void)
{
- printk(KERN_DEBUG DRVNAME ": disabling watchdog timer\n");
+ pr_debug("disabling watchdog timer\n");
ar7_wdt_disable(0);
}
@@ -183,9 +183,7 @@ static int ar7_wdt_open(struct inode *inode, struct file *file)
static int ar7_wdt_release(struct inode *inode, struct file *file)
{
if (!expect_close)
- printk(KERN_WARNING DRVNAME
- ": watchdog device closed unexpectedly,"
- "will not disable the watchdog timer\n");
+ pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
else if (!nowayout)
ar7_wdt_disable_wdt();
clear_bit(0, &wdt_is_open);
@@ -283,28 +281,28 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
ar7_regs_wdt =
platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
if (!ar7_regs_wdt) {
- printk(KERN_ERR DRVNAME ": could not get registers resource\n");
+ pr_err("could not get registers resource\n");
rc = -ENODEV;
goto out;
}
if (!request_mem_region(ar7_regs_wdt->start,
resource_size(ar7_regs_wdt), LONGNAME)) {
- printk(KERN_WARNING DRVNAME ": watchdog I/O region busy\n");
+ pr_warn("watchdog I/O region busy\n");
rc = -EBUSY;
goto out;
}
ar7_wdt = ioremap(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
if (!ar7_wdt) {
- printk(KERN_ERR DRVNAME ": could not ioremap registers\n");
+ pr_err("could not ioremap registers\n");
rc = -ENXIO;
goto out_mem_region;
}
vbus_clk = clk_get(NULL, "vbus");
if (IS_ERR(vbus_clk)) {
- printk(KERN_ERR DRVNAME ": could not get vbus clock\n");
+ pr_err("could not get vbus clock\n");
rc = PTR_ERR(vbus_clk);
goto out_mem_region;
}
@@ -315,7 +313,7 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
rc = misc_register(&ar7_wdt_miscdev);
if (rc) {
- printk(KERN_ERR DRVNAME ": unable to register misc device\n");
+ pr_err("unable to register misc device\n");
goto out_alloc;
}
goto out;
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index 4ca5d40304b2..2896430ce42c 100644
--- a/drivers/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -45,8 +45,8 @@ MODULE_PARM_DESC(timeout,
"Timeout value. Limited to be 1 or 2 seconds. (default="
__MODULE_STRING(TIMEOUT_DEFAULT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
index 7ceefd29ae14..7ef99a169e3b 100644
--- a/drivers/watchdog/at91rm9200_wdt.c
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -9,6 +9,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -28,14 +30,14 @@
#define WDT_MAX_TIME 256 /* seconds */
static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
__MODULE_STRING(WDT_DEFAULT_TIME) ")");
#ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -209,8 +211,8 @@ static int __devinit at91wdt_probe(struct platform_device *pdev)
if (res)
return res;
- printk(KERN_INFO "AT91 Watchdog Timer enabled (%d seconds%s)\n",
- wdt_time, nowayout ? ", nowayout" : "");
+ pr_info("AT91 Watchdog Timer enabled (%d seconds%s)\n",
+ wdt_time, nowayout ? ", nowayout" : "");
return 0;
}
@@ -268,8 +270,8 @@ static int __init at91_wdt_init(void)
if not reset to the default */
if (at91_wdt_settimeout(wdt_time)) {
at91_wdt_settimeout(WDT_DEFAULT_TIME);
- pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256"
- ", using %d\n", wdt_time);
+ pr_info("wdt_time value must be 1 <= wdt_time <= 256, using %d\n",
+ wdt_time);
}
return platform_driver_register(&at91wdt_driver);
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 00562566ef5f..05e1be85fdee 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -15,6 +15,8 @@
* bootloader doesn't write to this register.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -60,8 +62,8 @@ module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -96,7 +98,7 @@ static void at91_ping(unsigned long data)
at91_wdt_reset();
mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
} else
- printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+ pr_crit("I will reset your machine !\n");
}
/*
@@ -140,7 +142,7 @@ static int at91_wdt_settimeout(unsigned int timeout)
/* Check if disabled */
mr = wdt_read(AT91_WDT_MR);
if (mr & AT91_WDT_WDDIS) {
- printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+ pr_err("sorry, watchdog is disabled\n");
return -EIO;
}
@@ -283,7 +285,7 @@ static int __init at91wdt_probe(struct platform_device *pdev)
setup_timer(&at91wdt_private.timer, at91_ping, 0);
mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
- printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+ pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n",
heartbeat, nowayout);
return 0;
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 9db808349f8b..1f9371f49c40 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -17,6 +17,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -45,8 +47,8 @@
#define WDOG_CTRL_ACTION_NMI 2 /* NMI */
#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -114,8 +116,7 @@ static int ath79_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags))
ath79_wdt_disable();
else {
- pr_crit(DRIVER_NAME ": device closed unexpectedly, "
- "watchdog timer will not stop!\n");
+ pr_crit("device closed unexpectedly, watchdog timer will not stop!\n");
ath79_wdt_keepalive();
}
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 5c5f4b14fd05..bc0e91e78e86 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -10,6 +10,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -33,14 +35,14 @@
#define WDT_MAX_TIME 255 /* seconds */
static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
__MODULE_STRING(WDT_DEFAULT_TIME) ")");
#ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -91,7 +93,7 @@ static void bcm47xx_timer_tick(unsigned long unused)
bcm47xx_wdt_hw_start();
mod_timer(&wdt_timer, jiffies + HZ);
} else {
- printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n");
+ pr_crit("Watchdog will fire soon!!!\n");
}
}
@@ -140,8 +142,7 @@ static int bcm47xx_wdt_release(struct inode *inode, struct file *file)
if (expect_release == 42) {
bcm47xx_wdt_stop();
} else {
- printk(KERN_CRIT DRV_NAME
- ": Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
bcm47xx_wdt_start();
}
@@ -270,8 +271,7 @@ static int __init bcm47xx_wdt_init(void)
if (bcm47xx_wdt_settimeout(wdt_time)) {
bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
- printk(KERN_INFO DRV_NAME ": "
- "wdt_time value must be 0 < wdt_time < %d, using %d\n",
+ pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n",
(WDT_MAX_TIME + 1), wdt_time);
}
@@ -285,8 +285,8 @@ static int __init bcm47xx_wdt_init(void)
return ret;
}
- printk(KERN_INFO "BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
- wdt_time, nowayout ? ", nowayout" : "");
+ pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
+ wdt_time, nowayout ? ", nowayout" : "");
return 0;
}
diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c
index 8dc7de641e26..8379dc32fd90 100644
--- a/drivers/watchdog/bcm63xx_wdt.c
+++ b/drivers/watchdog/bcm63xx_wdt.c
@@ -10,6 +10,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -50,8 +52,8 @@ static struct {
static int expect_close;
static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -82,7 +84,7 @@ static void bcm63xx_timer_tick(unsigned long unused)
bcm63xx_wdt_hw_start();
mod_timer(&bcm63xx_wdt_device.timer, jiffies + HZ);
} else
- printk(KERN_CRIT PFX ": watchdog will restart system\n");
+ pr_crit("watchdog will restart system\n");
}
static void bcm63xx_wdt_pet(void)
@@ -126,8 +128,7 @@ static int bcm63xx_wdt_release(struct inode *inode, struct file *file)
if (expect_close == 42)
bcm63xx_wdt_pause();
else {
- printk(KERN_CRIT PFX
- ": Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
bcm63xx_wdt_start();
}
clear_bit(0, &bcm63xx_wdt_device.inuse);
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index b9fa9b71583a..38bc383e0677 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -11,6 +11,8 @@
* Licensed under the GPL-2 or later.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -28,15 +30,8 @@
#define stamp(fmt, args...) \
pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am")
-#define pr_devinit(fmt, args...) \
- ({ static const __devinitconst char __fmt[] = fmt; \
- printk(__fmt, ## args); })
-#define pr_init(fmt, args...) \
- ({ static const __initconst char __fmt[] = fmt; \
- printk(__fmt, ## args); })
#define WATCHDOG_NAME "bfin-wdt"
-#define PFX WATCHDOG_NAME ": "
/* The BF561 has two watchdogs (one per core), but since Linux
* only runs on core A, we'll just work with that one.
@@ -54,7 +49,7 @@
#define WATCHDOG_TIMEOUT 20
static unsigned int timeout = WATCHDOG_TIMEOUT;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static const struct watchdog_info bfin_wdt_info;
static unsigned long open_check;
static char expect_close;
@@ -126,7 +121,7 @@ static int bfin_wdt_set_timeout(unsigned long t)
stamp("maxtimeout=%us newtimeout=%lus (cnt=%#x)", max_t, t, cnt);
if (t > max_t) {
- printk(KERN_WARNING PFX "timeout value is too large\n");
+ pr_warn("timeout value is too large\n");
return -EINVAL;
}
@@ -182,8 +177,7 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
if (expect_close == 42)
bfin_wdt_stop();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
bfin_wdt_keepalive();
}
expect_close = 0;
@@ -368,14 +362,13 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
ret = misc_register(&bfin_wdt_miscdev);
if (ret) {
- pr_devinit(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
return ret;
}
- pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
- timeout, nowayout);
+ pr_info("initialized: timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
return 0;
}
@@ -439,14 +432,14 @@ static int __init bfin_wdt_init(void)
*/
ret = platform_driver_register(&bfin_wdt_driver);
if (ret) {
- pr_init(KERN_ERR PFX "unable to register driver\n");
+ pr_err("unable to register driver\n");
return ret;
}
bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME,
-1, NULL, 0);
if (IS_ERR(bfin_wdt_device)) {
- pr_init(KERN_ERR PFX "unable to register device\n");
+ pr_err("unable to register device\n");
platform_driver_unregister(&bfin_wdt_driver);
return PTR_ERR(bfin_wdt_device);
}
@@ -479,7 +472,7 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 7c0fdfca2646..ce0ab4415eff 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -12,6 +12,8 @@
* option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/smp.h>
@@ -21,7 +23,6 @@
#include <linux/uaccess.h>
#include <asm/reg_booke.h>
-#include <asm/system.h>
#include <asm/time.h>
#include <asm/div64.h>
@@ -225,8 +226,8 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1;
on_each_cpu(__booke_wdt_enable, NULL, 0);
- pr_debug("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
- period_to_sec(booke_wdt_period));
+ pr_debug("watchdog enabled (timeout = %llu sec)\n",
+ period_to_sec(booke_wdt_period));
}
spin_unlock(&booke_wdt_lock);
@@ -243,7 +244,7 @@ static int booke_wdt_release(struct inode *inode, struct file *file)
*/
on_each_cpu(__booke_wdt_disable, NULL, 0);
booke_wdt_enabled = 0;
- pr_debug("booke_wdt: watchdog disabled\n");
+ pr_debug("watchdog disabled\n");
#endif
clear_bit(0, &wdt_is_active);
@@ -275,19 +276,19 @@ static int __init booke_wdt_init(void)
{
int ret = 0;
- pr_info("booke_wdt: powerpc book-e watchdog driver loaded\n");
+ pr_info("powerpc book-e watchdog driver loaded\n");
ident.firmware_version = cur_cpu_spec->pvr_value;
ret = misc_register(&booke_wdt_miscdev);
if (ret) {
- pr_err("booke_wdt: cannot register device (minor=%u, ret=%i)\n",
+ pr_err("cannot register device (minor=%u, ret=%i)\n",
WATCHDOG_MINOR, ret);
return ret;
}
spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) {
- pr_info("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
+ pr_info("watchdog enabled (timeout = %llu sec)\n",
period_to_sec(booke_wdt_period));
on_each_cpu(__booke_wdt_enable, NULL, 0);
}
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index 5b89f7d6cd0f..6876430a9f5e 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -8,17 +8,15 @@
*/
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/bitops.h>
-#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/err.h>
#define DRV_NAME "WDOG COH 901 327"
@@ -69,13 +67,11 @@
#define U300_WDOG_IFR_WILL_BARK_IRQ_FORCE_ENABLE 0x0001U
/* Default timeout in seconds = 1 minute */
-static int margin = 60;
+static unsigned int margin = 60;
static resource_size_t phybase;
static resource_size_t physize;
static int irq;
static void __iomem *virtbase;
-static unsigned long coh901327_users;
-static unsigned long boot_status;
static struct device *parent;
/*
@@ -155,34 +151,35 @@ static void coh901327_disable(void)
__func__, val);
}
-static void coh901327_start(void)
+static int coh901327_start(struct watchdog_device *wdt_dev)
{
- coh901327_enable(margin * 100);
+ coh901327_enable(wdt_dev->timeout * 100);
+ return 0;
+}
+
+static int coh901327_stop(struct watchdog_device *wdt_dev)
+{
+ coh901327_disable();
+ return 0;
}
-static void coh901327_keepalive(void)
+static int coh901327_ping(struct watchdog_device *wdd)
{
clk_enable(clk);
/* Feed the watchdog */
writew(U300_WDOG_FR_FEED_RESTART_TIMER,
virtbase + U300_WDOG_FR);
clk_disable(clk);
+ return 0;
}
-static int coh901327_settimeout(int time)
+static int coh901327_settimeout(struct watchdog_device *wdt_dev,
+ unsigned int time)
{
- /*
- * Max margin is 327 since the 10ms
- * timeout register is max
- * 0x7FFF = 327670ms ~= 327s.
- */
- if (time <= 0 || time > 327)
- return -EINVAL;
-
- margin = time;
+ wdt_dev->timeout = time;
clk_enable(clk);
/* Set new timeout value */
- writew(margin * 100, virtbase + U300_WDOG_TR);
+ writew(time * 100, virtbase + U300_WDOG_TR);
/* Feed the dog */
writew(U300_WDOG_FR_FEED_RESTART_TIMER,
virtbase + U300_WDOG_FR);
@@ -190,6 +187,23 @@ static int coh901327_settimeout(int time)
return 0;
}
+static unsigned int coh901327_gettimeleft(struct watchdog_device *wdt_dev)
+{
+ u16 val;
+
+ clk_enable(clk);
+ /* Read repeatedly until the value is stable! */
+ val = readw(virtbase + U300_WDOG_CR);
+ while (val & U300_WDOG_CR_VALID_IND)
+ val = readw(virtbase + U300_WDOG_CR);
+ val &= U300_WDOG_CR_COUNT_VALUE_MASK;
+ clk_disable(clk);
+ if (val != 0)
+ val /= 100;
+
+ return val;
+}
+
/*
* This interrupt occurs 10 ms before the watchdog WILL bark.
*/
@@ -218,130 +232,35 @@ static irqreturn_t coh901327_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-/*
- * Allow only one user (daemon) to open the watchdog
- */
-static int coh901327_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(1, &coh901327_users))
- return -EBUSY;
- coh901327_start();
- return nonseekable_open(inode, file);
-}
-
-static int coh901327_release(struct inode *inode, struct file *file)
-{
- clear_bit(1, &coh901327_users);
- coh901327_disable();
- return 0;
-}
-
-static ssize_t coh901327_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
-{
- if (len)
- coh901327_keepalive();
- return len;
-}
-
-static long coh901327_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret = -ENOTTY;
- u16 val;
- int time;
- int new_options;
- union {
- struct watchdog_info __user *ident;
- int __user *i;
- } uarg;
- static const struct watchdog_info ident = {
- .options = WDIOF_CARDRESET |
- WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING,
- .identity = "COH 901 327 Watchdog",
- .firmware_version = 1,
- };
- uarg.i = (int __user *)arg;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user(uarg.ident, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- ret = put_user(0, uarg.i);
- break;
-
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(boot_status, uarg.i);
- break;
-
- case WDIOC_SETOPTIONS:
- ret = get_user(new_options, uarg.i);
- if (ret)
- break;
- if (new_options & WDIOS_DISABLECARD)
- coh901327_disable();
- if (new_options & WDIOS_ENABLECARD)
- coh901327_start();
- ret = 0;
- break;
-
- case WDIOC_KEEPALIVE:
- coh901327_keepalive();
- ret = 0;
- break;
-
- case WDIOC_SETTIMEOUT:
- ret = get_user(time, uarg.i);
- if (ret)
- break;
-
- ret = coh901327_settimeout(time);
- if (ret)
- break;
- /* Then fall through to return set value */
-
- case WDIOC_GETTIMEOUT:
- ret = put_user(margin, uarg.i);
- break;
-
- case WDIOC_GETTIMELEFT:
- clk_enable(clk);
- /* Read repeatedly until the value is stable! */
- val = readw(virtbase + U300_WDOG_CR);
- while (val & U300_WDOG_CR_VALID_IND)
- val = readw(virtbase + U300_WDOG_CR);
- val &= U300_WDOG_CR_COUNT_VALUE_MASK;
- clk_disable(clk);
- if (val != 0)
- val /= 100;
- ret = put_user(val, uarg.i);
- break;
- }
- return ret;
-}
+static const struct watchdog_info coh901327_ident = {
+ .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = DRV_NAME,
+};
-static const struct file_operations coh901327_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = coh901327_write,
- .unlocked_ioctl = coh901327_ioctl,
- .open = coh901327_open,
- .release = coh901327_release,
+static struct watchdog_ops coh901327_ops = {
+ .owner = THIS_MODULE,
+ .start = coh901327_start,
+ .stop = coh901327_stop,
+ .ping = coh901327_ping,
+ .set_timeout = coh901327_settimeout,
+ .get_timeleft = coh901327_gettimeleft,
};
-static struct miscdevice coh901327_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &coh901327_fops,
+static struct watchdog_device coh901327_wdt = {
+ .info = &coh901327_ident,
+ .ops = &coh901327_ops,
+ /*
+ * Max timeout is 327 since the 10ms
+ * timeout register is max
+ * 0x7FFF = 327670ms ~= 327s.
+ */
+ .min_timeout = 0,
+ .max_timeout = 327,
};
static int __exit coh901327_remove(struct platform_device *pdev)
{
- misc_deregister(&coh901327_miscdev);
+ watchdog_unregister_device(&coh901327_wdt);
coh901327_disable();
free_irq(irq, pdev);
clk_put(clk);
@@ -350,7 +269,6 @@ static int __exit coh901327_remove(struct platform_device *pdev)
return 0;
}
-
static int __init coh901327_probe(struct platform_device *pdev)
{
int ret;
@@ -393,7 +311,7 @@ static int __init coh901327_probe(struct platform_device *pdev)
case U300_WDOG_SR_STATUS_TIMED_OUT:
dev_info(&pdev->dev,
"watchdog timed out since last chip reset!\n");
- boot_status = WDIOF_CARDRESET;
+ coh901327_wdt.bootstatus |= WDIOF_CARDRESET;
/* Status will be cleared below */
break;
case U300_WDOG_SR_STATUS_NORMAL:
@@ -435,7 +353,11 @@ static int __init coh901327_probe(struct platform_device *pdev)
clk_disable(clk);
- ret = misc_register(&coh901327_miscdev);
+ if (margin < 1 || margin > 327)
+ margin = 60;
+ coh901327_wdt.timeout = margin;
+
+ ret = watchdog_register_device(&coh901327_wdt);
if (ret == 0)
dev_info(&pdev->dev,
"initialized. timer margin=%d sec\n", margin);
@@ -543,8 +465,8 @@ module_exit(coh901327_exit);
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
MODULE_DESCRIPTION("COH 901 327 Watchdog");
-module_param(margin, int, 0);
+module_param(margin, uint, 0);
MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:coh901327-watchdog");
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
index 251c863d71dd..7e888393de1f 100644
--- a/drivers/watchdog/cpu5wdt.c
+++ b/drivers/watchdog/cpu5wdt.c
@@ -19,6 +19,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -71,7 +73,7 @@ static struct {
static void cpu5wdt_trigger(unsigned long unused)
{
if (verbose > 2)
- printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
+ pr_debug("trigger at %i ticks\n", ticks);
if (cpu5wdt_device.running)
ticks--;
@@ -96,7 +98,7 @@ static void cpu5wdt_reset(void)
ticks = cpu5wdt_device.default_ticks;
if (verbose)
- printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
+ pr_debug("reset (%i ticks)\n", (int) ticks);
}
@@ -129,7 +131,7 @@ static int cpu5wdt_stop(void)
ticks = cpu5wdt_device.default_ticks;
spin_unlock_irqrestore(&cpu5wdt_lock, flags);
if (verbose)
- printk(KERN_CRIT PFX "stop not possible\n");
+ pr_crit("stop not possible\n");
return -EIO;
}
@@ -219,8 +221,7 @@ static int __devinit cpu5wdt_init(void)
int err;
if (verbose)
- printk(KERN_DEBUG PFX
- "port=0x%x, verbose=%i\n", port, verbose);
+ pr_debug("port=0x%x, verbose=%i\n", port, verbose);
init_completion(&cpu5wdt_device.stop);
cpu5wdt_device.queue = 0;
@@ -228,7 +229,7 @@ static int __devinit cpu5wdt_init(void)
cpu5wdt_device.default_ticks = ticks;
if (!request_region(port, CPU5WDT_EXTENT, PFX)) {
- printk(KERN_ERR PFX "request_region failed\n");
+ pr_err("request_region failed\n");
err = -EBUSY;
goto no_port;
}
@@ -237,16 +238,16 @@ static int __devinit cpu5wdt_init(void)
val = inb(port + CPU5WDT_STATUS_REG);
val = (val >> 2) & 1;
if (!val)
- printk(KERN_INFO PFX "sorry, was my fault\n");
+ pr_info("sorry, was my fault\n");
err = misc_register(&cpu5wdt_misc);
if (err < 0) {
- printk(KERN_ERR PFX "misc_register failed\n");
+ pr_err("misc_register failed\n");
goto no_misc;
}
- printk(KERN_INFO PFX "init success\n");
+ pr_info("init success\n");
return 0;
no_misc:
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 1b793dfd868f..95b1b954de1b 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -14,6 +14,8 @@
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
@@ -35,7 +37,6 @@
#include <asm/watchdog.h>
#define DRIVER_NAME "cpwd"
-#define PFX DRIVER_NAME ": "
#define WD_OBPNAME "watchdog"
#define WD_BADMODEL "SUNW,501-5336"
@@ -385,8 +386,7 @@ static int cpwd_open(struct inode *inode, struct file *f)
if (!p->initialized) {
if (request_irq(p->irq, &cpwd_interrupt,
IRQF_SHARED, DRIVER_NAME, p)) {
- printk(KERN_ERR PFX "Cannot register IRQ %d\n",
- p->irq);
+ pr_err("Cannot register IRQ %d\n", p->irq);
mutex_unlock(&cpwd_mutex);
return -EBUSY;
}
@@ -542,7 +542,7 @@ static int __devinit cpwd_probe(struct platform_device *op)
p = kzalloc(sizeof(*p), GFP_KERNEL);
err = -ENOMEM;
if (!p) {
- printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n");
+ pr_err("Unable to allocate struct cpwd\n");
goto out;
}
@@ -553,14 +553,14 @@ static int __devinit cpwd_probe(struct platform_device *op)
p->regs = of_ioremap(&op->resource[0], 0,
4 * WD_TIMER_REGSZ, DRIVER_NAME);
if (!p->regs) {
- printk(KERN_ERR PFX "Unable to map registers.\n");
+ pr_err("Unable to map registers\n");
goto out_free;
}
options = of_find_node_by_path("/options");
err = -ENODEV;
if (!options) {
- printk(KERN_ERR PFX "Unable to find /options node.\n");
+ pr_err("Unable to find /options node\n");
goto out_iounmap;
}
@@ -605,8 +605,8 @@ static int __devinit cpwd_probe(struct platform_device *op)
err = misc_register(&p->devs[i].misc);
if (err) {
- printk(KERN_ERR "Could not register misc device for "
- "dev %d\n", i);
+ pr_err("Could not register misc device for dev %d\n",
+ i);
goto out_unregister;
}
}
@@ -617,8 +617,8 @@ static int __devinit cpwd_probe(struct platform_device *op)
cpwd_timer.data = (unsigned long) p;
cpwd_timer.expires = WD_BTIMEOUT;
- printk(KERN_INFO PFX "PLD defect workaround enabled for "
- "model " WD_BADMODEL ".\n");
+ pr_info("PLD defect workaround enabled for model %s\n",
+ WD_BADMODEL);
}
dev_set_drvdata(&op->dev, p);
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 63d7b58f1c7d..06de1211a444 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -16,7 +16,8 @@
* If we receive an expected close for the watchdog then we keep the timer
* running, otherwise the timer is stopped and the watchdog will expire.
*/
-#define pr_fmt(fmt) "dw_wdt: " fmt
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <linux/clk.h>
@@ -45,8 +46,8 @@
/* The maximum TOP (timeout period) value that can be set in the watchdog. */
#define DW_WDT_MAX_TOP 15
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c
index 09cd888db619..77050037597a 100644
--- a/drivers/watchdog/ep93xx_wdt.c
+++ b/drivers/watchdog/ep93xx_wdt.c
@@ -8,6 +8,9 @@
* Authors: Ray Lehtiniemi <rayl@mail.com>,
* Alessandro Zummo <a.zummo@towertech.it>
*
+ * Copyright (c) 2012 H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Convert to a platform device and use the watchdog framework API
+ *
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
@@ -25,187 +28,90 @@
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/timer.h>
-#include <linux/uaccess.h>
#include <linux/io.h>
-#define WDT_VERSION "0.3"
-#define PFX "ep93xx_wdt: "
+#define WDT_VERSION "0.4"
/* default timeout (secs) */
#define WDT_TIMEOUT 30
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int timeout = WDT_TIMEOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+static unsigned int timeout = WDT_TIMEOUT;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+ "Watchdog timeout in seconds. (1<=timeout<=3600, default="
+ __MODULE_STRING(WDT_TIMEOUT) ")");
static void __iomem *mmio_base;
static struct timer_list timer;
static unsigned long next_heartbeat;
-static unsigned long wdt_status;
-static unsigned long boot_status;
-
-#define WDT_IN_USE 0
-#define WDT_OK_TO_CLOSE 1
#define EP93XX_WATCHDOG 0x00
#define EP93XX_WDSTATUS 0x04
-/* reset the wdt every ~200ms */
+/* reset the wdt every ~200ms - the heartbeat of the device is 0.250 seconds*/
#define WDT_INTERVAL (HZ/5)
-static void wdt_enable(void)
+static void ep93xx_wdt_timer_ping(unsigned long data)
{
- writel(0xaaaa, mmio_base + EP93XX_WATCHDOG);
-}
-
-static void wdt_disable(void)
-{
- writel(0xaa55, mmio_base + EP93XX_WATCHDOG);
-}
+ if (time_before(jiffies, next_heartbeat))
+ writel(0x5555, mmio_base + EP93XX_WATCHDOG);
-static inline void wdt_ping(void)
-{
- writel(0x5555, mmio_base + EP93XX_WATCHDOG);
+ /* Re-set the timer interval */
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
}
-static void wdt_startup(void)
+static int ep93xx_wdt_start(struct watchdog_device *wdd)
{
next_heartbeat = jiffies + (timeout * HZ);
- wdt_enable();
+ writel(0xaaaa, mmio_base + EP93XX_WATCHDOG);
mod_timer(&timer, jiffies + WDT_INTERVAL);
+
+ return 0;
}
-static void wdt_shutdown(void)
+static int ep93xx_wdt_stop(struct watchdog_device *wdd)
{
del_timer_sync(&timer);
- wdt_disable();
+ writel(0xaa55, mmio_base + EP93XX_WATCHDOG);
+
+ return 0;
}
-static void wdt_keepalive(void)
+static int ep93xx_wdt_keepalive(struct watchdog_device *wdd)
{
/* user land ping */
next_heartbeat = jiffies + (timeout * HZ);
-}
-
-static int ep93xx_wdt_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(WDT_IN_USE, &wdt_status))
- return -EBUSY;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- wdt_startup();
-
- return nonseekable_open(inode, file);
-}
-
-static ssize_t
-ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
- loff_t *ppos)
-{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
-
- if (c == 'V')
- set_bit(WDT_OK_TO_CLOSE, &wdt_status);
- else
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
- }
- }
- wdt_keepalive();
- }
- return len;
+ return 0;
}
-static const struct watchdog_info ident = {
- .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE,
- .identity = "EP93xx Watchdog",
+static const struct watchdog_info ep93xx_wdt_ident = {
+ .options = WDIOF_CARDRESET |
+ WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+ .identity = "EP93xx Watchdog",
};
-static long ep93xx_wdt_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int ret = -ENOTTY;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- ret = put_user(0, (int __user *)arg);
- break;
-
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(boot_status, (int __user *)arg);
- break;
-
- case WDIOC_KEEPALIVE:
- wdt_keepalive();
- ret = 0;
- break;
-
- case WDIOC_GETTIMEOUT:
- /* actually, it is 0.250 seconds.... */
- ret = put_user(1, (int __user *)arg);
- break;
- }
- return ret;
-}
-
-static int ep93xx_wdt_release(struct inode *inode, struct file *file)
-{
- if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
- wdt_shutdown();
- else
- printk(KERN_CRIT PFX
- "Device closed unexpectedly - timer will not stop\n");
-
- clear_bit(WDT_IN_USE, &wdt_status);
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- return 0;
-}
-
-static const struct file_operations ep93xx_wdt_fops = {
+static struct watchdog_ops ep93xx_wdt_ops = {
.owner = THIS_MODULE,
- .write = ep93xx_wdt_write,
- .unlocked_ioctl = ep93xx_wdt_ioctl,
- .open = ep93xx_wdt_open,
- .release = ep93xx_wdt_release,
- .llseek = no_llseek,
+ .start = ep93xx_wdt_start,
+ .stop = ep93xx_wdt_stop,
+ .ping = ep93xx_wdt_keepalive,
};
-static struct miscdevice ep93xx_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &ep93xx_wdt_fops,
+static struct watchdog_device ep93xx_wdt_wdd = {
+ .info = &ep93xx_wdt_ident,
+ .ops = &ep93xx_wdt_ops,
};
-static void ep93xx_timer_ping(unsigned long data)
-{
- if (time_before(jiffies, next_heartbeat))
- wdt_ping();
-
- /* Re-set the timer interval */
- mod_timer(&timer, jiffies + WDT_INTERVAL);
-}
-
static int __devinit ep93xx_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -224,30 +130,35 @@ static int __devinit ep93xx_wdt_probe(struct platform_device *pdev)
if (!mmio_base)
return -ENXIO;
- err = misc_register(&ep93xx_wdt_miscdev);
-
- val = readl(mmio_base + EP93XX_WATCHDOG);
- boot_status = val & 0x01 ? 1 : 0;
-
- printk(KERN_INFO PFX "EP93XX watchdog, driver version "
- WDT_VERSION "%s\n",
- (val & 0x08) ? " (nCS1 disable detected)" : "");
-
if (timeout < 1 || timeout > 3600) {
timeout = WDT_TIMEOUT;
- printk(KERN_INFO PFX
+ dev_warn(&pdev->dev,
"timeout value must be 1<=x<=3600, using %d\n",
timeout);
}
- setup_timer(&timer, ep93xx_timer_ping, 1);
- return err;
+ val = readl(mmio_base + EP93XX_WATCHDOG);
+ ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0;
+ ep93xx_wdt_wdd.timeout = timeout;
+
+ watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout);
+
+ setup_timer(&timer, ep93xx_wdt_timer_ping, 1);
+
+ err = watchdog_register_device(&ep93xx_wdt_wdd);
+ if (err)
+ return err;
+
+ dev_info(&pdev->dev,
+ "EP93XX watchdog, driver version " WDT_VERSION "%s\n",
+ (val & 0x08) ? " (nCS1 disable detected)" : "");
+
+ return 0;
}
static int __devexit ep93xx_wdt_remove(struct platform_device *pdev)
{
- wdt_shutdown();
- misc_deregister(&ep93xx_wdt_miscdev);
+ watchdog_unregister_device(&ep93xx_wdt_wdd);
return 0;
}
@@ -262,16 +173,9 @@ static struct platform_driver ep93xx_wdt_driver = {
module_platform_driver(ep93xx_wdt_driver);
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
-module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout,
- "Watchdog timeout in seconds. (1<=timeout<=3600, default="
- __MODULE_STRING(WDT_TIMEOUT) ")");
-
MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
- "Alessandro Zummo <a.zummo@towertech.it>");
+ "Alessandro Zummo <a.zummo@towertech.it>,"
+ "H Hartley Sweeten <hsweeten@visionengravers.com>");
MODULE_DESCRIPTION("EP93xx Watchdog");
MODULE_LICENSE("GPL");
MODULE_VERSION(WDT_VERSION);
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index 3946c51099c0..cd31b8a2a729 100644
--- a/drivers/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
@@ -45,6 +45,8 @@
* of the on-board SUPER I/O device SMSC FDC 37B782.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -59,7 +61,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
static unsigned long eurwdt_is_open;
static int eurwdt_timeout;
@@ -76,8 +77,8 @@ static char *ev = "int";
#define WDT_TIMEOUT 60 /* 1 minute */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -144,11 +145,11 @@ static void eurwdt_activate_timer(void)
/* Setting interrupt line */
if (irq == 2 || irq > 15 || irq < 0) {
- printk(KERN_ERR ": invalid irq number\n");
+ pr_err("invalid irq number\n");
irq = 0; /* if invalid we disable interrupt */
}
if (irq == 0)
- printk(KERN_INFO ": interrupt disabled\n");
+ pr_info("interrupt disabled\n");
eurwdt_write_reg(WDT_TIMER_CFG, irq << 4);
@@ -163,12 +164,12 @@ static void eurwdt_activate_timer(void)
static irqreturn_t eurwdt_interrupt(int irq, void *dev_id)
{
- printk(KERN_CRIT "timeout WDT timeout\n");
+ pr_crit("timeout WDT timeout\n");
#ifdef ONLY_TESTING
- printk(KERN_CRIT "Would Reboot.\n");
+ pr_crit("Would Reboot\n");
#else
- printk(KERN_CRIT "Initiating system reboot.\n");
+ pr_crit("Initiating system reboot\n");
emergency_restart();
#endif
return IRQ_HANDLED;
@@ -335,8 +336,7 @@ static int eurwdt_release(struct inode *inode, struct file *file)
if (eur_expect_close == 42)
eurwdt_disable_timer();
else {
- printk(KERN_CRIT
- "eurwdt: Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
eurwdt_ping();
}
clear_bit(0, &eurwdt_is_open);
@@ -429,35 +429,32 @@ static int __init eurwdt_init(void)
ret = request_irq(irq, eurwdt_interrupt, 0, "eurwdt", NULL);
if (ret) {
- printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
+ pr_err("IRQ %d is not free\n", irq);
goto out;
}
if (!request_region(io, 2, "eurwdt")) {
- printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
+ pr_err("IO %X is not free\n", io);
ret = -EBUSY;
goto outirq;
}
ret = register_reboot_notifier(&eurwdt_notifier);
if (ret) {
- printk(KERN_ERR
- "eurwdt: can't register reboot notifier (err=%d)\n", ret);
+ pr_err("can't register reboot notifier (err=%d)\n", ret);
goto outreg;
}
ret = misc_register(&eurwdt_miscdev);
if (ret) {
- printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
- WATCHDOG_MINOR);
+ pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
goto outreboot;
}
eurwdt_unlock_chip();
ret = 0;
- printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
- " - timeout event: %s\n",
+ pr_info("Eurotech WDT driver 0.01 at %X (Interrupt %d) - timeout event: %s\n",
io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
out:
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index e45ca2b4bfbe..c65b0a5a020c 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -19,6 +19,8 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -189,8 +191,7 @@ static inline int superio_enter(int base)
{
/* Don't step on other drivers' I/O space by accident */
if (!request_muxed_region(base, 2, DRVNAME)) {
- printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
- (int)base);
+ pr_err("I/O address 0x%04x already in use\n", (int)base);
return -EBUSY;
}
@@ -217,7 +218,7 @@ static int watchdog_set_timeout(int timeout)
{
if (timeout <= 0
|| timeout > max_timeout) {
- printk(KERN_ERR DRVNAME ": watchdog timeout out of range\n");
+ pr_err("watchdog timeout out of range\n");
return -EINVAL;
}
@@ -252,7 +253,7 @@ static int watchdog_set_pulse_width(unsigned int pw)
} else if (pw <= 5000) {
watchdog.pulse_val = 3;
} else {
- printk(KERN_ERR DRVNAME ": pulse width out of range\n");
+ pr_err("pulse width out of range\n");
err = -EINVAL;
goto exit_unlock;
}
@@ -309,8 +310,7 @@ static int f71862fg_pin_configure(unsigned short ioaddr)
if (ioaddr)
superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1);
} else {
- printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n",
- f71862fg_pin);
+ pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
return -EINVAL;
}
return 0;
@@ -487,8 +487,7 @@ static int watchdog_release(struct inode *inode, struct file *file)
if (!watchdog.expect_close) {
watchdog_keepalive();
- printk(KERN_CRIT DRVNAME
- ": Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
} else if (!nowayout) {
watchdog_stop();
}
@@ -672,25 +671,22 @@ static int __init watchdog_init(int sioaddr)
err = misc_register(&watchdog_miscdev);
if (err) {
- printk(KERN_ERR DRVNAME
- ": cannot register miscdev on minor=%d\n",
- watchdog_miscdev.minor);
+ pr_err("cannot register miscdev on minor=%d\n",
+ watchdog_miscdev.minor);
goto exit_reboot;
}
if (start_withtimeout) {
if (start_withtimeout <= 0
|| start_withtimeout > max_timeout) {
- printk(KERN_ERR DRVNAME
- ": starting timeout out of range\n");
+ pr_err("starting timeout out of range\n");
err = -EINVAL;
goto exit_miscdev;
}
err = watchdog_start();
if (err) {
- printk(KERN_ERR DRVNAME
- ": cannot start watchdog timer\n");
+ pr_err("cannot start watchdog timer\n");
goto exit_miscdev;
}
@@ -720,8 +716,7 @@ static int __init watchdog_init(int sioaddr)
if (nowayout)
__module_get(THIS_MODULE);
- printk(KERN_INFO DRVNAME
- ": watchdog started with initial timeout of %u sec\n",
+ pr_info("watchdog started with initial timeout of %u sec\n",
start_withtimeout);
}
@@ -746,7 +741,7 @@ static int __init f71808e_find(int sioaddr)
devid = superio_inw(sioaddr, SIO_REG_MANID);
if (devid != SIO_FINTEK_ID) {
- pr_debug(DRVNAME ": Not a Fintek device\n");
+ pr_debug("Not a Fintek device\n");
err = -ENODEV;
goto exit;
}
@@ -774,13 +769,13 @@ static int __init f71808e_find(int sioaddr)
err = -ENODEV;
goto exit;
default:
- printk(KERN_INFO DRVNAME ": Unrecognized Fintek device: %04x\n",
- (unsigned int)devid);
+ pr_info("Unrecognized Fintek device: %04x\n",
+ (unsigned int)devid);
err = -ENODEV;
goto exit;
}
- printk(KERN_INFO DRVNAME ": Found %s watchdog chip, revision %d\n",
+ pr_info("Found %s watchdog chip, revision %d\n",
f71808e_names[watchdog.type],
(int)superio_inb(sioaddr, SIO_REG_DEVREV));
exit:
@@ -808,8 +803,7 @@ static int __init f71808e_init(void)
static void __exit f71808e_exit(void)
{
if (watchdog_is_running()) {
- printk(KERN_WARNING DRVNAME
- ": Watchdog timer still running, stopping it\n");
+ pr_warn("Watchdog timer still running, stopping it\n");
watchdog_stop();
}
misc_deregister(&watchdog_miscdev);
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index b146082bd85a..17f4cae770c6 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -24,6 +24,8 @@
* capabilities) a kernel-based watchdog.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/init.h>
@@ -68,8 +70,8 @@ static unsigned int bus_clk;
static char expect_close;
static DEFINE_SPINLOCK(gef_wdt_spinlock);
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -110,7 +112,7 @@ static void gef_wdt_handler_enable(void)
if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_FALSE,
GEF_WDC_ENABLE_SHIFT)) {
gef_wdt_service();
- printk(KERN_NOTICE "gef_wdt: watchdog activated\n");
+ pr_notice("watchdog activated\n");
}
}
@@ -118,7 +120,7 @@ static void gef_wdt_handler_disable(void)
{
if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE,
GEF_WDC_ENABLE_SHIFT))
- printk(KERN_NOTICE "gef_wdt: watchdog deactivated\n");
+ pr_notice("watchdog deactivated\n");
}
static void gef_wdt_set_timeout(unsigned int timeout)
@@ -234,8 +236,7 @@ static int gef_wdt_release(struct inode *inode, struct file *file)
if (expect_close == 42)
gef_wdt_handler_disable();
else {
- printk(KERN_CRIT
- "gef_wdt: unexpected close, not stopping timer!\n");
+ pr_crit("unexpected close, not stopping timer!\n");
gef_wdt_service();
}
expect_close = 0;
@@ -313,7 +314,7 @@ static struct platform_driver gef_wdt_driver = {
static int __init gef_wdt_init(void)
{
- printk(KERN_INFO "GE watchdog driver\n");
+ pr_info("GE watchdog driver\n");
return platform_driver_register(&gef_wdt_driver);
}
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
index 9b49b125ad5a..dc563b680abd 100644
--- a/drivers/watchdog/geodewdt.c
+++ b/drivers/watchdog/geodewdt.c
@@ -9,6 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -39,8 +40,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=131, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -100,7 +101,7 @@ static int geodewdt_release(struct inode *inode, struct file *file)
geodewdt_disable();
module_put(THIS_MODULE);
} else {
- printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n");
+ pr_crit("Unexpected close - watchdog is not stopping\n");
geodewdt_ping();
set_bit(WDT_FLAGS_ORPHAN, &wdt_flags);
@@ -220,7 +221,7 @@ static int __devinit geodewdt_probe(struct platform_device *dev)
wdt_timer = cs5535_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
if (!wdt_timer) {
- printk(KERN_ERR "geodewdt: No timers were available\n");
+ pr_err("No timers were available\n");
return -ENODEV;
}
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 3c166d3f4e55..cbc7ceef2786 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -13,6 +13,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -45,7 +47,7 @@
static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */
static unsigned int reload; /* the computed soft_margin */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static char expect_release;
static unsigned long hpwdt_is_open;
@@ -235,8 +237,7 @@ static int __devinit cru_detect(unsigned long map_entry,
asminline_call(&cmn_regs, bios32_entrypoint);
if (cmn_regs.u1.ral != 0) {
- printk(KERN_WARNING
- "hpwdt: Call succeeded but with an error: 0x%x\n",
+ pr_warn("Call succeeded but with an error: 0x%x\n",
cmn_regs.u1.ral);
} else {
physical_bios_base = cmn_regs.u2.rebx;
@@ -256,14 +257,10 @@ static int __devinit cru_detect(unsigned long map_entry,
}
}
- printk(KERN_DEBUG "hpwdt: CRU Base Address: 0x%lx\n",
- physical_bios_base);
- printk(KERN_DEBUG "hpwdt: CRU Offset Address: 0x%lx\n",
- physical_bios_offset);
- printk(KERN_DEBUG "hpwdt: CRU Length: 0x%lx\n",
- cru_length);
- printk(KERN_DEBUG "hpwdt: CRU Mapped Address: %p\n",
- &cru_rom_addr);
+ pr_debug("CRU Base Address: 0x%lx\n", physical_bios_base);
+ pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset);
+ pr_debug("CRU Length: 0x%lx\n", cru_length);
+ pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr);
}
iounmap(bios32_map);
return retval;
@@ -458,16 +455,13 @@ static void hpwdt_ping(void)
static int hpwdt_change_timer(int new_margin)
{
if (new_margin < 1 || new_margin > HPWDT_MAX_TIMER) {
- printk(KERN_WARNING
- "hpwdt: New value passed in is invalid: %d seconds.\n",
+ pr_warn("New value passed in is invalid: %d seconds\n",
new_margin);
return -EINVAL;
}
soft_margin = new_margin;
- printk(KERN_DEBUG
- "hpwdt: New timer passed in is %d seconds.\n",
- new_margin);
+ pr_debug("New timer passed in is %d seconds\n", new_margin);
reload = SECS_TO_TICKS(soft_margin);
return 0;
@@ -535,8 +529,7 @@ static int hpwdt_release(struct inode *inode, struct file *file)
if (expect_release == 42) {
hpwdt_stop();
} else {
- printk(KERN_CRIT
- "hpwdt: Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
hpwdt_ping();
}
@@ -881,7 +874,7 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
module_param(soft_margin, int, 0);
MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index db45091ef434..738032a36bcf 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -27,6 +27,8 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -44,7 +46,6 @@
#define ESB_VERSION "0.05"
#define ESB_MODULE_NAME "i6300ESB timer"
#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
-#define PFX ESB_MODULE_NAME ": "
/* PCI configuration registers */
#define ESB_CONFIG_REG 0x60 /* Config register */
@@ -94,8 +95,8 @@ MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat in seconds. (1<heartbeat<2046, default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -213,8 +214,7 @@ static int esb_release(struct inode *inode, struct file *file)
if (esb_expect_close == 42)
esb_timer_stop();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
esb_timer_keepalive();
}
clear_bit(0, &timer_alive);
@@ -347,19 +347,19 @@ MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
static unsigned char __devinit esb_getdevice(struct pci_dev *pdev)
{
if (pci_enable_device(pdev)) {
- printk(KERN_ERR PFX "failed to enable device\n");
+ pr_err("failed to enable device\n");
goto err_devput;
}
if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
- printk(KERN_ERR PFX "failed to request region\n");
+ pr_err("failed to request region\n");
goto err_disable;
}
BASEADDR = pci_ioremap_bar(pdev, 0);
if (BASEADDR == NULL) {
/* Something's wrong here, BASEADDR has to be set */
- printk(KERN_ERR PFX "failed to get BASEADDR\n");
+ pr_err("failed to get BASEADDR\n");
goto err_release;
}
@@ -397,7 +397,7 @@ static void __devinit esb_initdevice(void)
/* Check that the WDT isn't already locked */
pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
if (val1 & ESB_WDT_LOCK)
- printk(KERN_WARNING PFX "nowayout already set\n");
+ pr_warn("nowayout already set\n");
/* Set the timer to watchdog mode and disable it for now */
pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
@@ -423,11 +423,11 @@ static int __devinit esb_probe(struct pci_dev *pdev,
cards_found++;
if (cards_found == 1)
- printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n",
+ pr_info("Intel 6300ESB WatchDog Timer Driver v%s\n",
ESB_VERSION);
if (cards_found > 1) {
- printk(KERN_ERR PFX "This driver only supports 1 device\n");
+ pr_err("This driver only supports 1 device\n");
return -ENODEV;
}
@@ -439,9 +439,8 @@ static int __devinit esb_probe(struct pci_dev *pdev,
if not reset to the default */
if (heartbeat < 0x1 || heartbeat > 2 * 0x03ff) {
heartbeat = WATCHDOG_HEARTBEAT;
- printk(KERN_INFO PFX
- "heartbeat value must be 1<heartbeat<2046, using %d\n",
- heartbeat);
+ pr_info("heartbeat value must be 1<heartbeat<2046, using %d\n",
+ heartbeat);
}
/* Initialize the watchdog and make sure it does not run */
@@ -450,14 +449,12 @@ static int __devinit esb_probe(struct pci_dev *pdev,
/* Register the watchdog so that userspace has access to it */
ret = misc_register(&esb_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto err_unmap;
}
- printk(KERN_INFO PFX
- "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
- BASEADDR, heartbeat, nowayout);
+ pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
+ BASEADDR, heartbeat, nowayout);
return 0;
err_unmap:
@@ -503,7 +500,7 @@ static int __init watchdog_init(void)
static void __exit watchdog_cleanup(void)
{
pci_unregister_driver(&esb_driver);
- printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+ pr_info("Watchdog Module Unloaded\n");
}
module_init(watchdog_init);
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c
index 481d1ad43464..2721d29ce243 100644
--- a/drivers/watchdog/iTCO_vendor_support.c
+++ b/drivers/watchdog/iTCO_vendor_support.c
@@ -17,10 +17,11 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
/* Module and version information */
#define DRV_NAME "iTCO_vendor_support"
#define DRV_VERSION "1.04"
-#define PFX DRV_NAME ": "
/* Includes */
#include <linux/module.h> /* For module specific items */
@@ -355,13 +356,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
static int __init iTCO_vendor_init_module(void)
{
- printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
+ pr_info("vendor-support=%d\n", vendorsupport);
return 0;
}
static void __exit iTCO_vendor_exit_module(void)
{
- printk(KERN_INFO PFX "Module Unloaded\n");
+ pr_info("Module Unloaded\n");
}
module_init(iTCO_vendor_init_module);
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index bdf401b240b5..9fecb95645a3 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -43,10 +43,11 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.07"
-#define PFX DRV_NAME ": "
/* Includes */
#include <linux/module.h> /* For module specific items */
@@ -413,8 +414,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
"5..76 (TCO v1) or 3..614 (TCO v2), default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -489,8 +490,7 @@ static int iTCO_wdt_start(void)
/* disable chipset's NO_REBOOT bit */
if (iTCO_wdt_unset_NO_REBOOT_bit()) {
spin_unlock(&iTCO_wdt_private.io_lock);
- printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
- "reboot disabled by hardware/BIOS\n");
+ pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n");
return -EIO;
}
@@ -661,8 +661,7 @@ static int iTCO_wdt_release(struct inode *inode, struct file *file)
if (expect_release == 42) {
iTCO_wdt_stop();
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
iTCO_wdt_keepalive();
}
clear_bit(0, &is_active);
@@ -804,8 +803,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
base_address &= 0x0000ff80;
if (base_address == 0x00000000) {
/* Something's wrong here, ACPIBASE has to be set */
- printk(KERN_ERR PFX "failed to get TCOBASE address, "
- "device disabled by hardware/BIOS\n");
+ pr_err("failed to get TCOBASE address, device disabled by hardware/BIOS\n");
return -ENODEV;
}
iTCO_wdt_private.iTCO_version =
@@ -820,8 +818,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
if (iTCO_wdt_private.iTCO_version == 2) {
pci_read_config_dword(pdev, 0xf0, &base_address);
if ((base_address & 1) == 0) {
- printk(KERN_ERR PFX "RCBA is disabled by hardware"
- "/BIOS, device disabled\n");
+ pr_err("RCBA is disabled by hardware/BIOS, device disabled\n");
ret = -ENODEV;
goto out;
}
@@ -831,8 +828,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
/* Check chipset's NO_REBOOT bit */
if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
- printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
- "device disabled by hardware/BIOS\n");
+ pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
goto out_unmap;
}
@@ -842,9 +838,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
- printk(KERN_ERR PFX
- "I/O address 0x%04lx already in use, "
- "device disabled\n", SMI_EN);
+ pr_err("I/O address 0x%04lx already in use, device disabled\n",
+ SMI_EN);
ret = -EIO;
goto out_unmap;
}
@@ -858,17 +853,16 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
/* The TCO I/O registers reside in a 32-byte range pointed to
by the TCOBASE value */
if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
- printk(KERN_ERR PFX "I/O address 0x%04lx already in use "
- "device disabled\n", TCOBASE);
+ pr_err("I/O address 0x%04lx already in use, device disabled\n",
+ TCOBASE);
ret = -EIO;
goto unreg_smi_en;
}
- printk(KERN_INFO PFX
- "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
- iTCO_chipset_info[ent->driver_data].name,
- iTCO_chipset_info[ent->driver_data].iTCO_version,
- TCOBASE);
+ pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
+ iTCO_chipset_info[ent->driver_data].name,
+ iTCO_chipset_info[ent->driver_data].iTCO_version,
+ TCOBASE);
/* Clear out the (probably old) status */
outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
@@ -882,20 +876,18 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
if not reset to the default */
if (iTCO_wdt_set_heartbeat(heartbeat)) {
iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
- printk(KERN_INFO PFX
- "timeout value out of range, using %d\n", heartbeat);
+ pr_info("timeout value out of range, using %d\n", heartbeat);
}
ret = misc_register(&iTCO_wdt_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_region;
}
- printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
- heartbeat, nowayout);
+ pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
+ heartbeat, nowayout);
return 0;
@@ -947,7 +939,7 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev)
}
if (!found)
- printk(KERN_INFO PFX "No device detected.\n");
+ pr_info("No device detected\n");
return ret;
}
@@ -979,8 +971,7 @@ static int __init iTCO_wdt_init_module(void)
{
int err;
- printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
- DRV_VERSION);
+ pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION);
err = platform_driver_register(&iTCO_wdt_driver);
if (err)
@@ -1004,7 +995,7 @@ static void __exit iTCO_wdt_cleanup_module(void)
{
platform_device_unregister(iTCO_wdt_platform_device);
platform_driver_unregister(&iTCO_wdt_driver);
- printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+ pr_info("Watchdog Module Unloaded\n");
}
module_init(iTCO_wdt_init_module);
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
index 0149d8dfc81d..184c0bfc87a4 100644
--- a/drivers/watchdog/ib700wdt.c
+++ b/drivers/watchdog/ib700wdt.c
@@ -31,6 +31,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
@@ -44,7 +46,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
static struct platform_device *ibwdt_platform_device;
static unsigned long ibwdt_is_open;
@@ -53,7 +54,6 @@ static char expect_close;
/* Module information */
#define DRV_NAME "ib700wdt"
-#define PFX DRV_NAME ": "
/*
*
@@ -102,8 +102,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 0<= timeout <=30, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -246,8 +246,7 @@ static int ibwdt_close(struct inode *inode, struct file *file)
if (expect_close == 42) {
ibwdt_disable();
} else {
- printk(KERN_CRIT PFX
- "WDT device closed unexpectedly. WDT will not stop!\n");
+ pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
ibwdt_ping();
}
clear_bit(0, &ibwdt_is_open);
@@ -284,16 +283,14 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
#if WDT_START != WDT_STOP
if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
- printk(KERN_ERR PFX "STOP method I/O %X is not available.\n",
- WDT_STOP);
+ pr_err("STOP method I/O %X is not available\n", WDT_STOP);
res = -EIO;
goto out_nostopreg;
}
#endif
if (!request_region(WDT_START, 1, "IB700 WDT")) {
- printk(KERN_ERR PFX "START method I/O %X is not available.\n",
- WDT_START);
+ pr_err("START method I/O %X is not available\n", WDT_START);
res = -EIO;
goto out_nostartreg;
}
@@ -302,13 +299,12 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
* if not reset to the default */
if (ibwdt_set_heartbeat(timeout)) {
ibwdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 0<=x<=30, using %d\n", timeout);
+ pr_info("timeout value must be 0<=x<=30, using %d\n", timeout);
}
res = misc_register(&ibwdt_miscdev);
if (res) {
- printk(KERN_ERR PFX "failed to register misc device\n");
+ pr_err("failed to register misc device\n");
goto out_nomisc;
}
return 0;
@@ -353,8 +349,7 @@ static int __init ibwdt_init(void)
{
int err;
- printk(KERN_INFO PFX
- "WDT driver for IB700 single board computer initialising.\n");
+ pr_info("WDT driver for IB700 single board computer initialising\n");
err = platform_driver_register(&ibwdt_driver);
if (err)
@@ -378,7 +373,7 @@ static void __exit ibwdt_exit(void)
{
platform_device_unregister(ibwdt_platform_device);
platform_driver_unregister(&ibwdt_driver);
- printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+ pr_info("Watchdog Module Unloaded\n");
}
module_init(ibwdt_init);
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
index c7481ad51629..bc3fb8fe89ab 100644
--- a/drivers/watchdog/ibmasr.c
+++ b/drivers/watchdog/ibmasr.c
@@ -10,6 +10,8 @@
* of the GNU Public License, incorporated herein by reference.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -31,8 +33,6 @@ enum {
ASMTYPE_SPRUCE,
};
-#define PFX "ibmasr: "
-
#define TOPAZ_ASR_REG_OFFSET 4
#define TOPAZ_ASR_TOGGLE 0x40
#define TOPAZ_ASR_DISABLE 0x80
@@ -60,7 +60,7 @@ enum {
#define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned long asr_is_open;
static char asr_expect_close;
@@ -234,12 +234,11 @@ static int __init asr_get_base_address(void)
}
if (!request_region(asr_base, asr_length, "ibmasr")) {
- printk(KERN_ERR PFX "address %#x already in use\n",
- asr_base);
+ pr_err("address %#x already in use\n", asr_base);
return -EBUSY;
}
- printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
+ pr_info("found %sASR @ addr %#x\n", type, asr_base);
return 0;
}
@@ -332,8 +331,7 @@ static int asr_release(struct inode *inode, struct file *file)
if (asr_expect_close == 42)
asr_disable();
else {
- printk(KERN_CRIT PFX
- "unexpected close, not stopping watchdog!\n");
+ pr_crit("unexpected close, not stopping watchdog!\n");
asr_toggle();
}
clear_bit(0, &asr_is_open);
@@ -393,7 +391,7 @@ static int __init ibmasr_init(void)
rc = misc_register(&asr_miscdev);
if (rc < 0) {
release_region(asr_base, asr_length);
- printk(KERN_ERR PFX "failed to register misc device\n");
+ pr_err("failed to register misc device\n");
return rc;
}
@@ -413,7 +411,7 @@ static void __exit ibmasr_exit(void)
module_init(ibmasr_init);
module_exit(ibmasr_exit);
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index c44c3334003a..7a2b734fcdc7 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -46,6 +46,9 @@
#define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */
#define IMX2_WDT_SEQ2 0xAAAA /* -> service sequence 2 */
+#define IMX2_WDT_WRSR 0x04 /* Reset Status Register */
+#define IMX2_WDT_WRSR_TOUT (1 << 1) /* -> Reset due to Timeout */
+
#define IMX2_WDT_MAX_TIME 128
#define IMX2_WDT_DEFAULT_TIME 60 /* in seconds */
@@ -65,8 +68,8 @@ static struct {
static struct miscdevice imx2_wdt_miscdev;
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -175,6 +178,7 @@ static long imx2_wdt_ioctl(struct file *file, unsigned int cmd,
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_value;
+ u16 val;
switch (cmd) {
case WDIOC_GETSUPPORT:
@@ -182,9 +186,13 @@ static long imx2_wdt_ioctl(struct file *file, unsigned int cmd,
sizeof(struct watchdog_info)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
+ case WDIOC_GETBOOTSTATUS:
+ val = __raw_readw(imx2_wdt.base + IMX2_WDT_WRSR);
+ new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
+ return put_user(new_value, p);
+
case WDIOC_KEEPALIVE:
imx2_wdt_ping();
return 0;
diff --git a/drivers/watchdog/indydog.c b/drivers/watchdog/indydog.c
index 1475e09f9af2..6d90f7a2ce22 100644
--- a/drivers/watchdog/indydog.c
+++ b/drivers/watchdog/indydog.c
@@ -12,6 +12,8 @@
* based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -26,14 +28,13 @@
#include <linux/uaccess.h>
#include <asm/sgi/mc.h>
-#define PFX "indydog: "
static unsigned long indydog_alive;
static DEFINE_SPINLOCK(indydog_lock);
#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -60,7 +61,7 @@ static void indydog_stop(void)
sgimc->cpuctrl0 = mc_ctrl0;
spin_unlock(&indydog_lock);
- printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+ pr_info("Stopped watchdog timer\n");
}
static void indydog_ping(void)
@@ -83,7 +84,7 @@ static int indydog_open(struct inode *inode, struct file *file)
indydog_start();
indydog_ping();
- printk(KERN_INFO "Started watchdog timer.\n");
+ pr_info("Started watchdog timer\n");
return nonseekable_open(inode, file);
}
@@ -178,30 +179,25 @@ static struct notifier_block indydog_notifier = {
.notifier_call = indydog_notify_sys,
};
-static char banner[] __initdata =
- KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
-
static int __init watchdog_init(void)
{
int ret;
ret = register_reboot_notifier(&indydog_notifier);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&indydog_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&indydog_notifier);
return ret;
}
- printk(banner);
+ pr_info("Hardware Watchdog Timer for SGI IP22: 0.3\n");
return 0;
}
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
index 1abdc0454c54..9dda2d08af91 100644
--- a/drivers/watchdog/intel_scu_watchdog.c
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -22,6 +22,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -96,15 +98,14 @@ static struct intel_scu_watchdog_dev watchdog_device;
static void watchdog_fire(void)
{
if (force_boot) {
- printk(KERN_CRIT PFX "Initiating system reboot.\n");
+ pr_crit("Initiating system reboot\n");
emergency_restart();
- printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+ pr_crit("Reboot didn't ?????\n");
}
else {
- printk(KERN_CRIT PFX "Immediate Reboot Disabled\n");
- printk(KERN_CRIT PFX
- "System will reset when watchdog timer times out!\n");
+ pr_crit("Immediate Reboot Disabled\n");
+ pr_crit("System will reset when watchdog timer times out!\n");
}
}
@@ -112,8 +113,8 @@ static int check_timer_margin(int new_margin)
{
if ((new_margin < MIN_TIME_CYCLE) ||
(new_margin > MAX_TIME - timer_set)) {
- pr_debug("Watchdog timer: value of new_margin %d is out of the range %d to %d\n",
- new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
+ pr_debug("value of new_margin %d is out of the range %d to %d\n",
+ new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
return -EINVAL;
}
return 0;
@@ -156,14 +157,14 @@ static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
int int_status;
int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
- pr_debug("Watchdog timer: irq, int_status: %x\n", int_status);
+ pr_debug("irq, int_status: %x\n", int_status);
if (int_status != 0)
return IRQ_NONE;
/* has the timer been started? If not, then this is spurious */
if (watchdog_device.timer_started == 0) {
- pr_debug("Watchdog timer: spurious interrupt received\n");
+ pr_debug("spurious interrupt received\n");
return IRQ_HANDLED;
}
@@ -220,16 +221,15 @@ static int intel_scu_set_heartbeat(u32 t)
(watchdog_device.timer_set - timer_margin)
* watchdog_device.timer_tbl_ptr->freq_hz;
- pr_debug("Watchdog timer: set_heartbeat: timer freq is %d\n",
- watchdog_device.timer_tbl_ptr->freq_hz);
- pr_debug("Watchdog timer: set_heartbeat: timer_set is %x (hex)\n",
- watchdog_device.timer_set);
- pr_debug("Watchdog timer: set_hearbeat: timer_margin is %x (hex)\n",
- timer_margin);
- pr_debug("Watchdog timer: set_heartbeat: threshold is %x (hex)\n",
- watchdog_device.threshold);
- pr_debug("Watchdog timer: set_heartbeat: soft_threshold is %x (hex)\n",
- watchdog_device.soft_threshold);
+ pr_debug("set_heartbeat: timer freq is %d\n",
+ watchdog_device.timer_tbl_ptr->freq_hz);
+ pr_debug("set_heartbeat: timer_set is %x (hex)\n",
+ watchdog_device.timer_set);
+ pr_debug("set_hearbeat: timer_margin is %x (hex)\n", timer_margin);
+ pr_debug("set_heartbeat: threshold is %x (hex)\n",
+ watchdog_device.threshold);
+ pr_debug("set_heartbeat: soft_threshold is %x (hex)\n",
+ watchdog_device.soft_threshold);
/* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
/* watchdog timing come out right. */
@@ -264,7 +264,7 @@ static int intel_scu_set_heartbeat(u32 t)
if (MAX_RETRY < retry_count++) {
/* Unable to set timer value */
- pr_err("Watchdog timer: Unable to set timer\n");
+ pr_err("Unable to set timer\n");
return -ENODEV;
}
@@ -321,18 +321,17 @@ static int intel_scu_release(struct inode *inode, struct file *file)
*/
if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
- pr_debug("Watchdog timer: intel_scu_release, without open\n");
+ pr_debug("intel_scu_release, without open\n");
return -ENOTTY;
}
if (!watchdog_device.timer_started) {
/* Just close, since timer has not been started */
- pr_debug("Watchdog timer: closed, without starting timer\n");
+ pr_debug("closed, without starting timer\n");
return 0;
}
- printk(KERN_CRIT PFX
- "Unexpected close of /dev/watchdog!\n");
+ pr_crit("Unexpected close of /dev/watchdog!\n");
/* Since the timer was started, prevent future reopens */
watchdog_device.driver_closed = 1;
@@ -454,9 +453,8 @@ static int __init intel_scu_watchdog_init(void)
/* Check value of timer_set boot parameter */
if ((timer_set < MIN_TIME_CYCLE) ||
(timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
- pr_err("Watchdog timer: value of timer_set %x (hex) "
- "is out of range from %x to %x (hex)\n",
- timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
+ pr_err("value of timer_set %x (hex) is out of range from %x to %x (hex)\n",
+ timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
return -EINVAL;
}
@@ -467,19 +465,18 @@ static int __init intel_scu_watchdog_init(void)
watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
if (watchdog_device.timer_tbl_ptr == NULL) {
- pr_debug("Watchdog timer - Intel SCU watchdog: timer is not available\n");
+ pr_debug("timer is not available\n");
return -ENODEV;
}
/* make sure the timer exists */
if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
- pr_debug("Watchdog timer - Intel SCU watchdog - timer %d does not have valid physical memory\n",
- sfi_mtimer_num);
+ pr_debug("timer %d does not have valid physical memory\n",
+ sfi_mtimer_num);
return -ENODEV;
}
if (watchdog_device.timer_tbl_ptr->irq == 0) {
- pr_debug("Watchdog timer: timer %d invalid irq\n",
- sfi_mtimer_num);
+ pr_debug("timer %d invalid irq\n", sfi_mtimer_num);
return -ENODEV;
}
@@ -487,7 +484,7 @@ static int __init intel_scu_watchdog_init(void)
20);
if (tmp_addr == NULL) {
- pr_debug("Watchdog timer: timer unable to ioremap\n");
+ pr_debug("timer unable to ioremap\n");
return -ENOMEM;
}
@@ -512,7 +509,7 @@ static int __init intel_scu_watchdog_init(void)
ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
if (ret) {
- pr_err("Watchdog timer: cannot register notifier %d)\n", ret);
+ pr_err("cannot register notifier %d)\n", ret);
goto register_reboot_error;
}
@@ -522,8 +519,8 @@ static int __init intel_scu_watchdog_init(void)
ret = misc_register(&watchdog_device.miscdev);
if (ret) {
- pr_err("Watchdog timer: cannot register miscdev %d err =%d\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev %d err =%d\n",
+ WATCHDOG_MINOR, ret);
goto misc_register_error;
}
@@ -532,7 +529,7 @@ static int __init intel_scu_watchdog_init(void)
IRQF_SHARED, "watchdog",
&watchdog_device.timer_load_count_addr);
if (ret) {
- pr_err("Watchdog timer: error requesting irq %d\n", ret);
+ pr_err("error requesting irq %d\n", ret);
goto request_irq_error;
}
/* Make sure timer is disabled before returning */
diff --git a/drivers/watchdog/intel_scu_watchdog.h b/drivers/watchdog/intel_scu_watchdog.h
index d2b074a82db6..f3ac608deb6a 100644
--- a/drivers/watchdog/intel_scu_watchdog.h
+++ b/drivers/watchdog/intel_scu_watchdog.h
@@ -25,7 +25,6 @@
#ifndef __INTEL_SCU_WATCHDOG_H
#define __INTEL_SCU_WATCHDOG_H
-#define PFX "Intel_SCU: "
#define WDT_VER "0.3"
/* minimum time between interrupts */
diff --git a/drivers/watchdog/iop_wdt.c b/drivers/watchdog/iop_wdt.c
index 82fa7a92a8d2..d964faf1a250 100644
--- a/drivers/watchdog/iop_wdt.c
+++ b/drivers/watchdog/iop_wdt.c
@@ -24,6 +24,8 @@
* Dan Williams <dan.j.williams@intel.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -34,7 +36,7 @@
#include <linux/uaccess.h>
#include <mach/hardware.h>
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned long wdt_status;
static unsigned long boot_status;
static DEFINE_SPINLOCK(wdt_lock);
@@ -85,7 +87,7 @@ static int wdt_disable(void)
write_wdtcr(IOP_WDTCR_DIS);
clear_bit(WDT_ENABLED, &wdt_status);
spin_unlock(&wdt_lock);
- printk(KERN_INFO "WATCHDOG: Disabled\n");
+ pr_info("Disabled\n");
return 0;
} else
return 1;
@@ -197,8 +199,8 @@ static int iop_wdt_release(struct inode *inode, struct file *file)
*/
if (state != 0) {
wdt_enable();
- printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
- "reset in %lu seconds\n", iop_watchdog_timeout());
+ pr_crit("Device closed unexpectedly - reset in %lu seconds\n",
+ iop_watchdog_timeout());
}
clear_bit(WDT_IN_USE, &wdt_status);
@@ -238,8 +240,7 @@ static int __init iop_wdt_init(void)
with an open */
ret = misc_register(&iop_wdt_miscdev);
if (ret == 0)
- printk(KERN_INFO "iop watchdog timer: timeout %lu sec\n",
- iop_watchdog_timeout());
+ pr_info("timeout %lu sec\n", iop_watchdog_timeout());
return ret;
}
@@ -252,7 +253,7 @@ static void __exit iop_wdt_exit(void)
module_init(iop_wdt_init);
module_exit(iop_wdt_exit);
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index 8d2d8502d3e8..f4cce6d66a55 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -20,6 +20,8 @@
* software is provided AS-IS with no warranties.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -33,6 +35,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
+#define DEBUG
#define NAME "it8712f_wdt"
MODULE_AUTHOR("Jorge Boncompte - DTI2 <jorge@dti2.net>");
@@ -45,8 +48,8 @@ static int margin = 60; /* in seconds */
module_param(margin, int, 0);
MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
static unsigned long wdt_open;
@@ -158,10 +161,10 @@ static void it8712f_wdt_update_margin(void)
*/
if (units <= max_units) {
config |= WDT_UNIT_SEC; /* else UNIT is MINUTES */
- printk(KERN_INFO NAME ": timer margin %d seconds\n", units);
+ pr_info("timer margin %d seconds\n", units);
} else {
units /= 60;
- printk(KERN_INFO NAME ": timer margin %d minutes\n", units);
+ pr_info("timer margin %d minutes\n", units);
}
superio_outb(config, WDT_CONFIG);
@@ -184,7 +187,7 @@ static int it8712f_wdt_enable(void)
if (ret)
return ret;
- printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
+ pr_debug("enabling watchdog timer\n");
superio_select(LDN_GPIO);
superio_outb(wdt_control_reg, WDT_CONTROL);
@@ -204,7 +207,7 @@ static int it8712f_wdt_disable(void)
if (ret)
return ret;
- printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+ pr_debug("disabling watchdog timer\n");
superio_select(LDN_GPIO);
superio_outb(0, WDT_CONFIG);
@@ -331,12 +334,10 @@ static int it8712f_wdt_open(struct inode *inode, struct file *file)
static int it8712f_wdt_release(struct inode *inode, struct file *file)
{
if (expect_close != 42) {
- printk(KERN_WARNING NAME
- ": watchdog device closed unexpectedly, will not"
- " disable the watchdog timer\n");
+ pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
} else if (!nowayout) {
if (it8712f_wdt_disable())
- printk(KERN_WARNING NAME "Watchdog disable failed\n");
+ pr_warn("Watchdog disable failed\n");
}
expect_close = 0;
clear_bit(0, &wdt_open);
@@ -374,13 +375,13 @@ static int __init it8712f_wdt_find(unsigned short *address)
superio_select(LDN_GAME);
superio_outb(1, ACT_REG);
if (!(superio_inb(ACT_REG) & 0x01)) {
- printk(KERN_ERR NAME ": Device not activated, skipping\n");
+ pr_err("Device not activated, skipping\n");
goto exit;
}
*address = superio_inw(BASE_REG);
if (*address == 0) {
- printk(KERN_ERR NAME ": Base address not set, skipping\n");
+ pr_err("Base address not set, skipping\n");
goto exit;
}
@@ -394,8 +395,7 @@ static int __init it8712f_wdt_find(unsigned short *address)
if (margin > (max_units * 60))
margin = (max_units * 60);
- printk(KERN_INFO NAME ": Found IT%04xF chip revision %d - "
- "using DogFood address 0x%x\n",
+ pr_info("Found IT%04xF chip revision %d - using DogFood address 0x%x\n",
chip_type, revision, *address);
exit:
@@ -411,27 +411,26 @@ static int __init it8712f_wdt_init(void)
return -ENODEV;
if (!request_region(address, 1, "IT8712F Watchdog")) {
- printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+ pr_warn("watchdog I/O region busy\n");
return -EBUSY;
}
err = it8712f_wdt_disable();
if (err) {
- printk(KERN_ERR NAME ": unable to disable watchdog timer.\n");
+ pr_err("unable to disable watchdog timer\n");
goto out;
}
err = register_reboot_notifier(&it8712f_wdt_notifier);
if (err) {
- printk(KERN_ERR NAME ": unable to register reboot notifier\n");
+ pr_err("unable to register reboot notifier\n");
goto out;
}
err = misc_register(&it8712f_wdt_miscdev);
if (err) {
- printk(KERN_ERR NAME
- ": cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, err);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, err);
goto reboot_out;
}
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index a2d9a1266a23..8a741bcb5124 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -29,6 +29,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -43,11 +45,9 @@
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <asm/system.h>
#define WATCHDOG_VERSION "1.14"
#define WATCHDOG_NAME "IT87 WDT"
-#define PFX WATCHDOG_NAME ": "
#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
#define WD_MAGIC 'V'
@@ -142,7 +142,7 @@ static int nogameport = DEFAULT_NOGAMEPORT;
static int exclusive = DEFAULT_EXCLUSIVE;
static int timeout = DEFAULT_TIMEOUT;
static int testmode = DEFAULT_TESTMODE;
-static int nowayout = DEFAULT_NOWAYOUT;
+static bool nowayout = DEFAULT_NOWAYOUT;
module_param(nogameport, int, 0);
MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
@@ -156,7 +156,7 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
module_param(testmode, int, 0);
MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
__MODULE_STRING(DEFAULT_TESTMODE));
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
__MODULE_STRING(WATCHDOG_NOWAYOUT));
@@ -428,8 +428,7 @@ static int wdt_release(struct inode *inode, struct file *file)
clear_bit(WDTS_TIMER_RUN, &wdt_status);
} else {
wdt_keepalive();
- printk(KERN_CRIT PFX
- "unexpected close, not stopping watchdog!\n");
+ pr_crit("unexpected close, not stopping watchdog!\n");
}
}
clear_bit(WDTS_DEV_OPEN, &wdt_status);
@@ -621,16 +620,14 @@ static int __init it87_wdt_init(void)
try_gameport = 0;
break;
case IT8705_ID:
- printk(KERN_ERR PFX
- "Unsupported Chip found, Chip %04x Revision %02x\n",
+ pr_err("Unsupported Chip found, Chip %04x Revision %02x\n",
chip_type, chip_rev);
return -ENODEV;
case NO_DEV_ID:
- printk(KERN_ERR PFX "no device\n");
+ pr_err("no device\n");
return -ENODEV;
default:
- printk(KERN_ERR PFX
- "Unknown Chip found, Chip %04x Revision %04x\n",
+ pr_err("Unknown Chip found, Chip %04x Revision %04x\n",
chip_type, chip_rev);
return -ENODEV;
}
@@ -663,13 +660,11 @@ static int __init it87_wdt_init(void)
if (!test_bit(WDTS_USE_GP, &wdt_status)) {
if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
if (gp_rreq_fail)
- printk(KERN_ERR PFX
- "I/O Address 0x%04x and 0x%04x"
- " already in use\n", base, CIR_BASE);
+ pr_err("I/O Address 0x%04x and 0x%04x already in use\n",
+ base, CIR_BASE);
else
- printk(KERN_ERR PFX
- "I/O Address 0x%04x already in use\n",
- CIR_BASE);
+ pr_err("I/O Address 0x%04x already in use\n",
+ CIR_BASE);
rc = -EIO;
goto err_out;
}
@@ -688,9 +683,8 @@ static int __init it87_wdt_init(void)
if (timeout < 1 || timeout > max_units * 60) {
timeout = DEFAULT_TIMEOUT;
- printk(KERN_WARNING PFX
- "Timeout value out of range, use default %d sec\n",
- DEFAULT_TIMEOUT);
+ pr_warn("Timeout value out of range, use default %d sec\n",
+ DEFAULT_TIMEOUT);
}
if (timeout > max_units)
@@ -698,16 +692,14 @@ static int __init it87_wdt_init(void)
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR PFX
- "Cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("Cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "Cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ pr_err("Cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
goto err_out_reboot;
}
@@ -722,9 +714,8 @@ static int __init it87_wdt_init(void)
outb(0x09, CIR_IER(base));
}
- printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. "
- "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
- "nogameport=%d)\n", chip_type, chip_rev, timeout,
+ pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n",
+ chip_type, chip_rev, timeout,
nowayout, testmode, exclusive, nogameport);
superio_exit();
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
index 084f71aa855a..3f047a58d3ae 100644
--- a/drivers/watchdog/ixp2000_wdt.c
+++ b/drivers/watchdog/ixp2000_wdt.c
@@ -16,6 +16,8 @@
* warranty of any kind, whether express or implied.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -29,7 +31,7 @@
#include <linux/uaccess.h>
#include <mach/hardware.h>
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status;
static DEFINE_SPINLOCK(wdt_lock);
@@ -158,8 +160,7 @@ static int ixp2000_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable();
else
- printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
- "timer will not stop\n");
+ pr_crit("Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
@@ -185,7 +186,7 @@ static struct miscdevice ixp2000_wdt_miscdev = {
static int __init ixp2000_wdt_init(void)
{
if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
- printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
+ pr_info("Unable to use IXP2000 watchdog due to IXP2800 erratum #25\n");
return -EIO;
}
wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
@@ -206,7 +207,7 @@ MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c
index 4fc2e9ac26f7..5580b4fff7fe 100644
--- a/drivers/watchdog/ixp4xx_wdt.c
+++ b/drivers/watchdog/ixp4xx_wdt.c
@@ -13,6 +13,8 @@
* warranty of any kind, whether express or implied.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -25,7 +27,7 @@
#include <linux/uaccess.h>
#include <mach/hardware.h>
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status;
static unsigned long boot_status;
@@ -147,8 +149,7 @@ static int ixp4xx_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable();
else
- printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
- "timer will not stop\n");
+ pr_crit("Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
@@ -176,8 +177,7 @@ static int __init ixp4xx_wdt_init(void)
int ret;
if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
- printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected"
- " - watchdog disabled\n");
+ pr_err("Rev. A0 IXP42x CPU detected - watchdog disabled\n");
return -ENODEV;
}
@@ -185,8 +185,7 @@ static int __init ixp4xx_wdt_init(void)
WDIOF_CARDRESET : 0;
ret = misc_register(&ixp4xx_wdt_miscdev);
if (ret == 0)
- printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec\n",
- heartbeat);
+ pr_info("timer heartbeat %d sec\n", heartbeat);
return ret;
}
@@ -205,7 +204,7 @@ MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index 17ef300bccc5..978615ef899d 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -17,18 +17,15 @@
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>
-#include <linux/bitops.h>
#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/err.h>
#include <asm/mach-jz4740/timer.h>
@@ -41,9 +38,6 @@
#define JZ_WDT_CLOCK_RTC 0x2
#define JZ_WDT_CLOCK_EXT 0x4
-#define WDT_IN_USE 0
-#define WDT_OK_TO_CLOSE 1
-
#define JZ_WDT_CLOCK_DIV_SHIFT 3
#define JZ_WDT_CLOCK_DIV_1 (0 << JZ_WDT_CLOCK_DIV_SHIFT)
@@ -56,32 +50,44 @@
#define DEFAULT_HEARTBEAT 5
#define MAX_HEARTBEAT 2048
-static struct {
- void __iomem *base;
- struct resource *mem;
- struct clk *rtc_clk;
- unsigned long status;
-} jz4740_wdt;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-static int heartbeat = DEFAULT_HEARTBEAT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
+module_param(heartbeat, uint, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat period in seconds from 1 to "
+ __MODULE_STRING(MAX_HEARTBEAT) ", default "
+ __MODULE_STRING(DEFAULT_HEARTBEAT));
+struct jz4740_wdt_drvdata {
+ struct watchdog_device wdt;
+ void __iomem *base;
+ struct clk *rtc_clk;
+};
-static void jz4740_wdt_service(void)
+static int jz4740_wdt_ping(struct watchdog_device *wdt_dev)
{
- writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+ struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
+
+ writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
+ return 0;
}
-static void jz4740_wdt_set_heartbeat(int new_heartbeat)
+static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ unsigned int new_timeout)
{
+ struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
unsigned int rtc_clk_rate;
unsigned int timeout_value;
unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
- heartbeat = new_heartbeat;
-
- rtc_clk_rate = clk_get_rate(jz4740_wdt.rtc_clk);
+ rtc_clk_rate = clk_get_rate(drvdata->rtc_clk);
- timeout_value = rtc_clk_rate * heartbeat;
+ timeout_value = rtc_clk_rate * new_timeout;
while (timeout_value > 0xffff) {
if (clock_div == JZ_WDT_CLOCK_DIV_1024) {
/* Requested timeout too high;
@@ -93,199 +99,115 @@ static void jz4740_wdt_set_heartbeat(int new_heartbeat)
clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
}
- writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
- writew(clock_div, jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+ writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+ writew(clock_div, drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
- writew((u16)timeout_value, jz4740_wdt.base + JZ_REG_WDT_TIMER_DATA);
- writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+ writew((u16)timeout_value, drvdata->base + JZ_REG_WDT_TIMER_DATA);
+ writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
writew(clock_div | JZ_WDT_CLOCK_RTC,
- jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+ drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
- writeb(0x1, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
-}
+ writeb(0x1, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
-static void jz4740_wdt_enable(void)
-{
- jz4740_timer_enable_watchdog();
- jz4740_wdt_set_heartbeat(heartbeat);
-}
-
-static void jz4740_wdt_disable(void)
-{
- jz4740_timer_disable_watchdog();
- writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+ wdt_dev->timeout = new_timeout;
+ return 0;
}
-static int jz4740_wdt_open(struct inode *inode, struct file *file)
+static int jz4740_wdt_start(struct watchdog_device *wdt_dev)
{
- if (test_and_set_bit(WDT_IN_USE, &jz4740_wdt.status))
- return -EBUSY;
-
- jz4740_wdt_enable();
+ jz4740_timer_enable_watchdog();
+ jz4740_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
- return nonseekable_open(inode, file);
+ return 0;
}
-static ssize_t jz4740_wdt_write(struct file *file, const char *data,
- size_t len, loff_t *ppos)
+static int jz4740_wdt_stop(struct watchdog_device *wdt_dev)
{
- if (len) {
- size_t i;
-
- clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
- for (i = 0; i != len; i++) {
- char c;
+ struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
- if (get_user(c, data + i))
- return -EFAULT;
-
- if (c == 'V')
- set_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
- }
- jz4740_wdt_service();
- }
+ jz4740_timer_disable_watchdog();
+ writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
- return len;
+ return 0;
}
-static const struct watchdog_info ident = {
- .options = WDIOF_KEEPALIVEPING,
+static const struct watchdog_info jz4740_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.identity = "jz4740 Watchdog",
};
-static long jz4740_wdt_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int ret = -ENOTTY;
- int heartbeat_seconds;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info *)arg, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(0, (int *)arg);
- break;
-
- case WDIOC_KEEPALIVE:
- jz4740_wdt_service();
- return 0;
-
- case WDIOC_SETTIMEOUT:
- if (get_user(heartbeat_seconds, (int __user *)arg))
- return -EFAULT;
-
- jz4740_wdt_set_heartbeat(heartbeat_seconds);
- return 0;
-
- case WDIOC_GETTIMEOUT:
- return put_user(heartbeat, (int *)arg);
-
- default:
- break;
- }
-
- return ret;
-}
-
-static int jz4740_wdt_release(struct inode *inode, struct file *file)
-{
- jz4740_wdt_service();
-
- if (test_and_clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status))
- jz4740_wdt_disable();
-
- clear_bit(WDT_IN_USE, &jz4740_wdt.status);
- return 0;
-}
-
-static const struct file_operations jz4740_wdt_fops = {
+static const struct watchdog_ops jz4740_wdt_ops = {
.owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = jz4740_wdt_write,
- .unlocked_ioctl = jz4740_wdt_ioctl,
- .open = jz4740_wdt_open,
- .release = jz4740_wdt_release,
-};
-
-static struct miscdevice jz4740_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &jz4740_wdt_fops,
+ .start = jz4740_wdt_start,
+ .stop = jz4740_wdt_stop,
+ .ping = jz4740_wdt_ping,
+ .set_timeout = jz4740_wdt_set_timeout,
};
static int __devinit jz4740_wdt_probe(struct platform_device *pdev)
{
- int ret = 0, size;
- struct resource *res;
- struct device *dev = &pdev->dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(dev, "failed to get memory region resource\n");
- return -ENXIO;
+ struct jz4740_wdt_drvdata *drvdata;
+ struct watchdog_device *jz4740_wdt;
+ struct resource *res;
+ int ret;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct jz4740_wdt_drvdata),
+ GFP_KERNEL);
+ if (!drvdata) {
+ dev_err(&pdev->dev, "Unable to alloacate watchdog device\n");
+ return -ENOMEM;
}
- size = resource_size(res);
- jz4740_wdt.mem = request_mem_region(res->start, size, pdev->name);
- if (jz4740_wdt.mem == NULL) {
- dev_err(dev, "failed to get memory region\n");
- return -EBUSY;
- }
+ if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+ heartbeat = DEFAULT_HEARTBEAT;
- jz4740_wdt.base = ioremap_nocache(res->start, size);
- if (jz4740_wdt.base == NULL) {
- dev_err(dev, "failed to map memory region\n");
+ jz4740_wdt = &drvdata->wdt;
+ jz4740_wdt->info = &jz4740_wdt_info;
+ jz4740_wdt->ops = &jz4740_wdt_ops;
+ jz4740_wdt->timeout = heartbeat;
+ jz4740_wdt->min_timeout = 1;
+ jz4740_wdt->max_timeout = MAX_HEARTBEAT;
+ watchdog_set_nowayout(jz4740_wdt, nowayout);
+ watchdog_set_drvdata(jz4740_wdt, drvdata);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ drvdata->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (drvdata->base == NULL) {
ret = -EBUSY;
- goto err_release_region;
+ goto err_out;
}
- jz4740_wdt.rtc_clk = clk_get(NULL, "rtc");
- if (IS_ERR(jz4740_wdt.rtc_clk)) {
- dev_err(dev, "cannot find RTC clock\n");
- ret = PTR_ERR(jz4740_wdt.rtc_clk);
- goto err_iounmap;
+ drvdata->rtc_clk = clk_get(NULL, "rtc");
+ if (IS_ERR(drvdata->rtc_clk)) {
+ dev_err(&pdev->dev, "cannot find RTC clock\n");
+ ret = PTR_ERR(drvdata->rtc_clk);
+ goto err_out;
}
- ret = misc_register(&jz4740_wdt_miscdev);
- if (ret < 0) {
- dev_err(dev, "cannot register misc device\n");
+ ret = watchdog_register_device(&drvdata->wdt);
+ if (ret < 0)
goto err_disable_clk;
- }
+ platform_set_drvdata(pdev, drvdata);
return 0;
err_disable_clk:
- clk_put(jz4740_wdt.rtc_clk);
-err_iounmap:
- iounmap(jz4740_wdt.base);
-err_release_region:
- release_mem_region(jz4740_wdt.mem->start,
- resource_size(jz4740_wdt.mem));
+ clk_put(drvdata->rtc_clk);
+err_out:
return ret;
}
-
static int __devexit jz4740_wdt_remove(struct platform_device *pdev)
{
- jz4740_wdt_disable();
- misc_deregister(&jz4740_wdt_miscdev);
- clk_put(jz4740_wdt.rtc_clk);
+ struct jz4740_wdt_drvdata *drvdata = platform_get_drvdata(pdev);
- iounmap(jz4740_wdt.base);
- jz4740_wdt.base = NULL;
-
- release_mem_region(jz4740_wdt.mem->start,
- resource_size(jz4740_wdt.mem));
- jz4740_wdt.mem = NULL;
+ jz4740_wdt_stop(&drvdata->wdt);
+ watchdog_unregister_device(&drvdata->wdt);
+ clk_put(drvdata->rtc_clk);
return 0;
}
-
static struct platform_driver jz4740_wdt_driver = {
.probe = jz4740_wdt_probe,
.remove = __devexit_p(jz4740_wdt_remove),
@@ -299,13 +221,6 @@ module_platform_driver(jz4740_wdt_driver);
MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
MODULE_DESCRIPTION("jz4740 Watchdog Driver");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat,
- "Watchdog heartbeat period in seconds from 1 to "
- __MODULE_STRING(MAX_HEARTBEAT) ", default "
- __MODULE_STRING(DEFAULT_HEARTBEAT));
-
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:jz4740-wdt");
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 51757a520e8f..59e75d9a6b7f 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -8,6 +8,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -28,14 +30,14 @@
#define WDT_MAX_TIME 171 /* seconds */
static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
__MODULE_STRING(WDT_DEFAULT_TIME) ")");
#ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#endif
@@ -233,8 +235,8 @@ static int __devinit ks8695wdt_probe(struct platform_device *pdev)
if (res)
return res;
- printk(KERN_INFO "KS8695 Watchdog Timer enabled (%d seconds%s)\n",
- wdt_time, nowayout ? ", nowayout" : "");
+ pr_info("KS8695 Watchdog Timer enabled (%d seconds%s)\n",
+ wdt_time, nowayout ? ", nowayout" : "");
return 0;
}
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
index d3a63be2e28d..a9593a3a32a0 100644
--- a/drivers/watchdog/lantiq_wdt.c
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -7,6 +7,8 @@
* Based on EP93xx wdt driver
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@@ -38,7 +40,7 @@
#define LTQ_WDT_DIVIDER 0x40000
#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static void __iomem *ltq_wdt_membase;
static unsigned long ltq_io_region_clk_rate;
@@ -160,7 +162,7 @@ ltq_wdt_release(struct inode *inode, struct file *file)
if (ltq_wdt_ok_to_close)
ltq_wdt_disable();
else
- pr_err("ltq_wdt: watchdog closed without warning\n");
+ pr_err("watchdog closed without warning\n");
ltq_wdt_ok_to_close = 0;
clear_bit(0, &ltq_wdt_in_use);
@@ -249,7 +251,7 @@ exit_ltq_wdt(void)
module_init(init_ltq_wdt);
module_exit(exit_ltq_wdt);
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
diff --git a/drivers/watchdog/m54xx_wdt.c b/drivers/watchdog/m54xx_wdt.c
index 4d43286074aa..663cad86c633 100644
--- a/drivers/watchdog/m54xx_wdt.c
+++ b/drivers/watchdog/m54xx_wdt.c
@@ -16,6 +16,8 @@
* warranty of any kind, whether express or implied.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -32,7 +34,7 @@
#include <asm/m54xxsim.h>
#include <asm/m54xxgpt.h>
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */
static unsigned long wdt_status;
@@ -166,8 +168,7 @@ static int m54xx_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable();
else {
- printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
- "timer will not stop\n");
+ pr_crit("Device closed unexpectedly - timer will not stop\n");
wdt_keepalive();
}
clear_bit(WDT_IN_USE, &wdt_status);
@@ -196,11 +197,10 @@ static int __init m54xx_wdt_init(void)
{
if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
"Coldfire M54xx Watchdog")) {
- printk(KERN_WARNING
- "Coldfire M54xx Watchdog : I/O region busy\n");
+ pr_warn("I/O region busy\n");
return -EBUSY;
}
- printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
+ pr_info("driver is loaded\n");
return misc_register(&m54xx_wdt_miscdev);
}
@@ -220,7 +220,7 @@ MODULE_DESCRIPTION("Coldfire M54xx Watchdog");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index 1332b838cc58..bf84f788e592 100644
--- a/drivers/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -28,6 +28,8 @@
* Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -43,7 +45,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
/* ports */
#define ZF_IOBASE 0x218
@@ -93,8 +94,8 @@ MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -141,10 +142,10 @@ static unsigned long next_heartbeat;
#define ZF_CTIMEOUT 0xffff
#ifndef ZF_DEBUG
-# define dprintk(format, args...)
+#define dprintk(format, args...)
#else
-# define dprintk(format, args...) printk(KERN_DEBUG PFX \
- ":%s:%d: " format, __func__, __LINE__ , ## args)
+#define dprintk(format, args...) \
+ pr_debug(":%s:%d: " format, __func__, __LINE__ , ## args)
#endif
@@ -203,7 +204,7 @@ static void zf_timer_off(void)
zf_set_control(ctrl_reg);
spin_unlock_irqrestore(&zf_port_lock, flags);
- printk(KERN_INFO PFX ": Watchdog timer is now disabled\n");
+ pr_info("Watchdog timer is now disabled\n");
}
@@ -233,7 +234,7 @@ static void zf_timer_on(void)
zf_set_control(ctrl_reg);
spin_unlock_irqrestore(&zf_port_lock, flags);
- printk(KERN_INFO PFX ": Watchdog timer is now enabled\n");
+ pr_info("Watchdog timer is now enabled\n");
}
@@ -263,7 +264,7 @@ static void zf_ping(unsigned long data)
mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
} else
- printk(KERN_CRIT PFX ": I will reset your machine\n");
+ pr_crit("I will reset your machine\n");
}
static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
@@ -342,8 +343,7 @@ static int zf_close(struct inode *inode, struct file *file)
zf_timer_off();
else {
del_timer(&zf_timer);
- printk(KERN_ERR PFX ": device file closed unexpectedly. "
- "Will not stop the WDT!\n");
+ pr_err("device file closed unexpectedly. Will not stop the WDT!\n");
}
clear_bit(0, &zf_is_open);
zf_expect_close = 0;
@@ -390,19 +390,18 @@ static void __init zf_show_action(int act)
{
static const char * const str[] = { "RESET", "SMI", "NMI", "SCI" };
- printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]);
+ pr_info("Watchdog using action = %s\n", str[act]);
}
static int __init zf_init(void)
{
int ret;
- printk(KERN_INFO PFX
- ": MachZ ZF-Logic Watchdog driver initializing.\n");
+ pr_info("MachZ ZF-Logic Watchdog driver initializing\n");
ret = zf_get_ZFL_version();
if (!ret || ret == 0xffff) {
- printk(KERN_WARNING PFX ": no ZF-Logic found\n");
+ pr_warn("no ZF-Logic found\n");
return -ENODEV;
}
@@ -414,23 +413,20 @@ static int __init zf_init(void)
zf_show_action(action);
if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) {
- printk(KERN_ERR "cannot reserve I/O ports at %d\n",
- ZF_IOBASE);
+ pr_err("cannot reserve I/O ports at %d\n", ZF_IOBASE);
ret = -EBUSY;
goto no_region;
}
ret = register_reboot_notifier(&zf_notifier);
if (ret) {
- printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
- ret);
+ pr_err("can't register reboot notifier (err=%d)\n", ret);
goto no_reboot;
}
ret = misc_register(&zf_miscdev);
if (ret) {
- printk(KERN_ERR "can't misc_register on minor=%d\n",
- WATCHDOG_MINOR);
+ pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
goto no_misc;
}
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index af63ecfbfa6f..8f4a74e91619 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -18,23 +18,20 @@
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
-#include <linux/uaccess.h>
#include <linux/io.h>
-#include <linux/device.h>
#include <linux/slab.h>
#define DEFAULT_HEARTBEAT 60
#define MAX_HEARTBEAT 60
-static int heartbeat = DEFAULT_HEARTBEAT;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
/*
* Memory mapping: a single byte, 3 first lower bits to select bit 3
@@ -45,15 +42,8 @@ static int nowayout = WATCHDOG_NOWAYOUT;
static DEFINE_SPINLOCK(io_lock);
-static unsigned long wdt_status;
-#define WDT_IN_USE 0
-#define WDT_RUNNING 1
-#define WDT_OK_TO_CLOSE 2
-
static int nodelay;
-static struct resource *wdt_mem;
static void __iomem *wdt_base;
-static struct platform_device *max63xx_pdev;
/*
* The timeout values used are actually the absolute minimum the chip
@@ -117,7 +107,7 @@ max63xx_select_timeout(struct max63xx_timeout *table, int value)
return NULL;
}
-static void max63xx_wdt_ping(void)
+static int max63xx_wdt_ping(struct watchdog_device *wdd)
{
u8 val;
@@ -129,15 +119,14 @@ static void max63xx_wdt_ping(void)
__raw_writeb(val & ~MAX6369_WDI, wdt_base);
spin_unlock(&io_lock);
+ return 0;
}
-static void max63xx_wdt_enable(struct max63xx_timeout *entry)
+static int max63xx_wdt_start(struct watchdog_device *wdd)
{
+ struct max63xx_timeout *entry = watchdog_get_drvdata(wdd);
u8 val;
- if (test_and_set_bit(WDT_RUNNING, &wdt_status))
- return;
-
spin_lock(&io_lock);
val = __raw_readb(wdt_base);
@@ -149,10 +138,11 @@ static void max63xx_wdt_enable(struct max63xx_timeout *entry)
/* check for a edge triggered startup */
if (entry->tdelay == 0)
- max63xx_wdt_ping();
+ max63xx_wdt_ping(wdd);
+ return 0;
}
-static void max63xx_wdt_disable(void)
+static int max63xx_wdt_stop(struct watchdog_device *wdd)
{
u8 val;
@@ -164,113 +154,29 @@ static void max63xx_wdt_disable(void)
__raw_writeb(val, wdt_base);
spin_unlock(&io_lock);
-
- clear_bit(WDT_RUNNING, &wdt_status);
-}
-
-static int max63xx_wdt_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(WDT_IN_USE, &wdt_status))
- return -EBUSY;
-
- max63xx_wdt_enable(current_timeout);
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- return nonseekable_open(inode, file);
-}
-
-static ssize_t max63xx_wdt_write(struct file *file, const char *data,
- size_t len, loff_t *ppos)
-{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
-
- if (c == 'V')
- set_bit(WDT_OK_TO_CLOSE, &wdt_status);
- }
- }
-
- max63xx_wdt_ping();
- }
-
- return len;
+ return 0;
}
-static const struct watchdog_info ident = {
- .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+static const struct watchdog_info max63xx_wdt_info = {
+ .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.identity = "max63xx Watchdog",
};
-static long max63xx_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret = -ENOTTY;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info *)arg, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(0, (int *)arg);
- break;
-
- case WDIOC_KEEPALIVE:
- max63xx_wdt_ping();
- ret = 0;
- break;
-
- case WDIOC_GETTIMEOUT:
- ret = put_user(heartbeat, (int *)arg);
- break;
- }
- return ret;
-}
-
-static int max63xx_wdt_release(struct inode *inode, struct file *file)
-{
- if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
- max63xx_wdt_disable();
- else
- dev_crit(&max63xx_pdev->dev,
- "device closed unexpectedly - timer will not stop\n");
-
- clear_bit(WDT_IN_USE, &wdt_status);
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- return 0;
-}
-
-static const struct file_operations max63xx_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = max63xx_wdt_write,
- .unlocked_ioctl = max63xx_wdt_ioctl,
- .open = max63xx_wdt_open,
- .release = max63xx_wdt_release,
+static const struct watchdog_ops max63xx_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = max63xx_wdt_start,
+ .stop = max63xx_wdt_stop,
+ .ping = max63xx_wdt_ping,
};
-static struct miscdevice max63xx_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &max63xx_wdt_fops,
+static struct watchdog_device max63xx_wdt_dev = {
+ .info = &max63xx_wdt_info,
+ .ops = &max63xx_wdt_ops,
};
static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
{
- int ret = 0;
- int size;
- struct device *dev = &pdev->dev;
+ struct resource *wdt_mem;
struct max63xx_timeout *table;
table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
@@ -278,68 +184,34 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
- dev_info(dev, "requesting %ds heartbeat\n", heartbeat);
+ dev_info(&pdev->dev, "requesting %ds heartbeat\n", heartbeat);
current_timeout = max63xx_select_timeout(table, heartbeat);
if (!current_timeout) {
- dev_err(dev, "unable to satisfy heartbeat request\n");
+ dev_err(&pdev->dev, "unable to satisfy heartbeat request\n");
return -EINVAL;
}
- dev_info(dev, "using %ds heartbeat with %ds initial delay\n",
+ dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
current_timeout->twd, current_timeout->tdelay);
heartbeat = current_timeout->twd;
- max63xx_pdev = pdev;
-
wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (wdt_mem == NULL) {
- dev_err(dev, "failed to get memory region resource\n");
- return -ENOENT;
- }
+ wdt_base = devm_request_and_ioremap(&pdev->dev, wdt_mem);
+ if (!wdt_base)
+ return -ENOMEM;
- size = resource_size(wdt_mem);
- if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
- dev_err(dev, "failed to get memory region\n");
- return -ENOENT;
- }
-
- wdt_base = ioremap(wdt_mem->start, size);
- if (!wdt_base) {
- dev_err(dev, "failed to map memory region\n");
- ret = -ENOMEM;
- goto out_request;
- }
+ max63xx_wdt_dev.timeout = heartbeat;
+ watchdog_set_nowayout(&max63xx_wdt_dev, nowayout);
+ watchdog_set_drvdata(&max63xx_wdt_dev, current_timeout);
- ret = misc_register(&max63xx_wdt_miscdev);
- if (ret < 0) {
- dev_err(dev, "cannot register misc device\n");
- goto out_unmap;
- }
-
- return 0;
-
-out_unmap:
- iounmap(wdt_base);
-out_request:
- release_mem_region(wdt_mem->start, size);
- wdt_mem = NULL;
-
- return ret;
+ return watchdog_register_device(&max63xx_wdt_dev);
}
static int __devexit max63xx_wdt_remove(struct platform_device *pdev)
{
- misc_deregister(&max63xx_wdt_miscdev);
- if (wdt_mem) {
- release_mem_region(wdt_mem->start, resource_size(wdt_mem));
- wdt_mem = NULL;
- }
-
- if (wdt_base)
- iounmap(wdt_base);
-
+ watchdog_unregister_device(&max63xx_wdt_dev);
return 0;
}
@@ -375,7 +247,7 @@ MODULE_PARM_DESC(heartbeat,
__MODULE_STRING(MAX_HEARTBEAT) ", default "
__MODULE_STRING(DEFAULT_HEARTBEAT));
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/mixcomwd.c b/drivers/watchdog/mixcomwd.c
index bc820d16699a..37e4b52dbce9 100644
--- a/drivers/watchdog/mixcomwd.c
+++ b/drivers/watchdog/mixcomwd.c
@@ -39,9 +39,10 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define VERSION "0.6"
#define WATCHDOG_NAME "mixcomwd"
-#define PFX WATCHDOG_NAME ": "
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -107,8 +108,8 @@ static int mixcomwd_timer_alive;
static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun, 0, 0);
static char expect_close;
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -156,15 +157,13 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
{
if (expect_close == 42) {
if (mixcomwd_timer_alive) {
- printk(KERN_ERR PFX
- "release called while internal timer alive");
+ pr_err("release called while internal timer alive\n");
return -EBUSY;
}
mixcomwd_timer_alive = 1;
mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
} else
- printk(KERN_CRIT PFX
- "WDT device closed unexpectedly. WDT will not stop!\n");
+ pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
clear_bit(0, &mixcomwd_opened);
expect_close = 0;
@@ -274,22 +273,19 @@ static int __init mixcomwd_init(void)
}
if (!found) {
- printk(KERN_ERR PFX
- "No card detected, or port not available.\n");
+ pr_err("No card detected, or port not available\n");
return -ENODEV;
}
ret = misc_register(&mixcomwd_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto error_misc_register_watchdog;
}
- printk(KERN_INFO
- "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
- VERSION, watchdog_port);
+ pr_info("MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
+ VERSION, watchdog_port);
return 0;
@@ -303,8 +299,7 @@ static void __exit mixcomwd_exit(void)
{
if (!nowayout) {
if (mixcomwd_timer_alive) {
- printk(KERN_WARNING PFX "I quit now, hardware will"
- " probably reboot!\n");
+ pr_warn("I quit now, hardware will probably reboot!\n");
del_timer_sync(&mixcomwd_timer);
mixcomwd_timer_alive = 0;
}
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 20feb4d3d791..40f7bf1f8654 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -17,6 +17,8 @@
* option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -60,8 +62,8 @@ module_param(reset, bool, 0);
MODULE_PARM_DESC(reset,
"Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -96,7 +98,7 @@ static void mpc8xxx_wdt_timer_ping(unsigned long arg)
static void mpc8xxx_wdt_pr_warn(const char *msg)
{
- pr_crit("mpc8xxx_wdt: %s, expect the %s soon!\n", msg,
+ pr_crit("%s, expect the %s soon!\n", msg,
reset ? "reset" : "machine check exception");
}
@@ -209,7 +211,7 @@ static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev)
enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN;
if (!enabled && wdt_type->hw_enabled) {
- pr_info("mpc8xxx_wdt: could not be enabled in software\n");
+ pr_info("could not be enabled in software\n");
ret = -ENOSYS;
goto err_unmap;
}
@@ -226,9 +228,8 @@ static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev)
goto err_unmap;
#endif
- pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d "
- "(%d seconds)\n", reset ? "reset" : "interrupt", timeout,
- timeout_sec);
+ pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n",
+ reset ? "reset" : "interrupt", timeout, timeout_sec);
/*
* If the watchdog was previously enabled or we're running on
@@ -303,7 +304,7 @@ static int mpc8xxx_wdt_init_late(void)
ret = misc_register(&mpc8xxx_wdt_miscdev);
if (ret) {
pr_err("cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ WATCHDOG_MINOR, ret);
return ret;
}
return 0;
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index 82ccd36e2c90..7c741dc987bd 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -19,6 +19,9 @@
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -44,7 +47,7 @@ struct mpcore_wdt {
char expect_close;
};
-static struct platform_device *mpcore_wdt_dev;
+static struct platform_device *mpcore_wdt_pdev;
static DEFINE_SPINLOCK(wdt_lock);
#define TIMER_MARGIN 60
@@ -54,8 +57,8 @@ MODULE_PARM_DESC(mpcore_margin,
"MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default="
__MODULE_STRING(TIMER_MARGIN) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -148,7 +151,7 @@ static int mpcore_wdt_set_heartbeat(int t)
*/
static int mpcore_wdt_open(struct inode *inode, struct file *file)
{
- struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_dev);
+ struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_pdev);
if (test_and_set_bit(0, &wdt->timer_alive))
return -EBUSY;
@@ -298,9 +301,9 @@ static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd,
* System shutdown handler. Turn off the watchdog if we're
* restarting or halting the system.
*/
-static void mpcore_wdt_shutdown(struct platform_device *dev)
+static void mpcore_wdt_shutdown(struct platform_device *pdev)
{
- struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+ struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
mpcore_wdt_stop(wdt);
@@ -324,99 +327,79 @@ static struct miscdevice mpcore_wdt_miscdev = {
.fops = &mpcore_wdt_fops,
};
-static int __devinit mpcore_wdt_probe(struct platform_device *dev)
+static int __devinit mpcore_wdt_probe(struct platform_device *pdev)
{
struct mpcore_wdt *wdt;
struct resource *res;
int ret;
/* We only accept one device, and it must have an id of -1 */
- if (dev->id != -1)
+ if (pdev->id != -1)
return -ENODEV;
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENODEV;
- goto err_out;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
- wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
- if (!wdt) {
- ret = -ENOMEM;
- goto err_out;
+ wdt = devm_kzalloc(&pdev->dev, sizeof(struct mpcore_wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ wdt->dev = &pdev->dev;
+ wdt->irq = platform_get_irq(pdev, 0);
+ if (wdt->irq >= 0) {
+ ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
+ "mpcore_wdt", wdt);
+ if (ret) {
+ dev_printk(KERN_ERR, wdt->dev,
+ "cannot register IRQ%d for watchdog\n",
+ wdt->irq);
+ return ret;
+ }
}
- wdt->dev = &dev->dev;
- wdt->irq = platform_get_irq(dev, 0);
- if (wdt->irq < 0) {
- ret = -ENXIO;
- goto err_free;
- }
- wdt->base = ioremap(res->start, resource_size(res));
- if (!wdt->base) {
- ret = -ENOMEM;
- goto err_free;
- }
+ wdt->base = devm_ioremap(wdt->dev, res->start, resource_size(res));
+ if (!wdt->base)
+ return -ENOMEM;
- mpcore_wdt_miscdev.parent = &dev->dev;
+ mpcore_wdt_miscdev.parent = &pdev->dev;
ret = misc_register(&mpcore_wdt_miscdev);
if (ret) {
dev_printk(KERN_ERR, wdt->dev,
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
- goto err_misc;
- }
-
- ret = request_irq(wdt->irq, mpcore_wdt_fire, 0, "mpcore_wdt", wdt);
- if (ret) {
- dev_printk(KERN_ERR, wdt->dev,
- "cannot register IRQ%d for watchdog\n", wdt->irq);
- goto err_irq;
+ return ret;
}
mpcore_wdt_stop(wdt);
- platform_set_drvdata(dev, wdt);
- mpcore_wdt_dev = dev;
+ platform_set_drvdata(pdev, wdt);
+ mpcore_wdt_pdev = pdev;
return 0;
-
-err_irq:
- misc_deregister(&mpcore_wdt_miscdev);
-err_misc:
- iounmap(wdt->base);
-err_free:
- kfree(wdt);
-err_out:
- return ret;
}
-static int __devexit mpcore_wdt_remove(struct platform_device *dev)
+static int __devexit mpcore_wdt_remove(struct platform_device *pdev)
{
- struct mpcore_wdt *wdt = platform_get_drvdata(dev);
-
- platform_set_drvdata(dev, NULL);
+ platform_set_drvdata(pdev, NULL);
misc_deregister(&mpcore_wdt_miscdev);
- mpcore_wdt_dev = NULL;
+ mpcore_wdt_pdev = NULL;
- free_irq(wdt->irq, wdt);
- iounmap(wdt->base);
- kfree(wdt);
return 0;
}
#ifdef CONFIG_PM
-static int mpcore_wdt_suspend(struct platform_device *dev, pm_message_t msg)
+static int mpcore_wdt_suspend(struct platform_device *pdev, pm_message_t msg)
{
- struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+ struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
mpcore_wdt_stop(wdt); /* Turn the WDT off */
return 0;
}
-static int mpcore_wdt_resume(struct platform_device *dev)
+static int mpcore_wdt_resume(struct platform_device *pdev)
{
- struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+ struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
/* re-activate timer */
if (test_bit(0, &wdt->timer_alive))
mpcore_wdt_start(wdt);
@@ -442,9 +425,6 @@ static struct platform_driver mpcore_wdt_driver = {
},
};
-static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. "
- "mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n";
-
static int __init mpcore_wdt_init(void)
{
/*
@@ -453,11 +433,12 @@ static int __init mpcore_wdt_init(void)
*/
if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
mpcore_wdt_set_heartbeat(TIMER_MARGIN);
- printk(KERN_INFO "mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
+ pr_info("mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
TIMER_MARGIN);
}
- printk(banner, mpcore_noboot, mpcore_margin, nowayout);
+ pr_info("MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n",
+ mpcore_noboot, mpcore_margin, nowayout);
return platform_driver_register(&mpcore_wdt_driver);
}
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
index 97f8a48d8b78..c53d025e70df 100644
--- a/drivers/watchdog/mv64x60_wdt.c
+++ b/drivers/watchdog/mv64x60_wdt.c
@@ -15,6 +15,8 @@
* or implied.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -58,8 +60,8 @@ static unsigned int bus_clk;
static char expect_close;
static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -100,7 +102,7 @@ static void mv64x60_wdt_handler_enable(void)
if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
MV64x60_WDC_ENABLE_SHIFT)) {
mv64x60_wdt_service();
- printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+ pr_notice("watchdog activated\n");
}
}
@@ -108,7 +110,7 @@ static void mv64x60_wdt_handler_disable(void)
{
if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
MV64x60_WDC_ENABLE_SHIFT))
- printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+ pr_notice("watchdog deactivated\n");
}
static void mv64x60_wdt_set_timeout(unsigned int timeout)
@@ -139,8 +141,7 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file)
if (expect_close == 42)
mv64x60_wdt_handler_disable();
else {
- printk(KERN_CRIT
- "mv64x60_wdt: unexpected close, not stopping timer!\n");
+ pr_crit("unexpected close, not stopping timer!\n");
mv64x60_wdt_service();
}
expect_close = 0;
@@ -308,7 +309,7 @@ static struct platform_driver mv64x60_wdt_driver = {
static int __init mv64x60_wdt_init(void)
{
- printk(KERN_INFO "MV64x60 watchdog driver\n");
+ pr_info("MV64x60 watchdog driver\n");
return platform_driver_register(&mv64x60_wdt_driver);
}
diff --git a/drivers/watchdog/nuc900_wdt.c b/drivers/watchdog/nuc900_wdt.c
index 529085b8b8fb..ea4c7448b754 100644
--- a/drivers/watchdog/nuc900_wdt.c
+++ b/drivers/watchdog/nuc900_wdt.c
@@ -55,8 +55,8 @@ module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c
index 809f41c30c44..6bbb9efc6125 100644
--- a/drivers/watchdog/nv_tco.c
+++ b/drivers/watchdog/nv_tco.c
@@ -21,6 +21,8 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -41,7 +43,6 @@
#define TCO_VERSION "0.01"
#define TCO_MODULE_NAME "NV_TCO"
#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
/* internal variables */
static unsigned int tcobase;
@@ -60,8 +61,8 @@ module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, "
"default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
" (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -169,8 +170,7 @@ static int nv_tco_release(struct inode *inode, struct file *file)
if (tco_expect_close == 42) {
tco_timer_stop();
} else {
- printk(KERN_CRIT PFX "Unexpected close, not stopping "
- "watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
tco_timer_keepalive();
}
clear_bit(0, &timer_alive);
@@ -323,15 +323,14 @@ static unsigned char __devinit nv_tco_getdevice(void)
val &= 0xffff;
if (val == 0x0001 || val == 0x0000) {
/* Something is wrong here, bar isn't setup */
- printk(KERN_ERR PFX "failed to get tcobase address\n");
+ pr_err("failed to get tcobase address\n");
return 0;
}
val &= 0xff00;
tcobase = val + 0x40;
if (!request_region(tcobase, 0x10, "NV TCO")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- tcobase);
+ pr_err("I/O address 0x%04x already in use\n", tcobase);
return 0;
}
@@ -347,7 +346,7 @@ static unsigned char __devinit nv_tco_getdevice(void)
/* Disable SMI caused by TCO */
if (!request_region(MCP51_SMI_EN(tcobase), 4, "NV TCO")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ pr_err("I/O address 0x%04x already in use\n",
MCP51_SMI_EN(tcobase));
goto out;
}
@@ -357,7 +356,7 @@ static unsigned char __devinit nv_tco_getdevice(void)
val = inl(MCP51_SMI_EN(tcobase));
release_region(MCP51_SMI_EN(tcobase), 4);
if (val & MCP51_SMI_EN_TCO) {
- printk(KERN_ERR PFX "Could not disable SMI caused by TCO\n");
+ pr_err("Could not disable SMI caused by TCO\n");
goto out;
}
@@ -367,8 +366,7 @@ static unsigned char __devinit nv_tco_getdevice(void)
pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
if (!(val & MCP51_SMBUS_SETUP_B_TCO_REBOOT)) {
- printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot "
- "disabled by hardware\n");
+ pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
goto out;
}
@@ -387,8 +385,8 @@ static int __devinit nv_tco_init(struct platform_device *dev)
return -ENODEV;
/* Check to see if last reboot was due to watchdog timeout */
- printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
- inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
+ pr_info("Watchdog reboot %sdetected\n",
+ inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
/* Clear out the old status */
outl(TCO_STS_RESET, TCO_STS(tcobase));
@@ -400,14 +398,14 @@ static int __devinit nv_tco_init(struct platform_device *dev)
if (tco_timer_set_heartbeat(heartbeat)) {
heartbeat = WATCHDOG_HEARTBEAT;
tco_timer_set_heartbeat(heartbeat);
- printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, "
- "using %d\n", heartbeat);
+ pr_info("heartbeat value must be 2<heartbeat<39, using %d\n",
+ heartbeat);
}
ret = misc_register(&nv_tco_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
- "(err=%d)\n", WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_region;
}
@@ -415,8 +413,8 @@ static int __devinit nv_tco_init(struct platform_device *dev)
tco_timer_stop();
- printk(KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec "
- "(nowayout=%d)\n", tcobase, heartbeat, nowayout);
+ pr_info("initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
+ tcobase, heartbeat, nowayout);
return 0;
@@ -439,8 +437,7 @@ static void __devexit nv_tco_cleanup(void)
pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
if (val & MCP51_SMBUS_SETUP_B_TCO_REBOOT) {
- printk(KERN_CRIT PFX "Couldn't unset REBOOT bit. Machine may "
- "soon reset\n");
+ pr_crit("Couldn't unset REBOOT bit. Machine may soon reset\n");
}
/* Deregister */
@@ -483,8 +480,7 @@ static int __init nv_tco_init_module(void)
{
int err;
- printk(KERN_INFO PFX "NV TCO WatchDog Timer Driver v%s\n",
- TCO_VERSION);
+ pr_info("NV TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
err = platform_driver_register(&nv_tco_driver);
if (err)
@@ -508,7 +504,7 @@ static void __exit nv_tco_cleanup_module(void)
{
platform_device_unregister(nv_tco_platform_device);
platform_driver_unregister(&nv_tco_driver);
- printk(KERN_INFO PFX "NV TCO Watchdog Module Unloaded.\n");
+ pr_info("NV TCO Watchdog Module Unloaded\n");
}
module_init(nv_tco_init_module);
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index 7c0d8630e641..461208831428 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -52,6 +52,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/watchdog.h>
@@ -95,8 +97,8 @@ MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat in seconds. (0 < heartbeat, default="
__MODULE_STRING(WD_TIMO) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, S_IRUGO);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -201,7 +203,7 @@ static void __init octeon_wdt_build_stage1(void)
uasm_resolve_relocs(relocs, labels);
len = (int)(p - nmi_stage1_insns);
- pr_debug("Synthesized NMI stage 1 handler (%d instructions).\n", len);
+ pr_debug("Synthesized NMI stage 1 handler (%d instructions)\n", len);
pr_debug("\t.set push\n");
pr_debug("\t.set noreorder\n");
@@ -627,7 +629,7 @@ static int octeon_wdt_release(struct inode *inode, struct file *file)
do_coundown = 0;
octeon_wdt_ping();
} else {
- pr_crit("octeon_wdt: WDT device closed unexpectedly. WDT will not stop!\n");
+ pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
}
clear_bit(0, &octeon_wdt_is_open);
expect_close = 0;
@@ -684,12 +686,12 @@ static int __init octeon_wdt_init(void)
octeon_wdt_calc_parameters(heartbeat);
- pr_info("octeon_wdt: Initial granularity %d Sec.\n", timeout_sec);
+ pr_info("Initial granularity %d Sec\n", timeout_sec);
ret = misc_register(&octeon_wdt_miscdev);
if (ret) {
- pr_err("octeon_wdt: cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto out;
}
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index f359ab85c3bc..55d2f66dbeae 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -19,6 +19,8 @@
* know the wdt reset interval
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -99,7 +101,7 @@ static void xwdt_stop(void)
iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
spin_unlock(&spinlock);
- printk(KERN_INFO PFX "Stopped!\n");
+ pr_info("Stopped!\n");
}
static void xwdt_keepalive(void)
@@ -165,7 +167,7 @@ static int xwdt_open(struct inode *inode, struct file *file)
__module_get(THIS_MODULE);
xwdt_start();
- printk(KERN_INFO PFX "Started...\n");
+ pr_info("Started...\n");
return nonseekable_open(inode, file);
}
@@ -175,8 +177,7 @@ static int xwdt_release(struct inode *inode, struct file *file)
if (expect_close == 42) {
xwdt_stop();
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
xwdt_keepalive();
}
@@ -300,22 +301,20 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
"clock-frequency", NULL);
if (pfreq == NULL) {
- printk(KERN_WARNING PFX
- "The watchdog clock frequency cannot be obtained!\n");
+ pr_warn("The watchdog clock frequency cannot be obtained!\n");
no_timeout = 1;
}
rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
if (rc) {
- printk(KERN_WARNING PFX "invalid address!\n");
+ pr_warn("invalid address!\n");
return rc;
}
tmptr = (u32 *)of_get_property(pdev->dev.of_node,
"xlnx,wdt-interval", NULL);
if (tmptr == NULL) {
- printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-interval\""
- " not found in device tree!\n");
+ pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
no_timeout = 1;
} else {
xdev.wdt_interval = *tmptr;
@@ -324,8 +323,7 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
tmptr = (u32 *)of_get_property(pdev->dev.of_node,
"xlnx,wdt-enable-once", NULL);
if (tmptr == NULL) {
- printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-enable-once\""
- " not found in device tree!\n");
+ pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
xdev.nowayout = WATCHDOG_NOWAYOUT;
}
@@ -339,20 +337,20 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
if (!request_mem_region(xdev.res.start,
xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
rc = -ENXIO;
- printk(KERN_ERR PFX "memory request failure!\n");
+ pr_err("memory request failure!\n");
goto err_out;
}
xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
if (xdev.base == NULL) {
rc = -ENOMEM;
- printk(KERN_ERR PFX "ioremap failure!\n");
+ pr_err("ioremap failure!\n");
goto release_mem;
}
rc = xwdt_selftest();
if (rc == XWT_TIMER_FAILED) {
- printk(KERN_ERR PFX "SelfTest routine error!\n");
+ pr_err("SelfTest routine error!\n");
goto unmap_io;
}
@@ -360,20 +358,17 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
rc = misc_register(&xwdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- xwdt_miscdev.minor, rc);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ xwdt_miscdev.minor, rc);
goto unmap_io;
}
if (no_timeout)
- printk(KERN_INFO PFX
- "driver loaded (timeout=? sec, nowayout=%d)\n",
- xdev.nowayout);
+ pr_info("driver loaded (timeout=? sec, nowayout=%d)\n",
+ xdev.nowayout);
else
- printk(KERN_INFO PFX
- "driver loaded (timeout=%d sec, nowayout=%d)\n",
- timeout, xdev.nowayout);
+ pr_info("driver loaded (timeout=%d sec, nowayout=%d)\n",
+ timeout, xdev.nowayout);
expect_close = 0;
clear_bit(0, &driver_open);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index d19ff5145e82..8285d65cd207 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -26,6 +26,8 @@
* Use the driver model and standard identifiers; handle bigger timeouts.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -183,7 +185,7 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
pm_runtime_put_sync(wdev->dev);
#else
- printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
+ pr_crit("Unexpected close, not stopping!\n");
#endif
wdev->omap_wdt_users = 0;
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 4ad78f868515..788aa158e78c 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -10,6 +10,8 @@
* warranty of any kind, whether express or implied.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -28,18 +30,19 @@
/*
* Watchdog timer block registers.
*/
-#define TIMER_CTRL (TIMER_VIRT_BASE + 0x0000)
+#define TIMER_CTRL 0x0000
#define WDT_EN 0x0010
-#define WDT_VAL (TIMER_VIRT_BASE + 0x0024)
+#define WDT_VAL 0x0024
#define WDT_MAX_CYCLE_COUNT 0xffffffff
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
static unsigned int wdt_max_duration; /* (seconds) */
static unsigned int wdt_tclk;
+static void __iomem *wdt_reg;
static unsigned long wdt_status;
static DEFINE_SPINLOCK(wdt_lock);
@@ -48,7 +51,7 @@ static void orion_wdt_ping(void)
spin_lock(&wdt_lock);
/* Reload watchdog duration */
- writel(wdt_tclk * heartbeat, WDT_VAL);
+ writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL);
spin_unlock(&wdt_lock);
}
@@ -60,7 +63,7 @@ static void orion_wdt_enable(void)
spin_lock(&wdt_lock);
/* Set watchdog duration */
- writel(wdt_tclk * heartbeat, WDT_VAL);
+ writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL);
/* Clear watchdog timer interrupt */
reg = readl(BRIDGE_CAUSE);
@@ -68,9 +71,9 @@ static void orion_wdt_enable(void)
writel(reg, BRIDGE_CAUSE);
/* Enable watchdog timer */
- reg = readl(TIMER_CTRL);
+ reg = readl(wdt_reg + TIMER_CTRL);
reg |= WDT_EN;
- writel(reg, TIMER_CTRL);
+ writel(reg, wdt_reg + TIMER_CTRL);
/* Enable reset on watchdog */
reg = readl(RSTOUTn_MASK);
@@ -92,9 +95,9 @@ static void orion_wdt_disable(void)
writel(reg, RSTOUTn_MASK);
/* Disable watchdog timer */
- reg = readl(TIMER_CTRL);
+ reg = readl(wdt_reg + TIMER_CTRL);
reg &= ~WDT_EN;
- writel(reg, TIMER_CTRL);
+ writel(reg, wdt_reg + TIMER_CTRL);
spin_unlock(&wdt_lock);
}
@@ -102,7 +105,7 @@ static void orion_wdt_disable(void)
static int orion_wdt_get_timeleft(int *time_left)
{
spin_lock(&wdt_lock);
- *time_left = readl(WDT_VAL) / wdt_tclk;
+ *time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
spin_unlock(&wdt_lock);
return 0;
}
@@ -209,8 +212,7 @@ static int orion_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
orion_wdt_disable();
else
- printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
- "timer will not stop\n");
+ pr_crit("Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
@@ -236,15 +238,20 @@ static struct miscdevice orion_wdt_miscdev = {
static int __devinit orion_wdt_probe(struct platform_device *pdev)
{
struct orion_wdt_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
int ret;
if (pdata) {
wdt_tclk = pdata->tclk;
} else {
- printk(KERN_ERR "Orion Watchdog misses platform data\n");
+ pr_err("misses platform data\n");
return -ENODEV;
}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ wdt_reg = ioremap(res->start, resource_size(res));
+
if (orion_wdt_miscdev.parent)
return -EBUSY;
orion_wdt_miscdev.parent = &pdev->dev;
@@ -257,8 +264,8 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev)
if (ret)
return ret;
- printk(KERN_INFO "Orion Watchdog Timer: Initial timeout %d sec%s\n",
- heartbeat, nowayout ? ", nowayout" : "");
+ pr_info("Initial timeout %d sec%s\n",
+ heartbeat, nowayout ? ", nowayout" : "");
return 0;
}
@@ -302,7 +309,7 @@ MODULE_DESCRIPTION("Orion Processor Watchdog");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index e78d89986768..5afb89b48650 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -18,6 +18,8 @@
* Release 1.1
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
@@ -33,7 +35,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
/* #define DEBUG 1 */
@@ -42,7 +43,6 @@
#define VERSION "1.1"
#define MODNAME "pc87413 WDT"
-#define PFX MODNAME ": "
#define DPFX MODNAME " - DEBUG: "
#define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */
@@ -65,7 +65,7 @@ static char expect_close; /* is the close expected? */
static DEFINE_SPINLOCK(io_lock); /* to guard us from io races */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
/* -- Low level function ----------------------------------------*/
@@ -87,7 +87,7 @@ static inline void pc87413_select_wdt_out(void)
outb_p(cr_data, WDT_DATA_IO_PORT);
#ifdef DEBUG
- printk(KERN_INFO DPFX
+ pr_info(DPFX
"Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n",
cr_data);
#endif
@@ -111,7 +111,7 @@ static inline void pc87413_enable_swc(void)
outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */
#ifdef DEBUG
- printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n");
+ pr_info(DPFX "pc87413 - Enable SWC functions\n");
#endif
}
@@ -132,7 +132,7 @@ static void pc87413_get_swc_base_addr(void)
swc_base_addr = (addr_h << 8) + addr_l;
#ifdef DEBUG
- printk(KERN_INFO DPFX
+ pr_info(DPFX
"Read SWC I/O Base Address: low %d, high %d, res %d\n",
addr_l, addr_h, swc_base_addr);
#endif
@@ -145,7 +145,7 @@ static inline void pc87413_swc_bank3(void)
/* Step 4: Select Bank3 of SWC */
outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
#ifdef DEBUG
- printk(KERN_INFO DPFX "Select Bank3 of SWC\n");
+ pr_info(DPFX "Select Bank3 of SWC\n");
#endif
}
@@ -156,7 +156,7 @@ static inline void pc87413_programm_wdto(char pc87413_time)
/* Step 5: Programm WDTO, Twd. */
outb_p(pc87413_time, swc_base_addr + WDTO);
#ifdef DEBUG
- printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);
+ pr_info(DPFX "Set WDTO to %d minutes\n", pc87413_time);
#endif
}
@@ -167,7 +167,7 @@ static inline void pc87413_enable_wden(void)
/* Step 6: Enable WDEN */
outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
#ifdef DEBUG
- printk(KERN_INFO DPFX "Enable WDEN\n");
+ pr_info(DPFX "Enable WDEN\n");
#endif
}
@@ -177,7 +177,7 @@ static inline void pc87413_enable_sw_wd_tren(void)
/* Enable SW_WD_TREN */
outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
#ifdef DEBUG
- printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");
+ pr_info(DPFX "Enable SW_WD_TREN\n");
#endif
}
@@ -188,7 +188,7 @@ static inline void pc87413_disable_sw_wd_tren(void)
/* Disable SW_WD_TREN */
outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
#ifdef DEBUG
- printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");
+ pr_info(DPFX "pc87413 - Disable SW_WD_TREN\n");
#endif
}
@@ -199,7 +199,7 @@ static inline void pc87413_enable_sw_wd_trg(void)
/* Enable SW_WD_TRG */
outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
#ifdef DEBUG
- printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");
+ pr_info(DPFX "pc87413 - Enable SW_WD_TRG\n");
#endif
}
@@ -210,7 +210,7 @@ static inline void pc87413_disable_sw_wd_trg(void)
/* Disable SW_WD_TRG */
outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
#ifdef DEBUG
- printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");
+ pr_info(DPFX "Disable SW_WD_TRG\n");
#endif
}
@@ -284,8 +284,7 @@ static int pc87413_open(struct inode *inode, struct file *file)
/* Reload and activate timer */
pc87413_refresh();
- printk(KERN_INFO MODNAME
- "Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
+ pr_info("Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
return nonseekable_open(inode, file);
}
@@ -308,11 +307,9 @@ static int pc87413_release(struct inode *inode, struct file *file)
if (expect_close == 42) {
pc87413_disable();
- printk(KERN_INFO MODNAME
- "Watchdog disabled, sleeping again...\n");
+ pr_info("Watchdog disabled, sleeping again...\n");
} else {
- printk(KERN_CRIT MODNAME
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
pc87413_refresh();
}
clear_bit(0, &timer_enabled);
@@ -428,7 +425,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd,
case WDIOC_KEEPALIVE:
pc87413_refresh();
#ifdef DEBUG
- printk(KERN_INFO DPFX "keepalive\n");
+ pr_info(DPFX "keepalive\n");
#endif
return 0;
case WDIOC_SETTIMEOUT:
@@ -508,7 +505,7 @@ static int __init pc87413_init(void)
{
int ret;
- printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
+ pr_info("Version " VERSION " at io 0x%X\n",
WDT_INDEX_IO_PORT);
if (!request_muxed_region(io, 2, MODNAME))
@@ -516,26 +513,23 @@ static int __init pc87413_init(void)
ret = register_reboot_notifier(&pc87413_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
}
ret = misc_register(&pc87413_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto reboot_unreg;
}
- printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
+ pr_info("initialized. timeout=%d min\n", timeout);
pc87413_select_wdt_out();
pc87413_enable_swc();
pc87413_get_swc_base_addr();
if (!request_region(swc_base_addr, 0x20, MODNAME)) {
- printk(KERN_ERR PFX
- "cannot request SWC region at 0x%x\n", swc_base_addr);
+ pr_err("cannot request SWC region at 0x%x\n", swc_base_addr);
ret = -EBUSY;
goto misc_unreg;
}
@@ -568,14 +562,14 @@ static void __exit pc87413_exit(void)
/* Stop the timer before we leave */
if (!nowayout) {
pc87413_disable();
- printk(KERN_INFO MODNAME "Watchdog disabled.\n");
+ pr_info("Watchdog disabled\n");
}
misc_deregister(&pc87413_miscdev);
unregister_reboot_notifier(&pc87413_notifier);
release_region(swc_base_addr, 0x20);
- printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
+ pr_info("watchdog component driver removed\n");
}
module_init(pc87413_init);
@@ -597,7 +591,7 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in minutes (default="
__MODULE_STRING(DEFAULT_TIMEOUT) ").");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c
index 06f7922606c0..75694cf24f86 100644
--- a/drivers/watchdog/pcwd.c
+++ b/drivers/watchdog/pcwd.c
@@ -51,6 +51,8 @@
* http://www.pcwatchdog.com/
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
#include <linux/types.h> /* For standard types (like size_t) */
@@ -75,7 +77,6 @@
#define WATCHDOG_DATE "18 Feb 2007"
#define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
#define WATCHDOG_NAME "pcwd"
-#define PFX WATCHDOG_NAME ": "
#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "\n"
/*
@@ -203,8 +204,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
"(2 <= heartbeat <= 7200 or 0=delay-time from dip-switches, default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -220,8 +221,7 @@ static int send_isa_command(int cmd)
int port0, last_port0; /* Double read for stabilising */
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n",
- cmd);
+ pr_debug("sending following data cmd=0x%02x\n", cmd);
/* The WCMD bit must be 1 and the command is only 4 bits in size */
control_status = (cmd & 0x0F) | WD_WCMD;
@@ -240,9 +240,8 @@ static int send_isa_command(int cmd)
}
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "received following data for "
- "cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
- cmd, port0, last_port0);
+ pr_debug("received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
+ cmd, port0, last_port0);
return port0;
}
@@ -271,8 +270,7 @@ static int set_command_mode(void)
pcwd_private.command_mode = found;
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "command_mode=%d\n",
- pcwd_private.command_mode);
+ pr_debug("command_mode=%d\n", pcwd_private.command_mode);
return found;
}
@@ -288,8 +286,7 @@ static void unset_command_mode(void)
pcwd_private.command_mode = 0;
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "command_mode=%d\n",
- pcwd_private.command_mode);
+ pr_debug("command_mode=%d\n", pcwd_private.command_mode);
}
static inline void pcwd_check_temperature_support(void)
@@ -336,17 +333,14 @@ static void pcwd_show_card_info(void)
/* Get some extra info from the hardware (in command/debug/diag mode) */
if (pcwd_private.revision == PCWD_REVISION_A)
- printk(KERN_INFO PFX
- "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
- pcwd_private.io_addr);
+ pr_info("ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
+ pcwd_private.io_addr);
else if (pcwd_private.revision == PCWD_REVISION_C) {
pcwd_get_firmware();
- printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port "
- "0x%04x (Firmware version: %s)\n",
+ pr_info("ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
pcwd_private.io_addr, pcwd_private.fw_ver_str);
option_switches = pcwd_get_option_switches();
- printk(KERN_INFO PFX "Option switches (0x%02x): "
- "Temperature Reset Enable=%s, Power On Delay=%s\n",
+ pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
option_switches,
((option_switches & 0x10) ? "ON" : "OFF"),
((option_switches & 0x08) ? "ON" : "OFF"));
@@ -359,22 +353,18 @@ static void pcwd_show_card_info(void)
}
if (pcwd_private.supports_temp)
- printk(KERN_INFO PFX "Temperature Option Detected\n");
+ pr_info("Temperature Option Detected\n");
if (pcwd_private.boot_status & WDIOF_CARDRESET)
- printk(KERN_INFO PFX
- "Previous reboot was caused by the card\n");
+ pr_info("Previous reboot was caused by the card\n");
if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
- printk(KERN_EMERG PFX
- "Card senses a CPU Overheat. Panicking!\n");
- printk(KERN_EMERG PFX
- "CPU Overheat\n");
+ pr_emerg("Card senses a CPU Overheat. Panicking!\n");
+ pr_emerg("CPU Overheat\n");
}
if (pcwd_private.boot_status == 0)
- printk(KERN_INFO PFX
- "No previous trip detected - Cold boot or reset\n");
+ pr_info("No previous trip detected - Cold boot or reset\n");
}
static void pcwd_timer_ping(unsigned long data)
@@ -404,8 +394,7 @@ static void pcwd_timer_ping(unsigned long data)
spin_unlock(&pcwd_private.io_lock);
} else {
- printk(KERN_WARNING PFX
- "Heartbeat lost! Will not ping the watchdog\n");
+ pr_warn("Heartbeat lost! Will not ping the watchdog\n");
}
}
@@ -426,13 +415,13 @@ static int pcwd_start(void)
stat_reg = inb_p(pcwd_private.io_addr + 2);
spin_unlock(&pcwd_private.io_lock);
if (stat_reg & WD_WDIS) {
- printk(KERN_INFO PFX "Could not start watchdog\n");
+ pr_info("Could not start watchdog\n");
return -EIO;
}
}
if (debug >= VERBOSE)
- printk(KERN_DEBUG PFX "Watchdog started\n");
+ pr_debug("Watchdog started\n");
return 0;
}
@@ -454,13 +443,13 @@ static int pcwd_stop(void)
stat_reg = inb_p(pcwd_private.io_addr + 2);
spin_unlock(&pcwd_private.io_lock);
if ((stat_reg & WD_WDIS) == 0) {
- printk(KERN_INFO PFX "Could not stop watchdog\n");
+ pr_info("Could not stop watchdog\n");
return -EIO;
}
}
if (debug >= VERBOSE)
- printk(KERN_DEBUG PFX "Watchdog stopped\n");
+ pr_debug("Watchdog stopped\n");
return 0;
}
@@ -471,7 +460,7 @@ static int pcwd_keepalive(void)
pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+ pr_debug("Watchdog keepalive signal send\n");
return 0;
}
@@ -484,8 +473,7 @@ static int pcwd_set_heartbeat(int t)
heartbeat = t;
if (debug >= VERBOSE)
- printk(KERN_DEBUG PFX "New heartbeat: %d\n",
- heartbeat);
+ pr_debug("New heartbeat: %d\n", heartbeat);
return 0;
}
@@ -518,8 +506,7 @@ static int pcwd_get_status(int *status)
if (control_status & WD_T110) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
- printk(KERN_INFO PFX
- "Temperature overheat trip!\n");
+ pr_info("Temperature overheat trip!\n");
kernel_power_off();
}
}
@@ -530,8 +517,7 @@ static int pcwd_get_status(int *status)
if (control_status & WD_REVC_TTRP) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
- printk(KERN_INFO PFX
- "Temperature overheat trip!\n");
+ pr_info("Temperature overheat trip!\n");
kernel_power_off();
}
}
@@ -548,16 +534,14 @@ static int pcwd_clear_status(void)
spin_lock(&pcwd_private.io_lock);
if (debug >= VERBOSE)
- printk(KERN_INFO PFX
- "clearing watchdog trip status\n");
+ pr_info("clearing watchdog trip status\n");
control_status = inb_p(pcwd_private.io_addr + 1);
if (debug >= DEBUG) {
- printk(KERN_DEBUG PFX "status was: 0x%02x\n",
- control_status);
- printk(KERN_DEBUG PFX "sending: 0x%02x\n",
- (control_status & WD_REVC_R2DS));
+ pr_debug("status was: 0x%02x\n", control_status);
+ pr_debug("sending: 0x%02x\n",
+ (control_status & WD_REVC_R2DS));
}
/* clear reset status & Keep Relay 2 disable state as it is */
@@ -588,8 +572,7 @@ static int pcwd_get_temperature(int *temperature)
spin_unlock(&pcwd_private.io_lock);
if (debug >= DEBUG) {
- printk(KERN_DEBUG PFX "temperature is: %d F\n",
- *temperature);
+ pr_debug("temperature is: %d F\n", *temperature);
}
return 0;
@@ -720,8 +703,7 @@ static int pcwd_close(struct inode *inode, struct file *file)
if (expect_close == 42)
pcwd_stop();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
pcwd_keepalive();
}
expect_close = 0;
@@ -828,11 +810,10 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
int retval;
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
- id);
+ pr_debug("pcwd_isa_match id=%d\n", id);
if (!request_region(base_addr, 4, "PCWD")) {
- printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
+ pr_info("Port 0x%04x unavailable\n", base_addr);
return 0;
}
@@ -870,21 +851,20 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
int ret;
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n",
- id);
+ pr_debug("pcwd_isa_probe id=%d\n", id);
cards_found++;
if (cards_found == 1)
- printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n",
+ pr_info("v%s Ken Hollis (kenji@bitgate.com)\n",
WATCHDOG_VERSION);
if (cards_found > 1) {
- printk(KERN_ERR PFX "This driver only supports 1 device\n");
+ pr_err("This driver only supports 1 device\n");
return -ENODEV;
}
if (pcwd_ioports[id] == 0x0000) {
- printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+ pr_err("No I/O-Address for card detected\n");
return -ENODEV;
}
pcwd_private.io_addr = pcwd_ioports[id];
@@ -896,8 +876,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
if (!request_region(pcwd_private.io_addr,
(pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- pcwd_private.io_addr);
+ pr_err("I/O address 0x%04x already in use\n",
+ pcwd_private.io_addr);
ret = -EIO;
goto error_request_region;
}
@@ -932,30 +912,27 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
if not reset to the default */
if (pcwd_set_heartbeat(heartbeat)) {
pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
- printk(KERN_INFO PFX
- "heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
- WATCHDOG_HEARTBEAT);
+ pr_info("heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
+ WATCHDOG_HEARTBEAT);
}
if (pcwd_private.supports_temp) {
ret = misc_register(&temp_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- TEMP_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ TEMP_MINOR, ret);
goto error_misc_register_temp;
}
}
ret = misc_register(&pcwd_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto error_misc_register_watchdog;
}
- printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+ pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
return 0;
@@ -975,8 +952,7 @@ error_request_region:
static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
{
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n",
- id);
+ pr_debug("pcwd_isa_remove id=%d\n", id);
if (!pcwd_private.io_addr)
return 1;
@@ -1000,8 +976,7 @@ static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
{
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n",
- id);
+ pr_debug("pcwd_isa_shutdown id=%d\n", id);
pcwd_stop();
}
@@ -1025,7 +1000,7 @@ static int __init pcwd_init_module(void)
static void __exit pcwd_cleanup_module(void)
{
isa_unregister_driver(&pcwd_isa_driver);
- printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+ pr_info("Watchdog Module Unloaded\n");
}
module_init(pcwd_init_module);
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index b8d14f88f0b5..c891399bed6a 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -32,6 +32,8 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
#include <linux/types.h> /* For standard types (like size_t) */
@@ -54,8 +56,7 @@
#define WATCHDOG_VERSION "1.03"
#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
#define WATCHDOG_NAME "pcwd_pci"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION
/* Stuff for the PCI ID's */
#ifndef PCI_VENDOR_ID_QUICKLOGIC
@@ -145,8 +146,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
"(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -159,8 +160,8 @@ static int send_command(int cmd, int *msb, int *lsb)
int got_response, count;
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "sending following data "
- "cmd=0x%02x msb=0x%02x lsb=0x%02x\n", cmd, *msb, *lsb);
+ pr_debug("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x\n",
+ cmd, *msb, *lsb);
spin_lock(&pcipcwd_private.io_lock);
/* If a command requires data it should be written first.
@@ -185,12 +186,10 @@ static int send_command(int cmd, int *msb, int *lsb)
if (debug >= DEBUG) {
if (got_response) {
- printk(KERN_DEBUG PFX
- "time to process command was: %d ms\n",
- count);
+ pr_debug("time to process command was: %d ms\n",
+ count);
} else {
- printk(KERN_DEBUG PFX
- "card did not respond on command!\n");
+ pr_debug("card did not respond on command!\n");
}
}
@@ -203,9 +202,8 @@ static int send_command(int cmd, int *msb, int *lsb)
inb_p(pcipcwd_private.io_addr + 6);
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "received following data for "
- "cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",
- cmd, *msb, *lsb);
+ pr_debug("received following data for cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",
+ cmd, *msb, *lsb);
}
spin_unlock(&pcipcwd_private.io_lock);
@@ -243,27 +241,23 @@ static void pcipcwd_show_card_info(void)
/* Get switch settings */
option_switches = pcipcwd_get_option_switches();
- printk(KERN_INFO PFX "Found card at port "
- "0x%04x (Firmware: %s) %s temp option\n",
+ pr_info("Found card at port 0x%04x (Firmware: %s) %s temp option\n",
(int) pcipcwd_private.io_addr, fw_ver_str,
(pcipcwd_private.supports_temp ? "with" : "without"));
- printk(KERN_INFO PFX "Option switches (0x%02x): "
- "Temperature Reset Enable=%s, Power On Delay=%s\n",
+ pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
option_switches,
((option_switches & 0x10) ? "ON" : "OFF"),
((option_switches & 0x08) ? "ON" : "OFF"));
if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
- printk(KERN_INFO PFX
- "Previous reset was caused by the Watchdog card\n");
+ pr_info("Previous reset was caused by the Watchdog card\n");
if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
- printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
+ pr_info("Card sensed a CPU Overheat\n");
if (pcipcwd_private.boot_status == 0)
- printk(KERN_INFO PFX
- "No previous trip detected - Cold boot or reset\n");
+ pr_info("No previous trip detected - Cold boot or reset\n");
}
static int pcipcwd_start(void)
@@ -278,12 +272,12 @@ static int pcipcwd_start(void)
spin_unlock(&pcipcwd_private.io_lock);
if (stat_reg & WD_PCI_WDIS) {
- printk(KERN_ERR PFX "Card timer not enabled\n");
+ pr_err("Card timer not enabled\n");
return -1;
}
if (debug >= VERBOSE)
- printk(KERN_DEBUG PFX "Watchdog started\n");
+ pr_debug("Watchdog started\n");
return 0;
}
@@ -303,13 +297,12 @@ static int pcipcwd_stop(void)
spin_unlock(&pcipcwd_private.io_lock);
if (!(stat_reg & WD_PCI_WDIS)) {
- printk(KERN_ERR PFX
- "Card did not acknowledge disable attempt\n");
+ pr_err("Card did not acknowledge disable attempt\n");
return -1;
}
if (debug >= VERBOSE)
- printk(KERN_DEBUG PFX "Watchdog stopped\n");
+ pr_debug("Watchdog stopped\n");
return 0;
}
@@ -322,7 +315,7 @@ static int pcipcwd_keepalive(void)
spin_unlock(&pcipcwd_private.io_lock);
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+ pr_debug("Watchdog keepalive signal send\n");
return 0;
}
@@ -340,8 +333,7 @@ static int pcipcwd_set_heartbeat(int t)
heartbeat = t;
if (debug >= VERBOSE)
- printk(KERN_DEBUG PFX "New heartbeat: %d\n",
- heartbeat);
+ pr_debug("New heartbeat: %d\n", heartbeat);
return 0;
}
@@ -357,12 +349,11 @@ static int pcipcwd_get_status(int *status)
if (control_status & WD_PCI_TTRP) {
*status |= WDIOF_OVERHEAT;
if (temp_panic)
- panic(PFX "Temperature overheat trip!\n");
+ panic(KBUILD_MODNAME ": Temperature overheat trip!\n");
}
if (debug >= DEBUG)
- printk(KERN_DEBUG PFX "Control Status #1: 0x%02x\n",
- control_status);
+ pr_debug("Control Status #1: 0x%02x\n", control_status);
return 0;
}
@@ -374,14 +365,14 @@ static int pcipcwd_clear_status(void)
int reset_counter;
if (debug >= VERBOSE)
- printk(KERN_INFO PFX "clearing watchdog trip status & LED\n");
+ pr_info("clearing watchdog trip status & LED\n");
control_status = inb_p(pcipcwd_private.io_addr + 1);
if (debug >= DEBUG) {
- printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);
- printk(KERN_DEBUG PFX "sending: 0x%02x\n",
- (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
+ pr_debug("status was: 0x%02x\n", control_status);
+ pr_debug("sending: 0x%02x\n",
+ (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
}
/* clear trip status & LED and keep mode of relay 2 */
@@ -394,8 +385,7 @@ static int pcipcwd_clear_status(void)
send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);
if (debug >= DEBUG) {
- printk(KERN_DEBUG PFX "reset count was: 0x%02x\n",
- reset_counter);
+ pr_debug("reset count was: 0x%02x\n", reset_counter);
}
return 0;
@@ -418,8 +408,7 @@ static int pcipcwd_get_temperature(int *temperature)
*temperature = (*temperature * 9 / 5) + 32;
if (debug >= DEBUG) {
- printk(KERN_DEBUG PFX "temperature is: %d F\n",
- *temperature);
+ pr_debug("temperature is: %d F\n", *temperature);
}
return 0;
@@ -437,8 +426,7 @@ static int pcipcwd_get_timeleft(int *time_left)
*time_left = (msb << 8) + lsb;
if (debug >= VERBOSE)
- printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
- *time_left);
+ pr_debug("Time left before next reboot: %d\n", *time_left);
return 0;
}
@@ -583,8 +571,7 @@ static int pcipcwd_open(struct inode *inode, struct file *file)
/* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &is_active)) {
if (debug >= VERBOSE)
- printk(KERN_ERR PFX
- "Attempt to open already opened device.\n");
+ pr_err("Attempt to open already opened device\n");
return -EBUSY;
}
@@ -602,8 +589,7 @@ static int pcipcwd_release(struct inode *inode, struct file *file)
if (expect_release == 42) {
pcipcwd_stop();
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
pcipcwd_keepalive();
}
expect_release = 0;
@@ -703,20 +689,20 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
cards_found++;
if (cards_found == 1)
- printk(KERN_INFO PFX DRIVER_VERSION);
+ pr_info("%s\n", DRIVER_VERSION);
if (cards_found > 1) {
- printk(KERN_ERR PFX "This driver only supports 1 device\n");
+ pr_err("This driver only supports 1 device\n");
return -ENODEV;
}
if (pci_enable_device(pdev)) {
- printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+ pr_err("Not possible to enable PCI Device\n");
return -ENODEV;
}
if (pci_resource_start(pdev, 0) == 0x0000) {
- printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+ pr_err("No I/O-Address for card detected\n");
ret = -ENODEV;
goto err_out_disable_device;
}
@@ -725,8 +711,8 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
if (pci_request_regions(pdev, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- (int) pcipcwd_private.io_addr);
+ pr_err("I/O address 0x%04x already in use\n",
+ (int) pcipcwd_private.io_addr);
ret = -EIO;
goto err_out_disable_device;
}
@@ -755,36 +741,33 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
* if not reset to the default */
if (pcipcwd_set_heartbeat(heartbeat)) {
pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
- printk(KERN_INFO PFX
- "heartbeat value must be 0<heartbeat<65536, using %d\n",
+ pr_info("heartbeat value must be 0<heartbeat<65536, using %d\n",
WATCHDOG_HEARTBEAT);
}
ret = register_reboot_notifier(&pcipcwd_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto err_out_release_region;
}
if (pcipcwd_private.supports_temp) {
ret = misc_register(&pcipcwd_temp_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX "cannot register miscdev on "
- "minor=%d (err=%d)\n", TEMP_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ TEMP_MINOR, ret);
goto err_out_unregister_reboot;
}
}
ret = misc_register(&pcipcwd_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto err_out_misc_deregister;
}
- printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+ pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
return 0;
@@ -842,7 +825,7 @@ static void __exit pcipcwd_cleanup_module(void)
{
pci_unregister_driver(&pcipcwd_driver);
- printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+ pr_info("Watchdog Module Unloaded\n");
}
module_init(pcipcwd_init_module);
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index d8de1ddd176a..7b14d1847927 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -24,6 +24,8 @@
* http://www.berkprod.com/ or http://www.pcwatchdog.com/
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
#include <linux/types.h> /* For standard types (like size_t) */
@@ -42,17 +44,23 @@
#include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
-
#ifdef CONFIG_USB_DEBUG
- static int debug = 1;
+static int debug = 1;
#else
- static int debug;
+static int debug;
#endif
/* Use our own dbg macro */
+
#undef dbg
-#define dbg(format, arg...) \
- do { if (debug) printk(KERN_DEBUG PFX format "\n" , ## arg); } while (0)
+#ifndef DEBUG
+#define DEBUG
+#endif
+#define dbg(format, ...) \
+do { \
+ if (debug) \
+ pr_debug(format "\n", ##__VA_ARGS__); \
+} while (0)
/* Module and Version Information */
#define DRIVER_VERSION "1.02"
@@ -60,7 +68,6 @@
#define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
#define DRIVER_LICENSE "GPL"
#define DRIVER_NAME "pcwd_usb"
-#define PFX DRIVER_NAME ": "
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -80,8 +87,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
"(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -220,8 +227,8 @@ static void usb_pcwd_intr_done(struct urb *urb)
resubmit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- printk(KERN_ERR PFX "can't resubmit intr, "
- "usb_submit_urb failed with result %d\n", retval);
+ pr_err("can't resubmit intr, usb_submit_urb failed with result %d\n",
+ retval);
}
static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd,
@@ -284,8 +291,7 @@ static int usb_pcwd_start(struct usb_pcwd_private *usb_pcwd)
&msb, &lsb);
if ((retval == 0) || (lsb == 0)) {
- printk(KERN_ERR PFX
- "Card did not acknowledge enable attempt\n");
+ pr_err("Card did not acknowledge enable attempt\n");
return -1;
}
@@ -303,8 +309,7 @@ static int usb_pcwd_stop(struct usb_pcwd_private *usb_pcwd)
&msb, &lsb);
if ((retval == 0) || (lsb != 0)) {
- printk(KERN_ERR PFX
- "Card did not acknowledge disable attempt\n");
+ pr_err("Card did not acknowledge disable attempt\n");
return -1;
}
@@ -506,8 +511,7 @@ static int usb_pcwd_release(struct inode *inode, struct file *file)
if (expect_release == 42) {
usb_pcwd_stop(usb_pcwd_device);
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
usb_pcwd_keepalive(usb_pcwd_device);
}
expect_release = 0;
@@ -627,7 +631,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
cards_found++;
if (cards_found > 1) {
- printk(KERN_ERR PFX "This driver only supports 1 device\n");
+ pr_err("This driver only supports 1 device\n");
return -ENODEV;
}
@@ -636,8 +640,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
/* check out that we have a HID device */
if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
- printk(KERN_ERR PFX
- "The device isn't a Human Interface Device\n");
+ pr_err("The device isn't a Human Interface Device\n");
return -ENODEV;
}
@@ -646,7 +649,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
if (!usb_endpoint_is_int_in(endpoint)) {
/* we didn't find a Interrupt endpoint with direction IN */
- printk(KERN_ERR PFX "Couldn't find an INTR & IN endpoint\n");
+ pr_err("Couldn't find an INTR & IN endpoint\n");
return -ENODEV;
}
@@ -657,7 +660,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
/* allocate memory for our device and initialize it */
usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
if (usb_pcwd == NULL) {
- printk(KERN_ERR PFX "Out of memory\n");
+ pr_err("Out of memory\n");
goto error;
}
@@ -674,14 +677,14 @@ static int usb_pcwd_probe(struct usb_interface *interface,
usb_pcwd->intr_buffer = usb_alloc_coherent(udev, usb_pcwd->intr_size,
GFP_ATOMIC, &usb_pcwd->intr_dma);
if (!usb_pcwd->intr_buffer) {
- printk(KERN_ERR PFX "Out of memory\n");
+ pr_err("Out of memory\n");
goto error;
}
/* allocate the urb's */
usb_pcwd->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!usb_pcwd->intr_urb) {
- printk(KERN_ERR PFX "Out of memory\n");
+ pr_err("Out of memory\n");
goto error;
}
@@ -694,7 +697,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
/* register our interrupt URB with the USB system */
if (usb_submit_urb(usb_pcwd->intr_urb, GFP_KERNEL)) {
- printk(KERN_ERR PFX "Problem registering interrupt URB\n");
+ pr_err("Problem registering interrupt URB\n");
retval = -EIO; /* failure */
goto error;
}
@@ -713,15 +716,13 @@ static int usb_pcwd_probe(struct usb_interface *interface,
else
sprintf(fw_ver_str, "<card no answer>");
- printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n",
- fw_ver_str);
+ pr_info("Found card (Firmware: %s) with temp option\n", fw_ver_str);
/* Get switch settings */
usb_pcwd_send_command(usb_pcwd, CMD_GET_DIP_SWITCH_SETTINGS, &dummy,
&option_switches);
- printk(KERN_INFO PFX "Option switches (0x%02x): "
- "Temperature Reset Enable=%s, Power On Delay=%s\n",
+ pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
option_switches,
((option_switches & 0x10) ? "ON" : "OFF"),
((option_switches & 0x08) ? "ON" : "OFF"));
@@ -734,39 +735,34 @@ static int usb_pcwd_probe(struct usb_interface *interface,
* if not reset to the default */
if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
- printk(KERN_INFO PFX
- "heartbeat value must be 0<heartbeat<65536, using %d\n",
+ pr_info("heartbeat value must be 0<heartbeat<65536, using %d\n",
WATCHDOG_HEARTBEAT);
}
retval = register_reboot_notifier(&usb_pcwd_notifier);
if (retval != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n",
- retval);
+ pr_err("cannot register reboot notifier (err=%d)\n", retval);
goto error;
}
retval = misc_register(&usb_pcwd_temperature_miscdev);
if (retval != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- TEMP_MINOR, retval);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ TEMP_MINOR, retval);
goto err_out_unregister_reboot;
}
retval = misc_register(&usb_pcwd_miscdev);
if (retval != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, retval);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, retval);
goto err_out_misc_deregister;
}
/* we can register the device now, as it is ready */
usb_set_intfdata(interface, usb_pcwd);
- printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+ pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
return 0;
@@ -824,7 +820,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface)
mutex_unlock(&disconnect_mutex);
- printk(KERN_INFO PFX "USB PC Watchdog disconnected\n");
+ pr_info("USB PC Watchdog disconnected\n");
}
module_usb_driver(usb_pcwd_driver);
diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c
index 2d22e996e996..7d3d471f810c 100644
--- a/drivers/watchdog/pika_wdt.c
+++ b/drivers/watchdog/pika_wdt.c
@@ -5,6 +5,8 @@
* Sean MacLennan <smaclennan@pikatech.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -23,7 +25,6 @@
#include <linux/of_platform.h>
#define DRV_NAME "PIKA-WDT"
-#define PFX DRV_NAME ": "
/* Hardware timeout in seconds */
#define WDT_HW_TIMEOUT 2
@@ -38,8 +39,8 @@ module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -90,7 +91,7 @@ static void pikawdt_ping(unsigned long data)
pikawdt_reset();
mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT);
} else
- printk(KERN_CRIT PFX "I will reset your machine !\n");
+ pr_crit("I will reset your machine !\n");
}
@@ -228,14 +229,14 @@ static int __init pikawdt_init(void)
np = of_find_compatible_node(NULL, NULL, "pika,fpga");
if (np == NULL) {
- printk(KERN_ERR PFX "Unable to find fpga.\n");
+ pr_err("Unable to find fpga\n");
return -ENOENT;
}
pikawdt_private.fpga = of_iomap(np, 0);
of_node_put(np);
if (pikawdt_private.fpga == NULL) {
- printk(KERN_ERR PFX "Unable to map fpga.\n");
+ pr_err("Unable to map fpga\n");
return -ENOMEM;
}
@@ -244,7 +245,7 @@ static int __init pikawdt_init(void)
/* POST information is in the sd area. */
np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
if (np == NULL) {
- printk(KERN_ERR PFX "Unable to find fpga-sd.\n");
+ pr_err("Unable to find fpga-sd\n");
ret = -ENOENT;
goto out;
}
@@ -252,7 +253,7 @@ static int __init pikawdt_init(void)
fpga = of_iomap(np, 0);
of_node_put(np);
if (fpga == NULL) {
- printk(KERN_ERR PFX "Unable to map fpga-sd.\n");
+ pr_err("Unable to map fpga-sd\n");
ret = -ENOMEM;
goto out;
}
@@ -271,12 +272,12 @@ static int __init pikawdt_init(void)
ret = misc_register(&pikawdt_miscdev);
if (ret) {
- printk(KERN_ERR PFX "Unable to register miscdev.\n");
+ pr_err("Unable to register miscdev\n");
goto out;
}
- printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
- heartbeat, nowayout);
+ pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
+ heartbeat, nowayout);
return 0;
out:
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index dfae030a7ef2..6b8432f61d05 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -8,33 +8,32 @@
* Based on sa1100 driver,
* Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
*
- * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * 2005-2006 (c) MontaVista Software, Inc.
+ *
+ * (C) 2012 Wolfram Sang, Pengutronix
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
-#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/err.h>
#include <mach/hardware.h>
-#define MODULE_NAME "PNX4008-WDT: "
-
/* WatchDog Timer - Chapter 23 Page 207 */
#define DEFAULT_HEARTBEAT 19
@@ -77,251 +76,128 @@
#define WDOG_COUNTER_RATE 13000000 /*the counter clock is 13 MHz fixed */
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int heartbeat = DEFAULT_HEARTBEAT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
static DEFINE_SPINLOCK(io_lock);
-static unsigned long wdt_status;
-#define WDT_IN_USE 0
-#define WDT_OK_TO_CLOSE 1
-#define WDT_REGION_INITED 2
-#define WDT_DEVICE_INITED 3
-
-static unsigned long boot_status;
-
-static struct resource *wdt_mem;
static void __iomem *wdt_base;
struct clk *wdt_clk;
-static void wdt_enable(void)
+static int pnx4008_wdt_start(struct watchdog_device *wdd)
{
spin_lock(&io_lock);
/* stop counter, initiate counter reset */
- __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
+ writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
/*wait for reset to complete. 100% guarantee event */
- while (__raw_readl(WDTIM_COUNTER(wdt_base)))
+ while (readl(WDTIM_COUNTER(wdt_base)))
cpu_relax();
/* internal and external reset, stop after that */
- __raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0,
- WDTIM_MCTRL(wdt_base));
+ writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0, WDTIM_MCTRL(wdt_base));
/* configure match output */
- __raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
+ writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
/* clear interrupt, just in case */
- __raw_writel(MATCH_INT, WDTIM_INT(wdt_base));
+ writel(MATCH_INT, WDTIM_INT(wdt_base));
/* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
- __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base));
- __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
+ writel(0xFFFF, WDTIM_PULSE(wdt_base));
+ writel(wdd->timeout * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
/*enable counter, stop when debugger active */
- __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
+ writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
spin_unlock(&io_lock);
+ return 0;
}
-static void wdt_disable(void)
+static int pnx4008_wdt_stop(struct watchdog_device *wdd)
{
spin_lock(&io_lock);
- __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
+ writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
spin_unlock(&io_lock);
+ return 0;
}
-static int pnx4008_wdt_open(struct inode *inode, struct file *file)
-{
- int ret;
-
- if (test_and_set_bit(WDT_IN_USE, &wdt_status))
- return -EBUSY;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- ret = clk_enable(wdt_clk);
- if (ret) {
- clear_bit(WDT_IN_USE, &wdt_status);
- return ret;
- }
-
- wdt_enable();
-
- return nonseekable_open(inode, file);
-}
-
-static ssize_t pnx4008_wdt_write(struct file *file, const char *data,
- size_t len, loff_t *ppos)
+static int pnx4008_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int new_timeout)
{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- set_bit(WDT_OK_TO_CLOSE, &wdt_status);
- }
- }
- wdt_enable();
- }
-
- return len;
+ wdd->timeout = new_timeout;
+ return 0;
}
-static const struct watchdog_info ident = {
+static const struct watchdog_info pnx4008_wdt_ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "PNX4008 Watchdog",
};
-static long pnx4008_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret = -ENOTTY;
- int time;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info *)arg, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- ret = put_user(0, (int *)arg);
- break;
-
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(boot_status, (int *)arg);
- break;
-
- case WDIOC_KEEPALIVE:
- wdt_enable();
- ret = 0;
- break;
-
- case WDIOC_SETTIMEOUT:
- ret = get_user(time, (int *)arg);
- if (ret)
- break;
-
- if (time <= 0 || time > MAX_HEARTBEAT) {
- ret = -EINVAL;
- break;
- }
-
- heartbeat = time;
- wdt_enable();
- /* Fall through */
-
- case WDIOC_GETTIMEOUT:
- ret = put_user(heartbeat, (int *)arg);
- break;
- }
- return ret;
-}
-
-static int pnx4008_wdt_release(struct inode *inode, struct file *file)
-{
- if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status))
- printk(KERN_WARNING "WATCHDOG: Device closed unexpectedly\n");
-
- wdt_disable();
- clk_disable(wdt_clk);
- clear_bit(WDT_IN_USE, &wdt_status);
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- return 0;
-}
-
-static const struct file_operations pnx4008_wdt_fops = {
+static const struct watchdog_ops pnx4008_wdt_ops = {
.owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = pnx4008_wdt_write,
- .unlocked_ioctl = pnx4008_wdt_ioctl,
- .open = pnx4008_wdt_open,
- .release = pnx4008_wdt_release,
+ .start = pnx4008_wdt_start,
+ .stop = pnx4008_wdt_stop,
+ .set_timeout = pnx4008_wdt_set_timeout,
};
-static struct miscdevice pnx4008_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &pnx4008_wdt_fops,
+static struct watchdog_device pnx4008_wdd = {
+ .info = &pnx4008_wdt_ident,
+ .ops = &pnx4008_wdt_ops,
+ .min_timeout = 1,
+ .max_timeout = MAX_HEARTBEAT,
};
static int __devinit pnx4008_wdt_probe(struct platform_device *pdev)
{
- int ret = 0, size;
+ struct resource *r;
+ int ret = 0;
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
- printk(KERN_INFO MODULE_NAME
- "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat);
-
- wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (wdt_mem == NULL) {
- printk(KERN_INFO MODULE_NAME
- "failed to get memory region resource\n");
- return -ENOENT;
- }
-
- size = resource_size(wdt_mem);
-
- if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
- printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
- return -ENOENT;
- }
- wdt_base = (void __iomem *)IO_ADDRESS(wdt_mem->start);
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ wdt_base = devm_request_and_ioremap(&pdev->dev, r);
+ if (!wdt_base)
+ return -EADDRINUSE;
wdt_clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(wdt_clk)) {
- ret = PTR_ERR(wdt_clk);
- release_mem_region(wdt_mem->start, size);
- wdt_mem = NULL;
- goto out;
- }
+ if (IS_ERR(wdt_clk))
+ return PTR_ERR(wdt_clk);
ret = clk_enable(wdt_clk);
- if (ret) {
- release_mem_region(wdt_mem->start, size);
- wdt_mem = NULL;
- clk_put(wdt_clk);
+ if (ret)
goto out;
- }
- ret = misc_register(&pnx4008_wdt_miscdev);
+ pnx4008_wdd.timeout = heartbeat;
+ pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
+ WDIOF_CARDRESET : 0;
+ watchdog_set_nowayout(&pnx4008_wdd, nowayout);
+
+ pnx4008_wdt_stop(&pnx4008_wdd); /* disable for now */
+
+ ret = watchdog_register_device(&pnx4008_wdd);
if (ret < 0) {
- printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
- release_mem_region(wdt_mem->start, size);
- wdt_mem = NULL;
- clk_disable(wdt_clk);
- clk_put(wdt_clk);
- } else {
- boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
- WDIOF_CARDRESET : 0;
- wdt_disable(); /*disable for now */
- clk_disable(wdt_clk);
- set_bit(WDT_DEVICE_INITED, &wdt_status);
+ dev_err(&pdev->dev, "cannot register watchdog device\n");
+ goto disable_clk;
}
+ dev_info(&pdev->dev, "PNX4008 Watchdog Timer: heartbeat %d sec\n",
+ heartbeat);
+
+ return 0;
+
+disable_clk:
+ clk_disable(wdt_clk);
out:
+ clk_put(wdt_clk);
return ret;
}
static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
{
- misc_deregister(&pnx4008_wdt_miscdev);
+ watchdog_unregister_device(&pnx4008_wdd);
clk_disable(wdt_clk);
clk_put(wdt_clk);
- if (wdt_mem) {
- release_mem_region(wdt_mem->start, resource_size(wdt_mem));
- wdt_mem = NULL;
- }
return 0;
}
@@ -337,15 +213,16 @@ static struct platform_driver platform_wdt_driver = {
module_platform_driver(platform_wdt_driver);
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
MODULE_DESCRIPTION("PNX4008 Watchdog Driver");
-module_param(heartbeat, int, 0);
+module_param(heartbeat, uint, 0);
MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat period in seconds from 1 to "
__MODULE_STRING(MAX_HEARTBEAT) ", default "
__MODULE_STRING(DEFAULT_HEARTBEAT));
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Set to 1 to keep watchdog running after device release");
diff --git a/drivers/watchdog/pnx833x_wdt.c b/drivers/watchdog/pnx833x_wdt.c
index a7b5ad2a98bd..1b62a7dfcc95 100644
--- a/drivers/watchdog/pnx833x_wdt.c
+++ b/drivers/watchdog/pnx833x_wdt.c
@@ -17,6 +17,8 @@
* based on softdog.c by Alan Cox <alan@redhat.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -30,7 +32,6 @@
#include <linux/init.h>
#include <asm/mach-pnx833x/pnx833x.h>
-#define PFX "pnx833x: "
#define WATCHDOG_TIMEOUT 30 /* 30 sec Maximum timeout */
#define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
#define PNX_WATCHDOG_TIMEOUT (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY)
@@ -54,8 +55,8 @@ module_param(pnx833x_wdt_timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
__MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds).");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -76,7 +77,7 @@ static void pnx833x_wdt_start(void)
PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
- printk(KERN_INFO PFX "Started watchdog timer.\n");
+ pr_info("Started watchdog timer\n");
}
static void pnx833x_wdt_stop(void)
@@ -87,7 +88,7 @@ static void pnx833x_wdt_stop(void)
PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
- printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+ pr_info("Stopped watchdog timer\n");
}
static void pnx833x_wdt_ping(void)
@@ -113,7 +114,7 @@ static int pnx833x_wdt_open(struct inode *inode, struct file *file)
pnx833x_wdt_ping();
- printk(KERN_INFO "Started watchdog timer.\n");
+ pr_info("Started watchdog timer\n");
return nonseekable_open(inode, file);
}
@@ -232,9 +233,6 @@ static struct notifier_block pnx833x_wdt_notifier = {
.notifier_call = pnx833x_wdt_notify_sys,
};
-static char banner[] __initdata =
- KERN_INFO PFX "Hardware Watchdog Timer for PNX833x: Version 0.1\n";
-
static int __init watchdog_init(void)
{
int ret, cause;
@@ -243,27 +241,25 @@ static int __init watchdog_init(void)
cause = PNX833X_REG(PNX833X_RESET);
/*If bit 31 is set then watchdog was cause of reset.*/
if (cause & 0x80000000) {
- printk(KERN_INFO PFX "The system was previously reset due to "
- "the watchdog firing - please investigate...\n");
+ pr_info("The system was previously reset due to the watchdog firing - please investigate...\n");
}
ret = register_reboot_notifier(&pnx833x_wdt_notifier);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&pnx833x_wdt_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&pnx833x_wdt_notifier);
return ret;
}
- printk(banner);
+ pr_info("Hardware Watchdog Timer for PNX833x: Version 0.1\n");
+
if (start_enabled)
pnx833x_wdt_start();
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index bf7bc8aa1c01..547353a50ebb 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -17,6 +17,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
#include <linux/types.h> /* For standard types (like size_t) */
@@ -33,8 +35,6 @@
#include <asm/mach-rc32434/integ.h> /* For the Watchdog registers */
-#define PFX KBUILD_MODNAME ": "
-
#define VERSION "1.0"
static struct {
@@ -64,8 +64,8 @@ module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout value, in seconds (default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -78,8 +78,7 @@ static int rc32434_wdt_set(int new_timeout)
int max_to = WTCOMP2SEC((u32)-1);
if (new_timeout < 0 || new_timeout > max_to) {
- printk(KERN_ERR PFX "timeout value must be between 0 and %d",
- max_to);
+ pr_err("timeout value must be between 0 and %d\n", max_to);
return -EINVAL;
}
timeout = new_timeout;
@@ -119,7 +118,7 @@ static void rc32434_wdt_start(void)
SET_BITS(wdt_reg->wtc, or, nand);
spin_unlock(&rc32434_wdt_device.io_lock);
- printk(KERN_INFO PFX "Started watchdog timer.\n");
+ pr_info("Started watchdog timer\n");
}
static void rc32434_wdt_stop(void)
@@ -130,7 +129,7 @@ static void rc32434_wdt_stop(void)
SET_BITS(wdt_reg->wtc, 0, 1 << RC32434_WTC_EN);
spin_unlock(&rc32434_wdt_device.io_lock);
- printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+ pr_info("Stopped watchdog timer\n");
}
static void rc32434_wdt_ping(void)
@@ -160,8 +159,7 @@ static int rc32434_wdt_release(struct inode *inode, struct file *file)
rc32434_wdt_stop();
module_put(THIS_MODULE);
} else {
- printk(KERN_CRIT PFX
- "device closed unexpectedly. WDT will not stop!\n");
+ pr_crit("device closed unexpectedly. WDT will not stop!\n");
rc32434_wdt_ping();
}
clear_bit(0, &rc32434_wdt_device.inuse);
@@ -262,9 +260,6 @@ static struct miscdevice rc32434_wdt_miscdev = {
.fops = &rc32434_wdt_fops,
};
-static char banner[] __devinitdata = KERN_INFO PFX
- "Watchdog Timer version " VERSION ", timer margin: %d sec\n";
-
static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
{
int ret;
@@ -272,13 +267,13 @@ static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb532_wdt_res");
if (!r) {
- printk(KERN_ERR PFX "failed to retrieve resources\n");
+ pr_err("failed to retrieve resources\n");
return -ENODEV;
}
wdt_reg = ioremap_nocache(r->start, resource_size(r));
if (!wdt_reg) {
- printk(KERN_ERR PFX "failed to remap I/O resources\n");
+ pr_err("failed to remap I/O resources\n");
return -ENXIO;
}
@@ -291,18 +286,18 @@ static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
* if not reset to the default */
if (rc32434_wdt_set(timeout)) {
rc32434_wdt_set(WATCHDOG_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be between 0 and %d\n",
+ pr_info("timeout value must be between 0 and %d\n",
WTCOMP2SEC((u32)-1));
}
ret = misc_register(&rc32434_wdt_miscdev);
if (ret < 0) {
- printk(KERN_ERR PFX "failed to register watchdog device\n");
+ pr_err("failed to register watchdog device\n");
goto unmap;
}
- printk(banner, timeout);
+ pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n",
+ timeout);
return 0;
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index c7e17ceafa6a..49e1b1c2135c 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -3,6 +3,8 @@
* Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -189,7 +191,7 @@ static int __devinit riowd_probe(struct platform_device *op)
p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
if (!p->regs) {
- printk(KERN_ERR PFX "Cannot map registers.\n");
+ pr_err("Cannot map registers\n");
goto out_free;
}
/* Make miscdev useable right away */
@@ -197,12 +199,12 @@ static int __devinit riowd_probe(struct platform_device *op)
err = misc_register(&riowd_miscdev);
if (err) {
- printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+ pr_err("Cannot register watchdog misc device\n");
goto out_iounmap;
}
- printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
- "regs at %p\n", riowd_timeout, p->regs);
+ pr_info("Hardware watchdog [%i minutes], regs at %p\n",
+ riowd_timeout, p->regs);
dev_set_drvdata(&op->dev, p);
return 0;
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 404172f02c9b..04e5a6de47d7 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -23,6 +23,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -46,12 +48,10 @@
#include <plat/regs-watchdog.h>
-#define PFX "s3c2410-wdt: "
-
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
static int soft_noboot;
@@ -59,7 +59,7 @@ static int debug;
module_param(tmr_margin, int, 0);
module_param(tmr_atboot, int, 0);
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
module_param(soft_noboot, int, 0);
module_param(debug, int, 0);
@@ -84,10 +84,11 @@ static DEFINE_SPINLOCK(wdt_lock);
/* watchdog control routines */
-#define DBG(msg...) do { \
- if (debug) \
- printk(KERN_INFO msg); \
- } while (0)
+#define DBG(fmt, ...) \
+do { \
+ if (debug) \
+ pr_info(fmt, ##__VA_ARGS__); \
+} while (0)
/* functions */
@@ -200,6 +201,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
writel(count, wdt_base + S3C2410_WTDAT);
writel(wtcon, wdt_base + S3C2410_WTCON);
+ wdd->timeout = timeout;
+
return 0;
}
@@ -354,7 +357,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
ret = s3c2410wdt_cpufreq_register();
if (ret < 0) {
- printk(KERN_ERR PFX "failed to register cpufreq\n");
+ pr_err("failed to register cpufreq\n");
goto err_clk;
}
@@ -483,8 +486,8 @@ static int s3c2410wdt_resume(struct platform_device *dev)
writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
writel(wtcon_save, wdt_base + S3C2410_WTCON);
- printk(KERN_INFO PFX "watchdog %sabled\n",
- (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
+ pr_info("watchdog %sabled\n",
+ (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
return 0;
}
@@ -518,12 +521,10 @@ static struct platform_driver s3c2410wdt_driver = {
};
-static char banner[] __initdata =
- KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
-
static int __init watchdog_init(void)
{
- printk(banner);
+ pr_info("S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n");
+
return platform_driver_register(&s3c2410wdt_driver);
}
diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c
index 016245419fad..54984deb8561 100644
--- a/drivers/watchdog/sa1100_wdt.c
+++ b/drivers/watchdog/sa1100_wdt.c
@@ -17,6 +17,9 @@
*
* 27/11/2000 Initial release
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -25,6 +28,7 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <linux/timex.h>
@@ -66,7 +70,7 @@ static int sa1100dog_open(struct inode *inode, struct file *file)
*/
static int sa1100dog_release(struct inode *inode, struct file *file)
{
- printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n");
+ pr_crit("Device closed - timer will not stop\n");
clear_bit(1, &sa1100wdt_users);
return 0;
}
@@ -169,9 +173,8 @@ static int __init sa1100dog_init(void)
ret = misc_register(&sa1100dog_miscdev);
if (ret == 0)
- printk(KERN_INFO
- "SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
- margin);
+ pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
+ margin);
return ret;
}
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
index b01a30e5a663..25c7a3f9652d 100644
--- a/drivers/watchdog/sb_wdog.c
+++ b/drivers/watchdog/sb_wdog.c
@@ -43,6 +43,9 @@
* version 1 or 2 as published by the Free Software Foundation.
*
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/io.h>
#include <linux/uaccess.h>
@@ -125,9 +128,8 @@ static int sbwdog_release(struct inode *inode, struct file *file)
__raw_writeb(0, user_dog);
module_put(THIS_MODULE);
} else {
- printk(KERN_CRIT
- "%s: Unexpected close, not stopping watchdog!\n",
- ident.identity);
+ pr_crit("%s: Unexpected close, not stopping watchdog!\n",
+ ident.identity);
sbwdog_pet(user_dog);
}
clear_bit(0, &sbwdog_gate);
@@ -269,7 +271,7 @@ irqreturn_t sbwdog_interrupt(int irq, void *addr)
* if it's the second watchdog timer, it's for those users
*/
if (wd_cfg_reg == user_dog)
- printk(KERN_CRIT "%s in danger of initiating system reset "
+ pr_crit("%s in danger of initiating system reset "
"in %ld.%01ld seconds\n",
ident.identity,
wd_init / 1000000, (wd_init / 100000) % 10);
@@ -290,9 +292,8 @@ static int __init sbwdog_init(void)
*/
ret = register_reboot_notifier(&sbwdog_notifier);
if (ret) {
- printk(KERN_ERR
- "%s: cannot register reboot notifier (err=%d)\n",
- ident.identity, ret);
+ pr_err("%s: cannot register reboot notifier (err=%d)\n",
+ ident.identity, ret);
return ret;
}
@@ -303,16 +304,16 @@ static int __init sbwdog_init(void)
ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
ident.identity, (void *)user_dog);
if (ret) {
- printk(KERN_ERR "%s: failed to request irq 1 - %d\n",
- ident.identity, ret);
+ pr_err("%s: failed to request irq 1 - %d\n",
+ ident.identity, ret);
goto out;
}
ret = misc_register(&sbwdog_miscdev);
if (ret == 0) {
- printk(KERN_INFO "%s: timeout is %ld.%ld secs\n",
- ident.identity,
- timeout / 1000000, (timeout / 100000) % 10);
+ pr_info("%s: timeout is %ld.%ld secs\n",
+ ident.identity,
+ timeout / 1000000, (timeout / 100000) % 10);
return 0;
}
free_irq(1, (void *)user_dog);
@@ -353,8 +354,7 @@ void platform_wd_setup(void)
ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
"Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0));
if (ret) {
- printk(KERN_CRIT
- "Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
+ pr_crit("Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
}
}
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
index 626d0e8e56c3..63632ec87c7e 100644
--- a/drivers/watchdog/sbc60xxwdt.c
+++ b/drivers/watchdog/sbc60xxwdt.c
@@ -48,6 +48,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -63,7 +65,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define OUR_NAME "sbc60xxwdt"
#define PFX OUR_NAME ": "
@@ -105,8 +106,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -132,8 +133,7 @@ static void wdt_timer_ping(unsigned long data)
/* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL);
} else
- printk(KERN_WARNING PFX
- "Heartbeat lost! Will not ping the watchdog\n");
+ pr_warn("Heartbeat lost! Will not ping the watchdog\n");
}
/*
@@ -146,7 +146,7 @@ static void wdt_startup(void)
/* Start the timer */
mod_timer(&timer, jiffies + WDT_INTERVAL);
- printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+ pr_info("Watchdog timer is now enabled\n");
}
static void wdt_turnoff(void)
@@ -154,7 +154,7 @@ static void wdt_turnoff(void)
/* Stop the timer */
del_timer(&timer);
inb_p(wdt_stop);
- printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+ pr_info("Watchdog timer is now disabled...\n");
}
static void wdt_keepalive(void)
@@ -217,8 +217,7 @@ static int fop_close(struct inode *inode, struct file *file)
wdt_turnoff();
else {
del_timer(&timer);
- printk(KERN_CRIT PFX
- "device file closed unexpectedly. Will not stop the WDT!\n");
+ pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
}
clear_bit(0, &wdt_is_open);
wdt_expect_close = 0;
@@ -335,14 +334,12 @@ static int __init sbc60xxwdt_init(void)
if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
timeout = WATCHDOG_TIMEOUT;
- printk(KERN_INFO PFX
- "timeout value must be 1 <= x <= 3600, using %d\n",
- timeout);
+ pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+ timeout);
}
if (!request_region(wdt_start, 1, "SBC 60XX WDT")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- wdt_start);
+ pr_err("I/O address 0x%04x already in use\n", wdt_start);
rc = -EIO;
goto err_out;
}
@@ -350,9 +347,7 @@ static int __init sbc60xxwdt_init(void)
/* We cannot reserve 0x45 - the kernel already has! */
if (wdt_stop != 0x45 && wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) {
- printk(KERN_ERR PFX
- "I/O address 0x%04x already in use\n",
- wdt_stop);
+ pr_err("I/O address 0x%04x already in use\n", wdt_stop);
rc = -EIO;
goto err_out_region1;
}
@@ -360,21 +355,18 @@ static int __init sbc60xxwdt_init(void)
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region2;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
goto err_out_reboot;
}
- printk(KERN_INFO PFX
- "WDT driver for 60XX single board computer initialised. "
- "timeout=%d sec (nowayout=%d)\n", timeout, nowayout);
+ pr_info("WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
return 0;
diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c
index 93ac58953122..719edc8fdeb3 100644
--- a/drivers/watchdog/sbc7240_wdt.c
+++ b/drivers/watchdog/sbc7240_wdt.c
@@ -16,6 +16,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ioport.h>
@@ -30,9 +32,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
-#include <asm/system.h>
-
-#define SBC7240_PREFIX "sbc7240_wdt: "
#define SBC7240_ENABLE_PORT 0x443
#define SBC7240_DISABLE_PORT 0x043
@@ -47,8 +46,8 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<="
__MODULE_STRING(SBC7240_MAX_TIMEOUT) ", default="
__MODULE_STRING(SBC7240_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Disable watchdog when closing device file");
#define SBC7240_OPEN_STATUS_BIT 0
@@ -65,8 +64,7 @@ static void wdt_disable(void)
/* disable the watchdog */
if (test_and_clear_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
inb_p(SBC7240_DISABLE_PORT);
- printk(KERN_INFO SBC7240_PREFIX
- "Watchdog timer is now disabled.\n");
+ pr_info("Watchdog timer is now disabled\n");
}
}
@@ -75,23 +73,20 @@ static void wdt_enable(void)
/* enable the watchdog */
if (!test_and_set_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
inb_p(SBC7240_ENABLE_PORT);
- printk(KERN_INFO SBC7240_PREFIX
- "Watchdog timer is now enabled.\n");
+ pr_info("Watchdog timer is now enabled\n");
}
}
static int wdt_set_timeout(int t)
{
if (t < 1 || t > SBC7240_MAX_TIMEOUT) {
- printk(KERN_ERR SBC7240_PREFIX
- "timeout value must be 1<=x<=%d\n",
- SBC7240_MAX_TIMEOUT);
+ pr_err("timeout value must be 1<=x<=%d\n", SBC7240_MAX_TIMEOUT);
return -1;
}
/* set the timeout */
outb_p((unsigned)t, SBC7240_SET_TIMEOUT_PORT);
timeout = t;
- printk(KERN_INFO SBC7240_PREFIX "timeout set to %d seconds\n", t);
+ pr_info("timeout set to %d seconds\n", t);
return 0;
}
@@ -150,8 +145,7 @@ static int fop_close(struct inode *inode, struct file *file)
|| !nowayout) {
wdt_disable();
} else {
- printk(KERN_CRIT SBC7240_PREFIX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
wdt_keepalive();
}
@@ -252,7 +246,7 @@ static struct notifier_block wdt_notifier = {
static void __exit sbc7240_wdt_unload(void)
{
- printk(KERN_INFO SBC7240_PREFIX "Removing watchdog\n");
+ pr_info("Removing watchdog\n");
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);
@@ -264,8 +258,7 @@ static int __init sbc7240_wdt_init(void)
int rc = -EBUSY;
if (!request_region(SBC7240_ENABLE_PORT, 1, "SBC7240 WDT")) {
- printk(KERN_ERR SBC7240_PREFIX
- "I/O address 0x%04x already in use\n",
+ pr_err("I/O address 0x%04x already in use\n",
SBC7240_ENABLE_PORT);
rc = -EIO;
goto err_out;
@@ -277,31 +270,27 @@ static int __init sbc7240_wdt_init(void)
if (timeout < 1 || timeout > SBC7240_MAX_TIMEOUT) {
timeout = SBC7240_TIMEOUT;
- printk(KERN_INFO SBC7240_PREFIX
- "timeout value must be 1<=x<=%d, using %d\n",
- SBC7240_MAX_TIMEOUT, timeout);
+ pr_info("timeout value must be 1<=x<=%d, using %d\n",
+ SBC7240_MAX_TIMEOUT, timeout);
}
wdt_set_timeout(timeout);
wdt_disable();
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR SBC7240_PREFIX
- "cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR SBC7240_PREFIX
- "cannot register miscdev on minor=%d (err=%d)\n",
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc);
goto err_out_reboot_notifier;
}
- printk(KERN_INFO SBC7240_PREFIX
- "Watchdog driver for SBC7240 initialised (nowayout=%d)\n",
- nowayout);
+ pr_info("Watchdog driver for SBC7240 initialised (nowayout=%d)\n",
+ nowayout);
return 0;
diff --git a/drivers/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c
index 514ec23050f7..d4781e05f017 100644
--- a/drivers/watchdog/sbc8360.c
+++ b/drivers/watchdog/sbc8360.c
@@ -36,6 +36,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
@@ -51,13 +53,10 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
static unsigned long sbc8360_is_open;
static char expect_close;
-#define PFX "sbc8360: "
-
/*
*
* Watchdog Timer Configuration
@@ -197,11 +196,11 @@ static int wd_times[64][2] = {
static int timeout = 27;
static int wd_margin = 0xB;
static int wd_multiplier = 2;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -280,8 +279,7 @@ static int sbc8360_close(struct inode *inode, struct file *file)
if (expect_close == 42)
sbc8360_stop();
else
- printk(KERN_CRIT PFX "SBC8360 device closed unexpectedly. "
- "SBC8360 will not stop!\n");
+ pr_crit("SBC8360 device closed unexpectedly. SBC8360 will not stop!\n");
clear_bit(0, &sbc8360_is_open);
expect_close = 0;
@@ -334,20 +332,19 @@ static int __init sbc8360_init(void)
unsigned long int mseconds = 60000;
if (timeout < 0 || timeout > 63) {
- printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+ pr_err("Invalid timeout index (must be 0-63)\n");
res = -EINVAL;
goto out;
}
if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
- printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
+ pr_err("ENABLE method I/O %X is not available\n",
SBC8360_ENABLE);
res = -EIO;
goto out;
}
if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
- printk(KERN_ERR PFX
- "BASETIME method I/O %X is not available.\n",
+ pr_err("BASETIME method I/O %X is not available\n",
SBC8360_BASETIME);
res = -EIO;
goto out_nobasetimereg;
@@ -355,13 +352,13 @@ static int __init sbc8360_init(void)
res = register_reboot_notifier(&sbc8360_notifier);
if (res) {
- printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
+ pr_err("Failed to register reboot notifier\n");
goto out_noreboot;
}
res = misc_register(&sbc8360_miscdev);
if (res) {
- printk(KERN_ERR PFX "failed to register misc device\n");
+ pr_err("failed to register misc device\n");
goto out_nomisc;
}
@@ -378,7 +375,7 @@ static int __init sbc8360_init(void)
mseconds = (wd_margin + 1) * 100000;
/* My kingdom for the ability to print "0.5 seconds" in the kernel! */
- printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
+ pr_info("Timeout set at %ld ms\n", mseconds);
return 0;
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c
index eaca366b7234..0c3e9f66ef77 100644
--- a/drivers/watchdog/sbc_epx_c3.c
+++ b/drivers/watchdog/sbc_epx_c3.c
@@ -13,6 +13,8 @@
* based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -28,13 +30,12 @@
#include <linux/uaccess.h>
#include <linux/io.h>
-#define PFX "epx_c3: "
static int epx_c3_alive;
#define WATCHDOG_TIMEOUT 1 /* 1 sec default timeout */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -51,7 +52,7 @@ static void epx_c3_stop(void)
outb(0, EPXC3_WATCHDOG_CTL_REG);
- printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+ pr_info("Stopped watchdog timer\n");
}
static void epx_c3_pet(void)
@@ -75,7 +76,7 @@ static int epx_c3_open(struct inode *inode, struct file *file)
epx_c3_pet();
epx_c3_alive = 1;
- printk(KERN_INFO "Started watchdog timer.\n");
+ pr_info("Started watchdog timer\n");
return nonseekable_open(inode, file);
}
@@ -173,9 +174,6 @@ static struct notifier_block epx_c3_notifier = {
.notifier_call = epx_c3_notify_sys,
};
-static const char banner[] __initconst = KERN_INFO PFX
- "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
-
static int __init watchdog_init(void)
{
int ret;
@@ -185,20 +183,19 @@ static int __init watchdog_init(void)
ret = register_reboot_notifier(&epx_c3_notifier);
if (ret) {
- printk(KERN_ERR PFX "cannot register reboot notifier "
- "(err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto out;
}
ret = misc_register(&epx_c3_miscdev);
if (ret) {
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
- "(err=%d)\n", WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&epx_c3_notifier);
goto out;
}
- printk(banner);
+ pr_info("Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n");
return 0;
diff --git a/drivers/watchdog/sbc_fitpc2_wdt.c b/drivers/watchdog/sbc_fitpc2_wdt.c
index d5d399464599..90d5527ca886 100644
--- a/drivers/watchdog/sbc_fitpc2_wdt.c
+++ b/drivers/watchdog/sbc_fitpc2_wdt.c
@@ -25,9 +25,8 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned int margin = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status;
static DEFINE_MUTEX(wdt_lock);
@@ -171,8 +170,7 @@ static int fitpc2_wdt_release(struct inode *inode, struct file *file)
wdt_disable();
pr_info("Device disabled\n");
} else {
- pr_warning("Device closed unexpectedly -"
- " timer will not stop\n");
+ pr_warn("Device closed unexpectedly - timer will not stop\n");
wdt_enable();
}
@@ -222,8 +220,8 @@ static int __init fitpc2_wdt_init(void)
}
if (margin < 31 || margin > 255) {
- pr_err("margin must be in range 31 - 255"
- " seconds, you tried to set %d\n", margin);
+ pr_err("margin must be in range 31 - 255 seconds, you tried to set %d\n",
+ margin);
err = -EINVAL;
goto err_margin;
}
@@ -231,7 +229,7 @@ static int __init fitpc2_wdt_init(void)
err = misc_register(&fitpc2_wdt_miscdev);
if (err) {
pr_err("cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, err);
+ WATCHDOG_MINOR, err);
goto err_margin;
}
@@ -261,7 +259,7 @@ MODULE_DESCRIPTION("SBC-FITPC2 Watchdog");
module_param(margin, int, 0);
MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c
index c01daca8405a..3fb83b0c28c2 100644
--- a/drivers/watchdog/sc1200wdt.c
+++ b/drivers/watchdog/sc1200wdt.c
@@ -31,6 +31,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
@@ -48,7 +50,6 @@
#define SC1200_MODULE_VER "build 20020303"
#define SC1200_MODULE_NAME "sc1200wdt"
-#define PFX SC1200_MODULE_NAME ": "
#define MAX_TIMEOUT 255 /* 255 minutes */
#define PMIR (io) /* Power Management Index Register */
@@ -71,7 +72,6 @@
#define UART2_IRQ 0x04 /* Serial1 */
/* 5 -7 are reserved */
-static char banner[] __initdata = PFX SC1200_MODULE_VER;
static int timeout = 1;
static int io = -1;
static int io_len = 2; /* for non plug and play */
@@ -93,8 +93,8 @@ MODULE_PARM_DESC(io, "io port");
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -176,7 +176,7 @@ static int sc1200wdt_open(struct inode *inode, struct file *file)
timeout = MAX_TIMEOUT;
sc1200wdt_start();
- printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
+ pr_info("Watchdog enabled, timeout = %d min(s)", timeout);
return nonseekable_open(inode, file);
}
@@ -254,11 +254,10 @@ static int sc1200wdt_release(struct inode *inode, struct file *file)
{
if (expect_close == 42) {
sc1200wdt_stop();
- printk(KERN_INFO PFX "Watchdog disabled\n");
+ pr_info("Watchdog disabled\n");
} else {
sc1200wdt_write_data(WDTO, timeout);
- printk(KERN_CRIT PFX
- "Unexpected close!, timeout = %d min(s)\n", timeout);
+ pr_crit("Unexpected close!, timeout = %d min(s)\n", timeout);
}
clear_bit(0, &open_flag);
expect_close = 0;
@@ -361,12 +360,11 @@ static int scl200wdt_pnp_probe(struct pnp_dev *dev,
io_len = pnp_port_len(wdt_dev, 0);
if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
- printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+ pr_err("Unable to register IO port %#x\n", io);
return -EBUSY;
}
- printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n",
- io, io_len);
+ pr_info("PnP device found at io port %#x/%d\n", io, io_len);
return 0;
}
@@ -392,7 +390,7 @@ static int __init sc1200wdt_init(void)
{
int ret;
- printk(KERN_INFO "%s\n", banner);
+ pr_info("%s\n", SC1200_MODULE_VER);
#if defined CONFIG_PNP
if (isapnp) {
@@ -403,7 +401,7 @@ static int __init sc1200wdt_init(void)
#endif
if (io == -1) {
- printk(KERN_ERR PFX "io parameter must be specified\n");
+ pr_err("io parameter must be specified\n");
ret = -EINVAL;
goto out_pnp;
}
@@ -416,7 +414,7 @@ static int __init sc1200wdt_init(void)
#endif
if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
- printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+ pr_err("Unable to register IO port %#x\n", io);
ret = -EBUSY;
goto out_pnp;
}
@@ -427,16 +425,14 @@ static int __init sc1200wdt_init(void)
ret = register_reboot_notifier(&sc1200wdt_notifier);
if (ret) {
- printk(KERN_ERR PFX
- "Unable to register reboot notifier err = %d\n", ret);
+ pr_err("Unable to register reboot notifier err = %d\n", ret);
goto out_io;
}
ret = misc_register(&sc1200wdt_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "Unable to register miscdev on minor %d\n",
- WATCHDOG_MINOR);
+ pr_err("Unable to register miscdev on minor %d\n",
+ WATCHDOG_MINOR);
goto out_rbt;
}
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c
index b2840409ebc7..707e027e5002 100644
--- a/drivers/watchdog/sc520_wdt.c
+++ b/drivers/watchdog/sc520_wdt.c
@@ -52,6 +52,8 @@
* This driver uses memory mapped IO, and spinlock.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -67,10 +69,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#define OUR_NAME "sc520_wdt"
-#define PFX OUR_NAME ": "
/*
* The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
@@ -98,8 +96,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1 <= timeout <= 3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -151,8 +149,7 @@ static void wdt_timer_ping(unsigned long data)
/* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL);
} else
- printk(KERN_WARNING PFX
- "Heartbeat lost! Will not ping the watchdog\n");
+ pr_warn("Heartbeat lost! Will not ping the watchdog\n");
}
/*
@@ -187,7 +184,7 @@ static int wdt_startup(void)
/* Start the watchdog */
wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
- printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+ pr_info("Watchdog timer is now enabled\n");
return 0;
}
@@ -199,7 +196,7 @@ static int wdt_turnoff(void)
/* Stop the watchdog */
wdt_config(0);
- printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+ pr_info("Watchdog timer is now disabled...\n");
return 0;
}
@@ -270,8 +267,7 @@ static int fop_close(struct inode *inode, struct file *file)
if (wdt_expect_close == 42)
wdt_turnoff();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
wdt_keepalive();
}
clear_bit(0, &wdt_is_open);
@@ -393,36 +389,32 @@ static int __init sc520_wdt_init(void)
if not reset to the default */
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 1 <= timeout <= 3600, using %d\n",
- WATCHDOG_TIMEOUT);
+ pr_info("timeout value must be 1 <= timeout <= 3600, using %d\n",
+ WATCHDOG_TIMEOUT);
}
wdtmrctl = ioremap(MMCR_BASE + OFFS_WDTMRCTL, 2);
if (!wdtmrctl) {
- printk(KERN_ERR PFX "Unable to remap memory\n");
+ pr_err("Unable to remap memory\n");
rc = -ENOMEM;
goto err_out_region2;
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("cannot register reboot notifier (err=%d)\n", rc);
goto err_out_ioremap;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, rc);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, rc);
goto err_out_notifier;
}
- printk(KERN_INFO PFX
- "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
- timeout, nowayout);
+ pr_info("WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
return 0;
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index 029467e34636..bd86f32d63ab 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -18,6 +18,8 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
/* Includes */
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
@@ -37,7 +39,6 @@
/* Module and version information */
#define DRV_NAME "sch311x_wdt"
-#define PFX DRV_NAME ": "
/* Runtime registers */
#define RESGEN 0x1d
@@ -79,8 +80,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=15300, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -323,8 +324,7 @@ static int sch311x_wdt_close(struct inode *inode, struct file *file)
if (sch311x_wdt_expect_close == 42) {
sch311x_wdt_stop();
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
sch311x_wdt_keepalive();
}
clear_bit(0, &sch311x_wdt_is_open);
@@ -504,20 +504,19 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
/* Check if Logical Device Register is currently active */
if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
- printk(KERN_INFO PFX "Seems that LDN 0x0a is not active...\n");
+ pr_info("Seems that LDN 0x0a is not active...\n");
/* Get the base address of the runtime registers */
base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
sch311x_sio_inb(sio_config_port, 0x61);
if (!base_addr) {
- printk(KERN_ERR PFX "Base address not set.\n");
+ pr_err("Base address not set\n");
err = -ENODEV;
goto exit;
}
*addr = base_addr;
- printk(KERN_INFO PFX "Found an SMSC SCH311%d chip at 0x%04x\n",
- dev_id, base_addr);
+ pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
exit:
sch311x_sio_exit(sio_config_port);
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
index e67b76c0526c..8ae7c282d465 100644
--- a/drivers/watchdog/scx200_wdt.c
+++ b/drivers/watchdog/scx200_wdt.c
@@ -17,6 +17,8 @@
of any nature resulting due to the use of this software. This
software is provided AS-IS with no warranties. */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -30,7 +32,7 @@
#include <linux/uaccess.h>
#include <linux/io.h>
-#define NAME "scx200_wdt"
+#define DEBUG
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
@@ -41,8 +43,8 @@ static int margin = 60; /* in seconds */
module_param(margin, int, 0);
MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
static u16 wdto_restart;
@@ -66,14 +68,13 @@ static void scx200_wdt_ping(void)
static void scx200_wdt_update_margin(void)
{
- printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
+ pr_info("timer margin %d seconds\n", margin);
wdto_restart = margin * W_SCALE;
}
static void scx200_wdt_enable(void)
{
- printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
- wdto_restart);
+ pr_debug("enabling watchdog timer, wdto_restart = %d\n", wdto_restart);
spin_lock(&scx_lock);
outw(0, scx200_cb_base + SCx200_WDT_WDTO);
@@ -86,7 +87,7 @@ static void scx200_wdt_enable(void)
static void scx200_wdt_disable(void)
{
- printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+ pr_debug("disabling watchdog timer\n");
spin_lock(&scx_lock);
outw(0, scx200_cb_base + SCx200_WDT_WDTO);
@@ -108,9 +109,7 @@ static int scx200_wdt_open(struct inode *inode, struct file *file)
static int scx200_wdt_release(struct inode *inode, struct file *file)
{
if (expect_close != 42)
- printk(KERN_WARNING NAME
- ": watchdog device closed unexpectedly, "
- "will not disable the watchdog timer\n");
+ pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
else if (!nowayout)
scx200_wdt_disable();
expect_close = 0;
@@ -219,7 +218,7 @@ static int __init scx200_wdt_init(void)
{
int r;
- printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
+ pr_debug("NatSemi SCx200 Watchdog Driver\n");
/* check that we have found the configuration block */
if (!scx200_cb_present())
@@ -228,7 +227,7 @@ static int __init scx200_wdt_init(void)
if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET,
SCx200_WDT_SIZE,
"NatSemi SCx200 Watchdog")) {
- printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+ pr_warn("watchdog I/O region busy\n");
return -EBUSY;
}
@@ -237,7 +236,7 @@ static int __init scx200_wdt_init(void)
r = register_reboot_notifier(&scx200_wdt_notifier);
if (r) {
- printk(KERN_ERR NAME ": unable to register reboot notifier");
+ pr_err("unable to register reboot notifier\n");
release_region(scx200_cb_base + SCx200_WDT_OFFSET,
SCx200_WDT_SIZE);
return r;
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index a267dc078daf..93958a7763e6 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -17,6 +17,9 @@
* Added expect close support, made emulated timeout runtime changeable
* general cleanups, add some ioctls
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
@@ -72,7 +75,7 @@ static DEFINE_SPINLOCK(shwdt_lock);
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned long next_heartbeat;
struct sh_wdt {
@@ -440,20 +443,20 @@ static int __init sh_wdt_init(void)
clock_division_ratio > 0x7)) {
clock_division_ratio = WTCSR_CKS_4096;
- pr_info("%s: divisor must be 0x5<=x<=0x7, using %d\n",
- DRV_NAME, clock_division_ratio);
+ pr_info("divisor must be 0x5<=x<=0x7, using %d\n",
+ clock_division_ratio);
}
rc = sh_wdt_set_heartbeat(heartbeat);
if (unlikely(rc)) {
heartbeat = WATCHDOG_HEARTBEAT;
- pr_info("%s: heartbeat value must be 1<=x<=3600, using %d\n",
- DRV_NAME, heartbeat);
+ pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
+ heartbeat);
}
- pr_info("%s: configured with heartbeat=%d sec (nowayout=%d)\n",
- DRV_NAME, heartbeat, nowayout);
+ pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
+ heartbeat, nowayout);
return platform_driver_register(&sh_wdt_driver);
}
@@ -481,7 +484,7 @@ MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
index 97b8184614ae..6d665f9c1d58 100644
--- a/drivers/watchdog/smsc37b787_wdt.c
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -43,6 +43,8 @@
* Documentation/watchdog/wdt.txt
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -58,7 +60,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
/* enable support for minutes as units? */
/* (does not always work correctly, so disabled by default!) */
@@ -70,7 +71,6 @@
#define UNIT_SECOND 0
#define UNIT_MINUTE 1
-#define MODNAME "smsc37b787_wdt: "
#define VERSION "1.1"
#define IOPORT 0x3F0
@@ -85,7 +85,7 @@ static char expect_close; /* is the close expected? */
static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
/* -- Low level function ----------------------------------------*/
@@ -363,8 +363,7 @@ static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
/* Reload and activate timer */
wb_smsc_wdt_enable();
- printk(KERN_INFO MODNAME
- "Watchdog enabled. Timeout set to %d %s.\n",
+ pr_info("Watchdog enabled. Timeout set to %d %s\n",
timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
return nonseekable_open(inode, file);
@@ -378,11 +377,9 @@ static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
if (expect_close == 42) {
wb_smsc_wdt_disable();
- printk(KERN_INFO MODNAME
- "Watchdog disabled, sleeping again...\n");
+ pr_info("Watchdog disabled, sleeping again...\n");
} else {
- printk(KERN_CRIT MODNAME
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
wb_smsc_wdt_reset_timer();
}
@@ -534,12 +531,11 @@ static int __init wb_smsc_wdt_init(void)
{
int ret;
- printk(KERN_INFO "SMsC 37B787 watchdog component driver "
- VERSION " initialising...\n");
+ pr_info("SMsC 37B787 watchdog component driver "
+ VERSION " initialising...\n");
if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
- printk(KERN_ERR MODNAME "Unable to register IO port %#x\n",
- IOPORT);
+ pr_err("Unable to register IO port %#x\n", IOPORT);
ret = -EBUSY;
goto out_pnp;
}
@@ -553,25 +549,22 @@ static int __init wb_smsc_wdt_init(void)
ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
if (ret) {
- printk(KERN_ERR MODNAME
- "Unable to register reboot notifier err = %d\n", ret);
+ pr_err("Unable to register reboot notifier err = %d\n", ret);
goto out_io;
}
ret = misc_register(&wb_smsc_wdt_miscdev);
if (ret) {
- printk(KERN_ERR MODNAME
- "Unable to register miscdev on minor %d\n",
- WATCHDOG_MINOR);
+ pr_err("Unable to register miscdev on minor %d\n",
+ WATCHDOG_MINOR);
goto out_rbt;
}
/* output info */
- printk(KERN_INFO MODNAME "Timeout set to %d %s.\n",
+ pr_info("Timeout set to %d %s\n",
timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
- printk(KERN_INFO MODNAME
- "Watchdog initialized and sleeping (nowayout=%d)...\n",
- nowayout);
+ pr_info("Watchdog initialized and sleeping (nowayout=%d)...\n",
+ nowayout);
out_clean:
return ret;
@@ -592,14 +585,14 @@ static void __exit wb_smsc_wdt_exit(void)
/* Stop the timer before we leave */
if (!nowayout) {
wb_smsc_wdt_shutdown();
- printk(KERN_INFO MODNAME "Watchdog disabled.\n");
+ pr_info("Watchdog disabled\n");
}
misc_deregister(&wb_smsc_wdt_miscdev);
unregister_reboot_notifier(&wb_smsc_wdt_notifier);
release_region(IOPORT, IOPORT_SIZE);
- printk(KERN_INFO "SMsC 37B787 watchdog component driver removed.\n");
+ pr_info("SMsC 37B787 watchdog component driver removed\n");
}
module_init(wb_smsc_wdt_init);
@@ -621,7 +614,7 @@ MODULE_PARM_DESC(unit,
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index bf16ffb4d21e..fe83beb8f1b7 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -1,5 +1,5 @@
/*
- * SoftDog 0.07: A Software Watchdog Device
+ * SoftDog: A Software Watchdog Device
*
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
@@ -36,45 +36,37 @@
* Added Matt Domsch's nowayout module option.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
-#include <linux/fs.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/jiffies.h>
-#include <linux/uaccess.h>
#include <linux/kernel.h>
-#define PFX "SoftDog: "
-
#define TIMER_MARGIN 60 /* Default is 60 seconds */
-static int soft_margin = TIMER_MARGIN; /* in seconds */
-module_param(soft_margin, int, 0);
+static unsigned int soft_margin = TIMER_MARGIN; /* in seconds */
+module_param(soft_margin, uint, 0);
MODULE_PARM_DESC(soft_margin,
"Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default="
__MODULE_STRING(TIMER_MARGIN) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-#ifdef ONLY_TESTING
-static int soft_noboot = 1;
-#else
static int soft_noboot = 0;
-#endif /* ONLY_TESTING */
-
module_param(soft_noboot, int, 0);
MODULE_PARM_DESC(soft_noboot,
- "Softdog action, set to 1 to ignore reboots, 0 to reboot "
- "(default depends on ONLY_TESTING)");
+ "Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)");
static int soft_panic;
module_param(soft_panic, int, 0);
@@ -89,9 +81,6 @@ static void watchdog_fire(unsigned long);
static struct timer_list watchdog_ticktock =
TIMER_INITIALIZER(watchdog_fire, 0, 0);
-static unsigned long driver_open, orphan_timer;
-static char expect_close;
-
/*
* If the timer expires..
@@ -99,18 +88,15 @@ static char expect_close;
static void watchdog_fire(unsigned long data)
{
- if (test_and_clear_bit(0, &orphan_timer))
- module_put(THIS_MODULE);
-
if (soft_noboot)
- printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
+ pr_crit("Triggered - Reboot ignored\n");
else if (soft_panic) {
- printk(KERN_CRIT PFX "Initiating panic.\n");
- panic("Software Watchdog Timer expired.");
+ pr_crit("Initiating panic\n");
+ panic("Software Watchdog Timer expired");
} else {
- printk(KERN_CRIT PFX "Initiating system reboot.\n");
+ pr_crit("Initiating system reboot\n");
emergency_restart();
- printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+ pr_crit("Reboot didn't ?????\n");
}
}
@@ -118,127 +104,24 @@ static void watchdog_fire(unsigned long data)
* Softdog operations
*/
-static int softdog_keepalive(void)
+static int softdog_ping(struct watchdog_device *w)
{
- mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+ mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ));
return 0;
}
-static int softdog_stop(void)
+static int softdog_stop(struct watchdog_device *w)
{
del_timer(&watchdog_ticktock);
return 0;
}
-static int softdog_set_heartbeat(int t)
-{
- if ((t < 0x0001) || (t > 0xFFFF))
- return -EINVAL;
-
- soft_margin = t;
- return 0;
-}
-
-/*
- * /dev/watchdog handling
- */
-
-static int softdog_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(0, &driver_open))
- return -EBUSY;
- if (!test_and_clear_bit(0, &orphan_timer))
- __module_get(THIS_MODULE);
- /*
- * Activate timer
- */
- softdog_keepalive();
- return nonseekable_open(inode, file);
-}
-
-static int softdog_release(struct inode *inode, struct file *file)
+static int softdog_set_timeout(struct watchdog_device *w, unsigned int t)
{
- /*
- * Shut off the timer.
- * Lock it in if it's a module and we set nowayout
- */
- if (expect_close == 42) {
- softdog_stop();
- module_put(THIS_MODULE);
- } else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
- set_bit(0, &orphan_timer);
- softdog_keepalive();
- }
- clear_bit(0, &driver_open);
- expect_close = 0;
+ w->timeout = t;
return 0;
}
-static ssize_t softdog_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
-{
- /*
- * Refresh the timer.
- */
- if (len) {
- if (!nowayout) {
- size_t i;
-
- /* In case it was set long ago */
- expect_close = 0;
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- expect_close = 42;
- }
- }
- softdog_keepalive();
- }
- return len;
-}
-
-static long softdog_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
- int new_margin;
- static const struct watchdog_info ident = {
- .options = WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE,
- .firmware_version = 0,
- .identity = "Software Watchdog",
- };
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- return put_user(0, p);
- case WDIOC_KEEPALIVE:
- softdog_keepalive();
- return 0;
- case WDIOC_SETTIMEOUT:
- if (get_user(new_margin, p))
- return -EFAULT;
- if (softdog_set_heartbeat(new_margin))
- return -EINVAL;
- softdog_keepalive();
- /* Fall */
- case WDIOC_GETTIMEOUT:
- return put_user(soft_margin, p);
- default:
- return -ENOTTY;
- }
-}
-
/*
* Notifier for system down
*/
@@ -248,7 +131,7 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
{
if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the WDT off */
- softdog_stop();
+ softdog_stop(NULL);
return NOTIFY_DONE;
}
@@ -256,28 +139,29 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static const struct file_operations softdog_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = softdog_write,
- .unlocked_ioctl = softdog_ioctl,
- .open = softdog_open,
- .release = softdog_release,
+static struct notifier_block softdog_notifier = {
+ .notifier_call = softdog_notify_sys,
};
-static struct miscdevice softdog_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &softdog_fops,
+static struct watchdog_info softdog_info = {
+ .identity = "Software Watchdog",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
};
-static struct notifier_block softdog_notifier = {
- .notifier_call = softdog_notify_sys,
+static struct watchdog_ops softdog_ops = {
+ .owner = THIS_MODULE,
+ .start = softdog_ping,
+ .stop = softdog_stop,
+ .ping = softdog_ping,
+ .set_timeout = softdog_set_timeout,
};
-static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 "
- "initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d "
- "(nowayout= %d)\n";
+static struct watchdog_device softdog_dev = {
+ .info = &softdog_info,
+ .ops = &softdog_ops,
+ .min_timeout = 1,
+ .max_timeout = 0xFFFF
+};
static int __init watchdog_init(void)
{
@@ -285,37 +169,36 @@ static int __init watchdog_init(void)
/* Check that the soft_margin value is within it's range;
if not reset to the default */
- if (softdog_set_heartbeat(soft_margin)) {
- softdog_set_heartbeat(TIMER_MARGIN);
- printk(KERN_INFO PFX
- "soft_margin must be 0 < soft_margin < 65536, using %d\n",
+ if (soft_margin < 1 || soft_margin > 65535) {
+ pr_info("soft_margin must be 0 < soft_margin < 65536, using %d\n",
TIMER_MARGIN);
+ return -EINVAL;
}
+ softdog_dev.timeout = soft_margin;
+
+ watchdog_set_nowayout(&softdog_dev, nowayout);
ret = register_reboot_notifier(&softdog_notifier);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
- ret = misc_register(&softdog_miscdev);
+ ret = watchdog_register_device(&softdog_dev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&softdog_notifier);
return ret;
}
- printk(banner, soft_noboot, soft_margin, soft_panic, nowayout);
+ pr_info("Software Watchdog Timer: 0.08 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n",
+ soft_noboot, soft_margin, soft_panic, nowayout);
return 0;
}
static void __exit watchdog_exit(void)
{
- misc_deregister(&softdog_miscdev);
+ watchdog_unregister_device(&softdog_dev);
unregister_reboot_notifier(&softdog_notifier);
}
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 87e0527669d8..59108e48ada3 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -20,6 +20,8 @@
* Includes, defines, variables, module parameters, ...
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -39,7 +41,6 @@
#define TCO_VERSION "0.01"
#define TCO_MODULE_NAME "SP5100 TCO timer"
#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
/* internal variables */
static u32 tcobase_phys;
@@ -61,8 +62,8 @@ module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
" (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -143,8 +144,7 @@ static int sp5100_tco_release(struct inode *inode, struct file *file)
if (tco_expect_close == 42) {
tco_timer_stop();
} else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
tco_timer_keepalive();
}
clear_bit(0, &timer_alive);
@@ -290,8 +290,7 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
/* Request the IO ports used by this driver */
pm_iobase = SP5100_IO_PM_INDEX_REG;
if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- pm_iobase);
+ pr_err("I/O address 0x%04x already in use\n", pm_iobase);
goto exit;
}
@@ -308,15 +307,14 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
"SP5100 TCO")) {
- printk(KERN_ERR PFX "mmio address 0x%04x already in use\n",
- val);
+ pr_err("mmio address 0x%04x already in use\n", val);
goto unreg_region;
}
tcobase_phys = val;
tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
if (tcobase == 0) {
- printk(KERN_ERR PFX "failed to get tcobase address\n");
+ pr_err("failed to get tcobase address\n");
goto unreg_mem_region;
}
@@ -375,9 +373,9 @@ static int __devinit sp5100_tco_init(struct platform_device *dev)
return -ENODEV;
/* Check to see if last reboot was due to watchdog timeout */
- printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
- readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
- "" : "not ");
+ pr_info("Watchdog reboot %sdetected\n",
+ readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
+ "" : "not ");
/* Clear out the old status */
val = readl(SP5100_WDT_CONTROL(tcobase));
@@ -395,16 +393,14 @@ static int __devinit sp5100_tco_init(struct platform_device *dev)
ret = misc_register(&sp5100_tco_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX "cannot register miscdev on minor="
- "%d (err=%d)\n",
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto exit;
}
clear_bit(0, &timer_alive);
- printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec"
- " (nowayout=%d)\n",
+ pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
tcobase, heartbeat, nowayout);
return 0;
@@ -455,8 +451,7 @@ static int __init sp5100_tco_init_module(void)
{
int err;
- printk(KERN_INFO PFX "SP5100 TCO WatchDog Timer Driver v%s\n",
- TCO_VERSION);
+ pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
err = platform_driver_register(&sp5100_tco_driver);
if (err)
@@ -480,7 +475,7 @@ static void __exit sp5100_tco_cleanup_module(void)
{
platform_device_unregister(sp5100_tco_platform_device);
platform_driver_unregister(&sp5100_tco_driver);
- printk(KERN_INFO PFX "SP5100 TCO Watchdog Module Unloaded.\n");
+ pr_info("SP5100 TCO Watchdog Module Unloaded\n");
}
module_init(sp5100_tco_init_module);
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 3ff9e47bd218..bbb170e50055 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -25,6 +25,7 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -55,14 +56,13 @@
/**
* struct sp805_wdt: sp805 wdt device structure
- *
- * lock: spin lock protecting dev structure and io access
- * base: base address of wdt
- * clk: clock structure of wdt
- * dev: amba device structure of wdt
- * status: current status of wdt
- * load_val: load value to be set for current timeout
- * timeout: current programmed timeout
+ * @lock: spin lock protecting dev structure and io access
+ * @base: base address of wdt
+ * @clk: clock structure of wdt
+ * @adev: amba device structure of wdt
+ * @status: current status of wdt
+ * @load_val: load value to be set for current timeout
+ * @timeout: current programmed timeout
*/
struct sp805_wdt {
spinlock_t lock;
@@ -78,7 +78,7 @@ struct sp805_wdt {
/* local variables */
static struct sp805_wdt *wdt;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
/* This routine finds load value that will reset system in required timout */
static void wdt_setload(unsigned int timeout)
@@ -113,10 +113,10 @@ static u32 wdt_timeleft(void)
rate = clk_get_rate(wdt->clk);
spin_lock(&wdt->lock);
- load = readl(wdt->base + WDTVALUE);
+ load = readl_relaxed(wdt->base + WDTVALUE);
/*If the interrupt is inactive then time left is WDTValue + WDTLoad. */
- if (!(readl(wdt->base + WDTRIS) & INT_MASK))
+ if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK))
load += wdt->load_val + 1;
spin_unlock(&wdt->lock);
@@ -128,14 +128,14 @@ static void wdt_enable(void)
{
spin_lock(&wdt->lock);
- writel(UNLOCK, wdt->base + WDTLOCK);
- writel(wdt->load_val, wdt->base + WDTLOAD);
- writel(INT_MASK, wdt->base + WDTINTCLR);
- writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
- writel(LOCK, wdt->base + WDTLOCK);
+ writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
+ writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
+ writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
+ writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
+ writel_relaxed(LOCK, wdt->base + WDTLOCK);
/* Flush posted writes. */
- readl(wdt->base + WDTLOCK);
+ readl_relaxed(wdt->base + WDTLOCK);
spin_unlock(&wdt->lock);
}
@@ -144,12 +144,12 @@ static void wdt_disable(void)
{
spin_lock(&wdt->lock);
- writel(UNLOCK, wdt->base + WDTLOCK);
- writel(0, wdt->base + WDTCONTROL);
- writel(LOCK, wdt->base + WDTLOCK);
+ writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
+ writel_relaxed(0, wdt->base + WDTCONTROL);
+ writel_relaxed(LOCK, wdt->base + WDTLOCK);
/* Flush posted writes. */
- readl(wdt->base + WDTLOCK);
+ readl_relaxed(wdt->base + WDTLOCK);
spin_unlock(&wdt->lock);
}
@@ -285,32 +285,33 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
- if (!request_mem_region(adev->res.start, resource_size(&adev->res),
- "sp805_wdt")) {
+ if (!devm_request_mem_region(&adev->dev, adev->res.start,
+ resource_size(&adev->res), "sp805_wdt")) {
dev_warn(&adev->dev, "Failed to get memory region resource\n");
ret = -ENOENT;
goto err;
}
- wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
+ wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt) {
dev_warn(&adev->dev, "Kzalloc failed\n");
ret = -ENOMEM;
- goto err_kzalloc;
+ goto err;
+ }
+
+ wdt->base = devm_ioremap(&adev->dev, adev->res.start,
+ resource_size(&adev->res));
+ if (!wdt->base) {
+ ret = -ENOMEM;
+ dev_warn(&adev->dev, "ioremap fail\n");
+ goto err;
}
wdt->clk = clk_get(&adev->dev, NULL);
if (IS_ERR(wdt->clk)) {
dev_warn(&adev->dev, "Clock not found\n");
ret = PTR_ERR(wdt->clk);
- goto err_clk_get;
- }
-
- wdt->base = ioremap(adev->res.start, resource_size(&adev->res));
- if (!wdt->base) {
- ret = -ENOMEM;
- dev_warn(&adev->dev, "ioremap fail\n");
- goto err_ioremap;
+ goto err;
}
wdt->adev = adev;
@@ -327,14 +328,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
err_misc_register:
- iounmap(wdt->base);
-err_ioremap:
clk_put(wdt->clk);
-err_clk_get:
- kfree(wdt);
- wdt = NULL;
-err_kzalloc:
- release_mem_region(adev->res.start, resource_size(&adev->res));
err:
dev_err(&adev->dev, "Probe Failed!!!\n");
return ret;
@@ -343,14 +337,42 @@ err:
static int __devexit sp805_wdt_remove(struct amba_device *adev)
{
misc_deregister(&sp805_wdt_miscdev);
- iounmap(wdt->base);
clk_put(wdt->clk);
- kfree(wdt);
- release_mem_region(adev->res.start, resource_size(&adev->res));
return 0;
}
+#ifdef CONFIG_PM
+static int sp805_wdt_suspend(struct device *dev)
+{
+ if (test_bit(WDT_BUSY, &wdt->status)) {
+ wdt_disable();
+ clk_disable(wdt->clk);
+ }
+
+ return 0;
+}
+
+static int sp805_wdt_resume(struct device *dev)
+{
+ int ret = 0;
+
+ if (test_bit(WDT_BUSY, &wdt->status)) {
+ ret = clk_enable(wdt->clk);
+ if (ret) {
+ dev_err(dev, "clock enable fail");
+ return ret;
+ }
+ wdt_enable();
+ }
+
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(sp805_wdt_dev_pm_ops, sp805_wdt_suspend,
+ sp805_wdt_resume);
+
static struct amba_id sp805_wdt_ids[] = {
{
.id = 0x00141805,
@@ -364,6 +386,7 @@ MODULE_DEVICE_TABLE(amba, sp805_wdt_ids);
static struct amba_driver sp805_wdt_driver = {
.drv = {
.name = MODULE_NAME,
+ .pm = &sp805_wdt_dev_pm_ops,
},
.id_table = sp805_wdt_ids,
.probe = sp805_wdt_probe,
@@ -372,7 +395,7 @@ static struct amba_driver sp805_wdt_driver = {
module_amba_driver(sp805_wdt_driver);
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Set to 1 to keep watchdog running after device release");
diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c
index e37d81178b9e..21d96b92bfd7 100644
--- a/drivers/watchdog/stmp3xxx_wdt.c
+++ b/drivers/watchdog/stmp3xxx_wdt.c
@@ -6,6 +6,9 @@
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -32,7 +35,7 @@
static DEFINE_SPINLOCK(stmp3xxx_wdt_io_lock);
static unsigned long wdt_status;
-static const int nowayout = WATCHDOG_NOWAYOUT;
+static const bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = DEFAULT_HEARTBEAT;
static unsigned long boot_status;
@@ -221,8 +224,7 @@ static int __devinit stmp3xxx_wdt_probe(struct platform_device *pdev)
return ret;
}
- printk(KERN_INFO "stmp3xxx watchdog: initialized, heartbeat %d sec\n",
- heartbeat);
+ pr_info("initialized, heartbeat %d sec\n", heartbeat);
return ret;
}
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index 1490293dc7da..8df050d800e6 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -34,8 +34,8 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. "
__MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT)
")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
/**
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
index 0764c6239b98..249f11305d26 100644
--- a/drivers/watchdog/twl4030_wdt.c
+++ b/drivers/watchdog/twl4030_wdt.c
@@ -42,8 +42,8 @@ struct twl4030_wdt {
unsigned long state;
};
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
index 9e9ed7bfabcb..98e16373e640 100644
--- a/drivers/watchdog/txx9wdt.c
+++ b/drivers/watchdog/txx9wdt.c
@@ -7,177 +7,99 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
-#include <linux/fs.h>
#include <linux/init.h>
-#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <asm/txx9tmr.h>
+#define WD_TIMER_CCD 7 /* 1/256 */
+#define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
+#define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
#define TIMER_MARGIN 60 /* Default is 60 seconds */
-static int timeout = TIMER_MARGIN; /* in seconds */
-module_param(timeout, int, 0);
+static unsigned int timeout = TIMER_MARGIN; /* in seconds */
+module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. "
"(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "
"default=" __MODULE_STRING(TIMER_MARGIN) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-#define WD_TIMER_CCD 7 /* 1/256 */
-#define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
-#define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
-
-static unsigned long txx9wdt_alive;
-static int expect_close;
static struct txx9_tmr_reg __iomem *txx9wdt_reg;
static struct clk *txx9_imclk;
static DEFINE_SPINLOCK(txx9_lock);
-static void txx9wdt_ping(void)
+static int txx9wdt_ping(struct watchdog_device *wdt_dev)
{
spin_lock(&txx9_lock);
__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
spin_unlock(&txx9_lock);
+ return 0;
}
-static void txx9wdt_start(void)
+static int txx9wdt_start(struct watchdog_device *wdt_dev)
{
spin_lock(&txx9_lock);
- __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
+ __raw_writel(WD_TIMER_CLK * wdt_dev->timeout, &txx9wdt_reg->cpra);
__raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
__raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */
__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
&txx9wdt_reg->tcr);
__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
spin_unlock(&txx9_lock);
+ return 0;
}
-static void txx9wdt_stop(void)
+static int txx9wdt_stop(struct watchdog_device *wdt_dev)
{
spin_lock(&txx9_lock);
__raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
__raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
&txx9wdt_reg->tcr);
spin_unlock(&txx9_lock);
-}
-
-static int txx9wdt_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(0, &txx9wdt_alive))
- return -EBUSY;
-
- if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) {
- clear_bit(0, &txx9wdt_alive);
- return -EBUSY;
- }
-
- if (nowayout)
- __module_get(THIS_MODULE);
-
- txx9wdt_start();
- return nonseekable_open(inode, file);
-}
-
-static int txx9wdt_release(struct inode *inode, struct file *file)
-{
- if (expect_close)
- txx9wdt_stop();
- else {
- printk(KERN_CRIT "txx9wdt: "
- "Unexpected close, not stopping watchdog!\n");
- txx9wdt_ping();
- }
- clear_bit(0, &txx9wdt_alive);
- expect_close = 0;
return 0;
}
-static ssize_t txx9wdt_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
+static int txx9wdt_set_timeout(struct watchdog_device *wdt_dev,
+ unsigned int new_timeout)
{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- expect_close = 0;
- for (i = 0; i != len; i++) {
- char c;
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- expect_close = 1;
- }
- }
- txx9wdt_ping();
- }
- return len;
+ wdt_dev->timeout = new_timeout;
+ txx9wdt_stop(wdt_dev);
+ txx9wdt_start(wdt_dev);
+ return 0;
}
-static long txx9wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
- int new_timeout;
- static const struct watchdog_info ident = {
- .options = WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE,
- .firmware_version = 0,
- .identity = "Hardware Watchdog for TXx9",
- };
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- return put_user(0, p);
- case WDIOC_KEEPALIVE:
- txx9wdt_ping();
- return 0;
- case WDIOC_SETTIMEOUT:
- if (get_user(new_timeout, p))
- return -EFAULT;
- if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT)
- return -EINVAL;
- timeout = new_timeout;
- txx9wdt_stop();
- txx9wdt_start();
- /* Fall */
- case WDIOC_GETTIMEOUT:
- return put_user(timeout, p);
- default:
- return -ENOTTY;
- }
-}
+static const struct watchdog_info txx9wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .identity = "Hardware Watchdog for TXx9",
+};
-static const struct file_operations txx9wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = txx9wdt_write,
- .unlocked_ioctl = txx9wdt_ioctl,
- .open = txx9wdt_open,
- .release = txx9wdt_release,
+static const struct watchdog_ops txx9wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = txx9wdt_start,
+ .stop = txx9wdt_stop,
+ .ping = txx9wdt_ping,
+ .set_timeout = txx9wdt_set_timeout,
};
-static struct miscdevice txx9wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &txx9wdt_fops,
+static struct watchdog_device txx9wdt = {
+ .info = &txx9wdt_info,
+ .ops = &txx9wdt_ops,
};
static int __init txx9wdt_probe(struct platform_device *dev)
@@ -199,27 +121,27 @@ static int __init txx9wdt_probe(struct platform_device *dev)
}
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res)
- goto exit_busy;
- if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
- "txx9wdt"))
- goto exit_busy;
- txx9wdt_reg = devm_ioremap(&dev->dev, res->start, resource_size(res));
- if (!txx9wdt_reg)
- goto exit_busy;
-
- ret = misc_register(&txx9wdt_miscdev);
- if (ret) {
+ txx9wdt_reg = devm_request_and_ioremap(&dev->dev, res);
+ if (!txx9wdt_reg) {
+ ret = -EBUSY;
goto exit;
}
- printk(KERN_INFO "Hardware Watchdog Timer for TXx9: "
- "timeout=%d sec (max %ld) (nowayout= %d)\n",
- timeout, WD_MAX_TIMEOUT, nowayout);
+ if (timeout < 1 || timeout > WD_MAX_TIMEOUT)
+ timeout = TIMER_MARGIN;
+ txx9wdt.timeout = timeout;
+ txx9wdt.min_timeout = 1;
+ txx9wdt.max_timeout = WD_MAX_TIMEOUT;
+ watchdog_set_nowayout(&txx9wdt, nowayout);
+
+ ret = watchdog_register_device(&txx9wdt);
+ if (ret)
+ goto exit;
+
+ pr_info("Hardware Watchdog Timer: timeout=%d sec (max %ld) (nowayout= %d)\n",
+ timeout, WD_MAX_TIMEOUT, nowayout);
return 0;
-exit_busy:
- ret = -EBUSY;
exit:
if (txx9_imclk) {
clk_disable(txx9_imclk);
@@ -230,7 +152,7 @@ exit:
static int __exit txx9wdt_remove(struct platform_device *dev)
{
- misc_deregister(&txx9wdt_miscdev);
+ watchdog_unregister_device(&txx9wdt);
clk_disable(txx9_imclk);
clk_put(txx9_imclk);
return 0;
@@ -238,7 +160,7 @@ static int __exit txx9wdt_remove(struct platform_device *dev)
static void txx9wdt_shutdown(struct platform_device *dev)
{
- txx9wdt_stop();
+ txx9wdt_stop(&txx9wdt);
}
static struct platform_driver txx9wdt_driver = {
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c
index 8f07dd4bd94a..465e08273c97 100644
--- a/drivers/watchdog/via_wdt.c
+++ b/drivers/watchdog/via_wdt.c
@@ -10,6 +10,9 @@
* Caveat: PnP must be enabled in BIOS to allow full access to watchdog
* control registers. If not, the watchdog must be configured in BIOS manually.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/io.h>
#include <linux/jiffies.h>
@@ -55,8 +58,8 @@ module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, between 1 and 1023 "
"(default = " __MODULE_STRING(WDT_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default = " __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -98,7 +101,7 @@ static void wdt_timer_tick(unsigned long data)
static int wdt_ping(struct watchdog_device *wdd)
{
/* calculate when the next userspace timeout will be */
- next_heartbeat = jiffies + timeout * HZ;
+ next_heartbeat = jiffies + wdd->timeout * HZ;
return 0;
}
@@ -106,7 +109,7 @@ static int wdt_start(struct watchdog_device *wdd)
{
unsigned int ctl = readl(wdt_mem);
- writel(timeout, wdt_mem + VIA_WDT_COUNT);
+ writel(wdd->timeout, wdt_mem + VIA_WDT_COUNT);
writel(ctl | VIA_WDT_RUNNING | VIA_WDT_TRIGGER, wdt_mem);
wdt_ping(wdd);
mod_timer(&timer, jiffies + WDT_HEARTBEAT);
@@ -125,7 +128,7 @@ static int wdt_set_timeout(struct watchdog_device *wdd,
unsigned int new_timeout)
{
writel(new_timeout, wdt_mem + VIA_WDT_COUNT);
- timeout = new_timeout;
+ wdd->timeout = new_timeout;
return 0;
}
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 576a388a1164..92f1326f0cfc 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -26,6 +26,8 @@
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -40,10 +42,8 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
-#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
static unsigned long wdt_is_open;
@@ -61,8 +61,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1 <= timeout <= 255, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -119,9 +119,8 @@ static void w83627hf_init(void)
outb_p(0xF6, WDT_EFER); /* Select CRF6 */
t = inb_p(WDT_EFDR); /* read CRF6 */
if (t != 0) {
- printk(KERN_INFO PFX
- "Watchdog already running. Resetting timeout to %d sec\n",
- timeout);
+ pr_info("Watchdog already running. Resetting timeout to %d sec\n",
+ timeout);
outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
}
@@ -290,8 +289,7 @@ static int wdt_close(struct inode *inode, struct file *file)
if (expect_close == 42)
wdt_disable();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
wdt_ping();
}
expect_close = 0;
@@ -344,18 +342,16 @@ static int __init wdt_init(void)
{
int ret;
- printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n");
+ pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n");
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 1 <= timeout <= 255, using %d\n",
- WATCHDOG_TIMEOUT);
+ pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
+ WATCHDOG_TIMEOUT);
}
if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- wdt_io);
+ pr_err("I/O address 0x%04x already in use\n", wdt_io);
ret = -EIO;
goto out;
}
@@ -364,22 +360,19 @@ static int __init wdt_init(void)
ret = register_reboot_notifier(&wdt_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto unreg_regions;
}
ret = misc_register(&wdt_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_reboot;
}
- printk(KERN_INFO PFX
- "initialized. timeout=%d sec (nowayout=%d)\n",
- timeout, nowayout);
+ pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
out:
return ret;
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c
index af08972de506..cd9f3c1e1af4 100644
--- a/drivers/watchdog/w83697hf_wdt.c
+++ b/drivers/watchdog/w83697hf_wdt.c
@@ -25,6 +25,8 @@
* "AS-IS" and at no charge.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -39,10 +41,8 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define WATCHDOG_NAME "w83697hf/hg WDT"
-#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
#define WATCHDOG_EARLY_DISABLE 1 /* Disable until userland kicks in */
@@ -62,8 +62,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=255 (default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -309,8 +309,7 @@ static int wdt_close(struct inode *inode, struct file *file)
if (expect_close == 42)
wdt_disable();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
wdt_ping();
}
expect_close = 0;
@@ -362,24 +361,21 @@ static struct notifier_block wdt_notifier = {
static int w83697hf_check_wdt(void)
{
if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX
- "I/O address 0x%x already in use\n", wdt_io);
+ pr_err("I/O address 0x%x already in use\n", wdt_io);
return -EIO;
}
- printk(KERN_DEBUG PFX
- "Looking for watchdog at address 0x%x\n", wdt_io);
+ pr_debug("Looking for watchdog at address 0x%x\n", wdt_io);
w83697hf_unlock();
if (w83697hf_get_reg(0x20) == 0x60) {
- printk(KERN_INFO PFX
- "watchdog found at address 0x%x\n", wdt_io);
+ pr_info("watchdog found at address 0x%x\n", wdt_io);
w83697hf_lock();
return 0;
}
/* Reprotect in case it was a compatible device */
w83697hf_lock();
- printk(KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io);
+ pr_info("watchdog not found at address 0x%x\n", wdt_io);
release_region(wdt_io, 2);
return -EIO;
}
@@ -390,7 +386,7 @@ static int __init wdt_init(void)
{
int ret, i, found = 0;
- printk(KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
+ pr_info("WDT driver for W83697HF/HG initializing\n");
if (wdt_io == 0) {
/* we will autodetect the W83697HF/HG watchdog */
@@ -405,7 +401,7 @@ static int __init wdt_init(void)
}
if (!found) {
- printk(KERN_ERR PFX "No W83697HF/HG could be found\n");
+ pr_err("No W83697HF/HG could be found\n");
ret = -EIO;
goto out;
}
@@ -413,34 +409,30 @@ static int __init wdt_init(void)
w83697hf_init();
if (early_disable) {
if (wdt_running())
- printk(KERN_WARNING PFX "Stopping previously enabled "
- "watchdog until userland kicks in\n");
+ pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
wdt_disable();
}
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 1 <= timeout <= 255, using %d\n",
- WATCHDOG_TIMEOUT);
+ pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
+ WATCHDOG_TIMEOUT);
}
ret = register_reboot_notifier(&wdt_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto unreg_regions;
}
ret = misc_register(&wdt_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_reboot;
}
- printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+ pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
out:
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
index be9c4d839e15..274be0bfaf24 100644
--- a/drivers/watchdog/w83697ug_wdt.c
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -30,6 +30,8 @@
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -44,10 +46,8 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define WATCHDOG_NAME "w83697ug/uf WDT"
-#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
static unsigned long wdt_is_open;
@@ -64,8 +64,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=255 (default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -91,8 +91,8 @@ static int w83697ug_select_wd_register(void)
version = inb(WDT_EFDR);
if (version == 0x68) { /* W83697UG */
- printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
- "W83697UG/UF found at 0x%04x\n", version, wdt_io);
+ pr_info("Watchdog chip version 0x%02x = W83697UG/UF found at 0x%04x\n",
+ version, wdt_io);
outb_p(0x2b, WDT_EFER);
c = inb_p(WDT_EFDR); /* select WDT0 */
@@ -101,7 +101,7 @@ static int w83697ug_select_wd_register(void)
outb_p(c, WDT_EFDR); /* set pin118 to WDT0 */
} else {
- printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+ pr_err("No W83697UG/UF could be found\n");
return -ENODEV;
}
@@ -131,8 +131,8 @@ static int w83697ug_init(void)
outb_p(0xF6, WDT_EFER); /* Select CRF6 */
t = inb_p(WDT_EFDR); /* read CRF6 */
if (t != 0) {
- printk(KERN_INFO PFX "Watchdog already running."
- " Resetting timeout to %d sec\n", timeout);
+ pr_info("Watchdog already running. Resetting timeout to %d sec\n",
+ timeout);
outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
}
outb_p(0xF5, WDT_EFER); /* Select CRF5 */
@@ -286,8 +286,7 @@ static int wdt_close(struct inode *inode, struct file *file)
if (expect_close == 42)
wdt_disable();
else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
wdt_ping();
}
expect_close = 0;
@@ -340,18 +339,16 @@ static int __init wdt_init(void)
{
int ret;
- printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+ pr_info("WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising\n");
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 1<=timeout<=255, using %d\n",
+ pr_info("timeout value must be 1<=timeout<=255, using %d\n",
WATCHDOG_TIMEOUT);
}
if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- wdt_io);
+ pr_err("I/O address 0x%04x already in use\n", wdt_io);
ret = -EIO;
goto out;
}
@@ -362,20 +359,18 @@ static int __init wdt_init(void)
ret = register_reboot_notifier(&wdt_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto unreg_regions;
}
ret = misc_register(&wdt_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto unreg_reboot;
}
- printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+ pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
out:
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index 24587d2060c4..7874ae06232b 100644
--- a/drivers/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -42,6 +42,8 @@
* daemon always getting scheduled within that time frame.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -56,10 +58,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define OUR_NAME "w83877f_wdt"
-#define PFX OUR_NAME ": "
#define ENABLE_W83877F_PORT 0x3F0
#define ENABLE_W83877F 0x87
@@ -91,8 +91,8 @@ MODULE_PARM_DESC(timeout,
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -126,8 +126,7 @@ static void wdt_timer_ping(unsigned long data)
spin_unlock(&wdt_spinlock);
} else
- printk(KERN_WARNING PFX
- "Heartbeat lost! Will not ping the watchdog\n");
+ pr_warn("Heartbeat lost! Will not ping the watchdog\n");
}
/*
@@ -165,7 +164,7 @@ static void wdt_startup(void)
wdt_change(WDT_ENABLE);
- printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+ pr_info("Watchdog timer is now enabled\n");
}
static void wdt_turnoff(void)
@@ -175,7 +174,7 @@ static void wdt_turnoff(void)
wdt_change(WDT_DISABLE);
- printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+ pr_info("Watchdog timer is now disabled...\n");
}
static void wdt_keepalive(void)
@@ -234,8 +233,7 @@ static int fop_close(struct inode *inode, struct file *file)
wdt_turnoff();
else {
del_timer(&timer);
- printk(KERN_CRIT PFX
- "device file closed unexpectedly. Will not stop the WDT!\n");
+ pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
}
clear_bit(0, &wdt_is_open);
wdt_expect_close = 0;
@@ -357,42 +355,37 @@ static int __init w83877f_wdt_init(void)
if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
timeout = WATCHDOG_TIMEOUT;
- printk(KERN_INFO PFX
- "timeout value must be 1 <= x <= 3600, using %d\n",
- timeout);
+ pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+ timeout);
}
if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- ENABLE_W83877F_PORT);
+ pr_err("I/O address 0x%04x already in use\n",
+ ENABLE_W83877F_PORT);
rc = -EIO;
goto err_out;
}
if (!request_region(WDT_PING, 1, "W8387FF WDT")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- WDT_PING);
+ pr_err("I/O address 0x%04x already in use\n", WDT_PING);
rc = -EIO;
goto err_out_region1;
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region2;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
goto err_out_reboot;
}
- printk(KERN_INFO PFX
- "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
+ pr_info("WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0;
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index 6e6743d1066f..5d2c902825c2 100644
--- a/drivers/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -15,6 +15,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -29,12 +31,9 @@
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <asm/system.h>
#define WATCHDOG_VERSION "1.00"
#define WATCHDOG_NAME "W83977F WDT"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
#define IO_INDEX_PORT 0x3F0
#define IO_DATA_PORT (IO_INDEX_PORT+1)
@@ -59,8 +58,8 @@ MODULE_PARM_DESC(timeout,
module_param(testmode, int, 0);
MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -131,7 +130,7 @@ static int wdt_start(void)
spin_unlock_irqrestore(&spinlock, flags);
- printk(KERN_INFO PFX "activated.\n");
+ pr_info("activated\n");
return 0;
}
@@ -185,7 +184,7 @@ static int wdt_stop(void)
spin_unlock_irqrestore(&spinlock, flags);
- printk(KERN_INFO PFX "shutdown.\n");
+ pr_info("shutdown\n");
return 0;
}
@@ -313,8 +312,7 @@ static int wdt_release(struct inode *inode, struct file *file)
clear_bit(0, &timer_alive);
} else {
wdt_keepalive();
- printk(KERN_CRIT PFX
- "unexpected close, not stopping watchdog!\n");
+ pr_crit("unexpected close, not stopping watchdog!\n");
}
expect_close = 0;
return 0;
@@ -471,7 +469,7 @@ static int __init w83977f_wdt_init(void)
{
int rc;
- printk(KERN_INFO PFX DRIVER_VERSION);
+ pr_info("driver v%s\n", WATCHDOG_VERSION);
/*
* Check that the timeout value is within it's range;
@@ -479,36 +477,31 @@ static int __init w83977f_wdt_init(void)
*/
if (wdt_set_timeout(timeout)) {
wdt_set_timeout(DEFAULT_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 15 <= timeout <= 7635, using %d\n",
- DEFAULT_TIMEOUT);
+ pr_info("timeout value must be 15 <= timeout <= 7635, using %d\n",
+ DEFAULT_TIMEOUT);
}
if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- IO_INDEX_PORT);
+ pr_err("I/O address 0x%04x already in use\n", IO_INDEX_PORT);
rc = -EIO;
goto err_out;
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
goto err_out_reboot;
}
- printk(KERN_INFO PFX
- "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
- timeout, nowayout, testmode);
+ pr_info("initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
+ timeout, nowayout, testmode);
return 0;
diff --git a/drivers/watchdog/wafer5823wdt.c b/drivers/watchdog/wafer5823wdt.c
index c3c3188c34d7..25aba6e00a23 100644
--- a/drivers/watchdog/wafer5823wdt.c
+++ b/drivers/watchdog/wafer5823wdt.c
@@ -26,6 +26,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
@@ -65,8 +67,8 @@ MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1 <= timeout <= 255, default="
__MODULE_STRING(WD_TIMO) ".");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -203,8 +205,7 @@ static int wafwdt_close(struct inode *inode, struct file *file)
if (expect_close == 42)
wafwdt_stop();
else {
- printk(KERN_CRIT PFX
- "WDT device closed unexpectedly. WDT will not stop!\n");
+ pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
wafwdt_ping();
}
clear_bit(0, &wafwdt_is_open);
@@ -256,49 +257,42 @@ static int __init wafwdt_init(void)
{
int ret;
- printk(KERN_INFO
- "WDT driver for Wafer 5823 single board computer initialising.\n");
+ pr_info("WDT driver for Wafer 5823 single board computer initialising\n");
if (timeout < 1 || timeout > 255) {
timeout = WD_TIMO;
- printk(KERN_INFO PFX
- "timeout value must be 1 <= x <= 255, using %d\n",
- timeout);
+ pr_info("timeout value must be 1 <= x <= 255, using %d\n",
+ timeout);
}
if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
- printk(KERN_ERR PFX
- "I/O address 0x%04x already in use\n",
- wdt_stop);
+ pr_err("I/O address 0x%04x already in use\n", wdt_stop);
ret = -EIO;
goto error;
}
}
if (!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
- printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
- wdt_start);
+ pr_err("I/O address 0x%04x already in use\n", wdt_start);
ret = -EIO;
goto error2;
}
ret = register_reboot_notifier(&wafwdt_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto error3;
}
ret = misc_register(&wafwdt_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto error4;
}
- printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+ pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return ret;
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index cfa1a1518aad..14d768bfa267 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -77,7 +77,7 @@ int watchdog_register_device(struct watchdog_device *wdd)
/* We only support 1 watchdog device via the /dev/watchdog interface */
ret = watchdog_dev_register(wdd);
if (ret) {
- pr_err("error registering /dev/watchdog (err=%d).\n", ret);
+ pr_err("error registering /dev/watchdog (err=%d)\n", ret);
return ret;
}
@@ -101,7 +101,7 @@ void watchdog_unregister_device(struct watchdog_device *wdd)
ret = watchdog_dev_unregister(wdd);
if (ret)
- pr_err("error unregistering /dev/watchdog (err=%d).\n", ret);
+ pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
}
EXPORT_SYMBOL_GPL(watchdog_unregister_device);
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 1199da0f98cf..8558da912c42 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -226,7 +226,6 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
err = wdd->ops->set_timeout(wdd, val);
if (err < 0)
return err;
- wdd->timeout = val;
/* If the watchdog is active then we send a keepalive ping
* to make sure that the watchdog keep's running (and if
* possible that it takes the new timeout) */
@@ -237,6 +236,11 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
if (wdd->timeout == 0)
return -EOPNOTSUPP;
return put_user(wdd->timeout, p);
+ case WDIOC_GETTIMELEFT:
+ if (!wdd->ops->get_timeleft)
+ return -EOPNOTSUPP;
+
+ return put_user(wdd->ops->get_timeleft(wdd), p);
default:
return -ENOTTY;
}
@@ -347,7 +351,7 @@ int watchdog_dev_register(struct watchdog_device *watchdog)
/* Only one device can register for /dev/watchdog */
if (test_and_set_bit(0, &watchdog_dev_busy)) {
- pr_err("only one watchdog can use /dev/watchdog.\n");
+ pr_err("only one watchdog can use /dev/watchdog\n");
return -EBUSY;
}
@@ -355,8 +359,8 @@ int watchdog_dev_register(struct watchdog_device *watchdog)
err = misc_register(&watchdog_miscdev);
if (err != 0) {
- pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
- watchdog->info->identity, WATCHDOG_MINOR, err);
+ pr_err("%s: cannot register miscdev on minor=%d (err=%d)\n",
+ watchdog->info->identity, WATCHDOG_MINOR, err);
goto out;
}
@@ -383,8 +387,8 @@ int watchdog_dev_unregister(struct watchdog_device *watchdog)
/* We can only unregister the watchdog device that was registered */
if (watchdog != wdd) {
- pr_err("%s: watchdog was not registered as /dev/watchdog.\n",
- watchdog->info->identity);
+ pr_err("%s: watchdog was not registered as /dev/watchdog\n",
+ watchdog->info->identity);
return -ENODEV;
}
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
index 94ec22b9e66b..0a77655cda60 100644
--- a/drivers/watchdog/wdrtas.c
+++ b/drivers/watchdog/wdrtas.c
@@ -26,6 +26,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -49,7 +51,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS_MISCDEV(TEMP_MINOR);
-static int wdrtas_nowayout = WATCHDOG_NOWAYOUT;
+static bool wdrtas_nowayout = WATCHDOG_NOWAYOUT;
static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
static char wdrtas_expect_close;
@@ -93,8 +95,8 @@ static int wdrtas_set_interval(int interval)
result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
WDRTAS_SURVEILLANCE_IND, 0, interval);
if (result < 0 && print_msg) {
- printk(KERN_ERR "wdrtas: setting the watchdog to %i "
- "timeout failed: %li\n", interval, result);
+ pr_err("setting the watchdog to %i timeout failed: %li\n",
+ interval, result);
print_msg--;
}
@@ -128,8 +130,8 @@ static int wdrtas_get_interval(int fallback_value)
spin_unlock(&rtas_data_buf_lock);
if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
- printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
- "timeout (%li). Continuing\n", result);
+ pr_warn("could not get sp_spi watchdog timeout (%li). Continuing\n",
+ result);
return fallback_value;
}
@@ -170,18 +172,18 @@ static void wdrtas_log_scanned_event(void)
int i;
for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
- printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = "
- "%02x %02x %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x\n",
- (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
- wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
- wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
- wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
- wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
- wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
- wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
- wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
- wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
+ pr_info("dumping event (line %i/%i), data = "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
+ wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
+ wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
+ wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
+ wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
+ wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
+ wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
+ wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
+ wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
}
/**
@@ -201,8 +203,7 @@ static void wdrtas_timer_keepalive(void)
(void *)__pa(wdrtas_logbuffer),
WDRTAS_LOGBUFFER_LEN);
if (result < 0)
- printk(KERN_ERR "wdrtas: event-scan failed: %li\n",
- result);
+ pr_err("event-scan failed: %li\n", result);
if (result == 0)
wdrtas_log_scanned_event();
} while (result == 0);
@@ -224,8 +225,7 @@ static int wdrtas_get_temperature(void)
result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
if (result < 0)
- printk(KERN_WARNING "wdrtas: reading the thermal sensor "
- "failed: %i\n", result);
+ pr_warn("reading the thermal sensor failed: %i\n", result);
else
temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
@@ -419,8 +419,7 @@ static int wdrtas_close(struct inode *inode, struct file *file)
if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
wdrtas_timer_stop();
else {
- printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog "
- "not stopped.\n");
+ pr_warn("got unexpected close. Watchdog not stopped.\n");
wdrtas_timer_keepalive();
}
@@ -552,30 +551,24 @@ static int wdrtas_get_tokens(void)
{
wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_WARNING "wdrtas: couldn't get token for "
- "get-sensor-state. Trying to continue without "
- "temperature support.\n");
+ pr_warn("couldn't get token for get-sensor-state. Trying to continue without temperature support.\n");
}
wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_WARNING "wdrtas: couldn't get token for "
- "ibm,get-system-parameter. Trying to continue with "
- "a default timeout value of %i seconds.\n",
- WDRTAS_DEFAULT_INTERVAL);
+ pr_warn("couldn't get token for ibm,get-system-parameter. Trying to continue with a default timeout value of %i seconds.\n",
+ WDRTAS_DEFAULT_INTERVAL);
}
wdrtas_token_set_indicator = rtas_token("set-indicator");
if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_ERR "wdrtas: couldn't get token for "
- "set-indicator. Terminating watchdog code.\n");
+ pr_err("couldn't get token for set-indicator. Terminating watchdog code.\n");
return -EIO;
}
wdrtas_token_event_scan = rtas_token("event-scan");
if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_ERR "wdrtas: couldn't get token for event-scan. "
- "Terminating watchdog code.\n");
+ pr_err("couldn't get token for event-scan. Terminating watchdog code.\n");
return -EIO;
}
@@ -609,17 +602,14 @@ static int wdrtas_register_devs(void)
result = misc_register(&wdrtas_miscdev);
if (result) {
- printk(KERN_ERR "wdrtas: couldn't register watchdog misc "
- "device. Terminating watchdog code.\n");
+ pr_err("couldn't register watchdog misc device. Terminating watchdog code.\n");
return result;
}
if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
result = misc_register(&wdrtas_tempdev);
if (result) {
- printk(KERN_WARNING "wdrtas: couldn't register "
- "watchdog temperature misc device. Continuing "
- "without temperature support.\n");
+ pr_warn("couldn't register watchdog temperature misc device. Continuing without temperature support.\n");
wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
}
}
@@ -643,8 +633,7 @@ static int __init wdrtas_init(void)
return -ENODEV;
if (register_reboot_notifier(&wdrtas_notifier)) {
- printk(KERN_ERR "wdrtas: could not register reboot notifier. "
- "Terminating watchdog code.\n");
+ pr_err("could not register reboot notifier. Terminating watchdog code.\n");
wdrtas_unregister_devs();
return -ENODEV;
}
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index d2ef002be96b..ee4333c01109 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -32,6 +32,8 @@
* Matt Domsch : Added nowayout module option
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -46,7 +48,6 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include "wd501p.h"
static unsigned long wdt_is_open;
@@ -65,8 +66,8 @@ MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
__MODULE_STRING(WD_TIMO) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -252,11 +253,11 @@ static int wdt_get_temperature(void)
static void wdt_decode_501(int status)
{
if (!(status & WDC_SR_TGOOD))
- printk(KERN_CRIT "Overheat alarm.(%d)\n", inb_p(WDT_RT));
+ pr_crit("Overheat alarm (%d)\n", inb_p(WDT_RT));
if (!(status & WDC_SR_PSUOVER))
- printk(KERN_CRIT "PSU over voltage.\n");
+ pr_crit("PSU over voltage\n");
if (!(status & WDC_SR_PSUUNDR))
- printk(KERN_CRIT "PSU under voltage.\n");
+ pr_crit("PSU under voltage\n");
}
/**
@@ -280,25 +281,25 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
spin_lock(&wdt_lock);
status = inb_p(WDT_SR);
- printk(KERN_CRIT "WDT status %d\n", status);
+ pr_crit("WDT status %d\n", status);
if (type == 501) {
wdt_decode_501(status);
if (tachometer) {
if (!(status & WDC_SR_FANGOOD))
- printk(KERN_CRIT "Possible fan fault.\n");
+ pr_crit("Possible fan fault\n");
}
}
if (!(status & WDC_SR_WCCR)) {
#ifdef SOFTWARE_REBOOT
#ifdef ONLY_TESTING
- printk(KERN_CRIT "Would Reboot.\n");
+ pr_crit("Would Reboot\n");
#else
- printk(KERN_CRIT "Initiating system reboot.\n");
+ pr_crit("Initiating system reboot\n");
emergency_restart();
#endif
#else
- printk(KERN_CRIT "Reset in 5ms.\n");
+ pr_crit("Reset in 5ms\n");
#endif
}
spin_unlock(&wdt_lock);
@@ -441,8 +442,7 @@ static int wdt_release(struct inode *inode, struct file *file)
wdt_stop();
clear_bit(0, &wdt_is_open);
} else {
- printk(KERN_CRIT
- "wdt: WDT device closed unexpectedly. WDT will not stop!\n");
+ pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
wdt_ping();
}
expect_close = 0;
@@ -593,7 +593,7 @@ static int __init wdt_init(void)
int ret;
if (type != 500 && type != 501) {
- printk(KERN_ERR "wdt: unknown card type '%d'.\n", type);
+ pr_err("unknown card type '%d'\n", type);
return -ENODEV;
}
@@ -601,53 +601,49 @@ static int __init wdt_init(void)
if not reset to the default */
if (wdt_set_heartbeat(heartbeat)) {
wdt_set_heartbeat(WD_TIMO);
- printk(KERN_INFO "wdt: heartbeat value must be "
- "0 < heartbeat < 65536, using %d\n", WD_TIMO);
+ pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
+ WD_TIMO);
}
if (!request_region(io, 8, "wdt501p")) {
- printk(KERN_ERR
- "wdt: I/O address 0x%04x already in use\n", io);
+ pr_err("I/O address 0x%04x already in use\n", io);
ret = -EBUSY;
goto out;
}
ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL);
if (ret) {
- printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
+ pr_err("IRQ %d is not free\n", irq);
goto outreg;
}
ret = register_reboot_notifier(&wdt_notifier);
if (ret) {
- printk(KERN_ERR
- "wdt: cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto outirq;
}
if (type == 501) {
ret = misc_register(&temp_miscdev);
if (ret) {
- printk(KERN_ERR "wdt: cannot register miscdev "
- "on minor=%d (err=%d)\n", TEMP_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ TEMP_MINOR, ret);
goto outrbt;
}
}
ret = misc_register(&wdt_miscdev);
if (ret) {
- printk(KERN_ERR
- "wdt: cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto outmisc;
}
- printk(KERN_INFO "WDT500/501-P driver 0.10 "
- "at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
+ pr_info("WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
io, irq, heartbeat, nowayout);
if (type == 501)
- printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
- (tachometer ? "Enabled" : "Disabled"));
+ pr_info("Fan Tachometer is %s\n",
+ tachometer ? "Enabled" : "Disabled");
return 0;
outmisc:
diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c
index f55135662d78..5eec74053882 100644
--- a/drivers/watchdog/wdt285.c
+++ b/drivers/watchdog/wdt285.c
@@ -16,6 +16,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -32,6 +34,7 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
+#include <asm/system_info.h>
#include <asm/hardware/dec21285.h>
/*
@@ -49,7 +52,7 @@ static unsigned long timer_alive;
*/
static void watchdog_fire(int irq, void *dev_id)
{
- printk(KERN_CRIT "Watchdog: Would Reboot.\n");
+ pr_crit("Would Reboot\n");
*CSR_TIMER4_CNTL = 0;
*CSR_TIMER4_CLR = 0;
}
@@ -205,13 +208,11 @@ static int __init footbridge_watchdog_init(void)
if (retval < 0)
return retval;
- printk(KERN_INFO
- "Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
- soft_margin);
+ pr_info("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
+ soft_margin);
if (machine_is_cats())
- printk(KERN_WARNING
- "Warning: Watchdog reset may not work on this machine.\n");
+ pr_warn("Warning: Watchdog reset may not work on this machine\n");
return 0;
}
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index a2f01c9f5c34..65a402344933 100644
--- a/drivers/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -23,6 +23,8 @@
* Netwinders only
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -37,13 +39,10 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#include <asm/mach-types.h>
#define WATCHDOG_VERSION "0.04"
#define WATCHDOG_NAME "Wdt977"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
#define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */
#define IO_DATA_PORT (IO_INDEX_PORT + 1)
@@ -68,8 +67,8 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300, default="
module_param(testmode, int, 0);
MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -119,7 +118,7 @@ static int wdt977_start(void)
outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags);
- printk(KERN_INFO PFX "activated.\n");
+ pr_info("activated\n");
return 0;
}
@@ -164,7 +163,7 @@ static int wdt977_stop(void)
outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags);
- printk(KERN_INFO PFX "shutdown.\n");
+ pr_info("shutdown\n");
return 0;
}
@@ -288,8 +287,7 @@ static int wdt977_release(struct inode *inode, struct file *file)
clear_bit(0, &timer_alive);
} else {
wdt977_keepalive();
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
}
expect_close = 0;
return 0;
@@ -446,15 +444,14 @@ static int __init wd977_init(void)
{
int rc;
- printk(KERN_INFO PFX DRIVER_VERSION);
+ pr_info("driver v%s\n", WATCHDOG_VERSION);
/* Check that the timeout value is within its range;
if not reset to the default */
if (wdt977_set_timeout(timeout)) {
wdt977_set_timeout(DEFAULT_TIMEOUT);
- printk(KERN_INFO PFX
- "timeout value must be 60 < timeout < 15300, using %d\n",
- DEFAULT_TIMEOUT);
+ pr_info("timeout value must be 60 < timeout < 15300, using %d\n",
+ DEFAULT_TIMEOUT);
}
/* on Netwinder the IOports are already reserved by
@@ -462,9 +459,8 @@ static int __init wd977_init(void)
*/
if (!machine_is_netwinder()) {
if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
- printk(KERN_ERR PFX
- "I/O address 0x%04x already in use\n",
- IO_INDEX_PORT);
+ pr_err("I/O address 0x%04x already in use\n",
+ IO_INDEX_PORT);
rc = -EIO;
goto err_out;
}
@@ -472,22 +468,19 @@ static int __init wd977_init(void)
rc = register_reboot_notifier(&wdt977_notifier);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", rc);
+ pr_err("cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region;
}
rc = misc_register(&wdt977_miscdev);
if (rc) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- wdt977_miscdev.minor, rc);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ wdt977_miscdev.minor, rc);
goto err_out_reboot;
}
- printk(KERN_INFO PFX
- "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
- timeout, nowayout, testmode);
+ pr_info("initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
+ timeout, nowayout, testmode);
return 0;
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index e0fc3baa9197..1c888c7d4cce 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -37,6 +37,8 @@
* Matt Domsch : nowayout module option
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -53,13 +55,10 @@
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <asm/system.h>
#define WDT_IS_PCI
#include "wd501p.h"
-#define PFX "wdt_pci: "
-
/* We can only use 1 card due to the /dev/watchdog restriction */
static int dev_count;
@@ -80,8 +79,8 @@ MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat in seconds. (0<heartbeat<65536, default="
__MODULE_STRING(WD_TIMO) ")");
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -312,33 +311,32 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
status = inb(WDT_SR);
udelay(8);
- printk(KERN_CRIT PFX "status %d\n", status);
+ pr_crit("status %d\n", status);
if (type == 501) {
if (!(status & WDC_SR_TGOOD)) {
- printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",
- inb(WDT_RT));
+ pr_crit("Overheat alarm (%d)\n", inb(WDT_RT));
udelay(8);
}
if (!(status & WDC_SR_PSUOVER))
- printk(KERN_CRIT PFX "PSU over voltage.\n");
+ pr_crit("PSU over voltage\n");
if (!(status & WDC_SR_PSUUNDR))
- printk(KERN_CRIT PFX "PSU under voltage.\n");
+ pr_crit("PSU under voltage\n");
if (tachometer) {
if (!(status & WDC_SR_FANGOOD))
- printk(KERN_CRIT PFX "Possible fan fault.\n");
+ pr_crit("Possible fan fault\n");
}
}
if (!(status & WDC_SR_WCCR)) {
#ifdef SOFTWARE_REBOOT
#ifdef ONLY_TESTING
- printk(KERN_CRIT PFX "Would Reboot.\n");
+ pr_crit("Would Reboot\n");
#else
- printk(KERN_CRIT PFX "Initiating system reboot.\n");
+ pr_crit("Initiating system reboot\n");
emergency_restart(NULL);
#endif
#else
- printk(KERN_CRIT PFX "Reset in 5ms.\n");
+ pr_crit("Reset in 5ms\n");
#endif
}
spin_unlock(&wdtpci_lock);
@@ -484,7 +482,7 @@ static int wdtpci_release(struct inode *inode, struct file *file)
if (expect_close == 42) {
wdtpci_stop();
} else {
- printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
+ pr_crit("Unexpected close, not stopping timer!\n");
wdtpci_ping();
}
expect_close = 0;
@@ -614,29 +612,29 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
dev_count++;
if (dev_count > 1) {
- printk(KERN_ERR PFX "This driver only supports one device\n");
+ pr_err("This driver only supports one device\n");
return -ENODEV;
}
if (type != 500 && type != 501) {
- printk(KERN_ERR PFX "unknown card type '%d'.\n", type);
+ pr_err("unknown card type '%d'\n", type);
return -ENODEV;
}
if (pci_enable_device(dev)) {
- printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+ pr_err("Not possible to enable PCI Device\n");
return -ENODEV;
}
if (pci_resource_start(dev, 2) == 0x0000) {
- printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+ pr_err("No I/O-Address for card detected\n");
ret = -ENODEV;
goto out_pci;
}
if (pci_request_region(dev, 2, "wdt_pci")) {
- printk(KERN_ERR PFX "I/O address 0x%llx already in use\n",
- (unsigned long long)pci_resource_start(dev, 2));
+ pr_err("I/O address 0x%llx already in use\n",
+ (unsigned long long)pci_resource_start(dev, 2));
goto out_pci;
}
@@ -645,53 +643,48 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED,
"wdt_pci", &wdtpci_miscdev)) {
- printk(KERN_ERR PFX "IRQ %d is not free\n", irq);
+ pr_err("IRQ %d is not free\n", irq);
goto out_reg;
}
- printk(KERN_INFO
- "PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
- (unsigned long long)io, irq);
+ pr_info("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
+ (unsigned long long)io, irq);
/* Check that the heartbeat value is within its range;
if not reset to the default */
if (wdtpci_set_heartbeat(heartbeat)) {
wdtpci_set_heartbeat(WD_TIMO);
- printk(KERN_INFO PFX
- "heartbeat value must be 0 < heartbeat < 65536, using %d\n",
- WD_TIMO);
+ pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
+ WD_TIMO);
}
ret = register_reboot_notifier(&wdtpci_notifier);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register reboot notifier (err=%d)\n", ret);
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
goto out_irq;
}
if (type == 501) {
ret = misc_register(&temp_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- TEMP_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ TEMP_MINOR, ret);
goto out_rbt;
}
}
ret = misc_register(&wdtpci_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
goto out_misc;
}
- printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+ pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
if (type == 501)
- printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
- (tachometer ? "Enabled" : "Disabled"));
+ pr_info("Fan Tachometer is %s\n",
+ tachometer ? "Enabled" : "Disabled");
ret = 0;
out:
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index 263c883f0806..b1815c5ed7a7 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -22,8 +22,8 @@
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/watchdog.h>
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -163,6 +163,8 @@ static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev,
ret);
}
+ wdt_dev->timeout = timeout;
+
return ret;
}
diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c
index 5d7113c7e501..3c76693447fd 100644
--- a/drivers/watchdog/wm8350_wdt.c
+++ b/drivers/watchdog/wm8350_wdt.c
@@ -8,63 +8,65 @@
* as published by the Free Software Foundation
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <linux/mfd/wm8350/core.h>
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-static unsigned long wm8350_wdt_users;
-static struct miscdevice wm8350_wdt_miscdev;
-static int wm8350_wdt_expect_close;
static DEFINE_MUTEX(wdt_mutex);
static struct {
- int time; /* Seconds */
- u16 val; /* To be set in WM8350_SYSTEM_CONTROL_2 */
+ unsigned int time; /* Seconds */
+ u16 val; /* To be set in WM8350_SYSTEM_CONTROL_2 */
} wm8350_wdt_cfgs[] = {
{ 1, 0x02 },
{ 2, 0x04 },
{ 4, 0x05 },
};
-static struct wm8350 *get_wm8350(void)
-{
- return dev_get_drvdata(wm8350_wdt_miscdev.parent);
-}
-
-static int wm8350_wdt_set_timeout(struct wm8350 *wm8350, u16 value)
+static int wm8350_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ unsigned int timeout)
{
- int ret;
+ struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
+ int ret, i;
u16 reg;
+ for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
+ if (wm8350_wdt_cfgs[i].time == timeout)
+ break;
+ if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
+ return -EINVAL;
+
mutex_lock(&wdt_mutex);
wm8350_reg_unlock(wm8350);
reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
reg &= ~WM8350_WDOG_TO_MASK;
- reg |= value;
+ reg |= wm8350_wdt_cfgs[i].val;
ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
wm8350_reg_lock(wm8350);
mutex_unlock(&wdt_mutex);
+ wdt_dev->timeout = timeout;
return ret;
}
-static int wm8350_wdt_start(struct wm8350 *wm8350)
+static int wm8350_wdt_start(struct watchdog_device *wdt_dev)
{
+ struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
int ret;
u16 reg;
@@ -82,8 +84,9 @@ static int wm8350_wdt_start(struct wm8350 *wm8350)
return ret;
}
-static int wm8350_wdt_stop(struct wm8350 *wm8350)
+static int wm8350_wdt_stop(struct watchdog_device *wdt_dev)
{
+ struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
int ret;
u16 reg;
@@ -100,8 +103,9 @@ static int wm8350_wdt_stop(struct wm8350 *wm8350)
return ret;
}
-static int wm8350_wdt_kick(struct wm8350 *wm8350)
+static int wm8350_wdt_ping(struct watchdog_device *wdt_dev)
{
+ struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
int ret;
u16 reg;
@@ -115,168 +119,25 @@ static int wm8350_wdt_kick(struct wm8350 *wm8350)
return ret;
}
-static int wm8350_wdt_open(struct inode *inode, struct file *file)
-{
- struct wm8350 *wm8350 = get_wm8350();
- int ret;
-
- if (!wm8350)
- return -ENODEV;
-
- if (test_and_set_bit(0, &wm8350_wdt_users))
- return -EBUSY;
-
- ret = wm8350_wdt_start(wm8350);
- if (ret != 0)
- return ret;
-
- return nonseekable_open(inode, file);
-}
-
-static int wm8350_wdt_release(struct inode *inode, struct file *file)
-{
- struct wm8350 *wm8350 = get_wm8350();
-
- if (wm8350_wdt_expect_close)
- wm8350_wdt_stop(wm8350);
- else {
- dev_warn(wm8350->dev, "Watchdog device closed uncleanly\n");
- wm8350_wdt_kick(wm8350);
- }
-
- clear_bit(0, &wm8350_wdt_users);
-
- return 0;
-}
-
-static ssize_t wm8350_wdt_write(struct file *file,
- const char __user *data, size_t count,
- loff_t *ppos)
-{
- struct wm8350 *wm8350 = get_wm8350();
- size_t i;
-
- if (count) {
- wm8350_wdt_kick(wm8350);
-
- if (!nowayout) {
- /* In case it was set long ago */
- wm8350_wdt_expect_close = 0;
-
- /* scan to see whether or not we got the magic
- character */
- for (i = 0; i != count; i++) {
- char c;
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- wm8350_wdt_expect_close = 42;
- }
- }
- }
- return count;
-}
-
-static const struct watchdog_info ident = {
+static const struct watchdog_info wm8350_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.identity = "WM8350 Watchdog",
};
-static long wm8350_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct wm8350 *wm8350 = get_wm8350();
- int ret = -ENOTTY, time, i;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
- u16 reg;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(0, p);
- break;
-
- case WDIOC_SETOPTIONS:
- {
- int options;
-
- if (get_user(options, p))
- return -EFAULT;
-
- ret = -EINVAL;
-
- /* Setting both simultaneously means at least one must fail */
- if (options == WDIOS_DISABLECARD)
- ret = wm8350_wdt_stop(wm8350);
-
- if (options == WDIOS_ENABLECARD)
- ret = wm8350_wdt_start(wm8350);
- break;
- }
-
- case WDIOC_KEEPALIVE:
- ret = wm8350_wdt_kick(wm8350);
- break;
-
- case WDIOC_SETTIMEOUT:
- ret = get_user(time, p);
- if (ret)
- break;
-
- if (time == 0) {
- if (nowayout)
- ret = -EINVAL;
- else
- wm8350_wdt_stop(wm8350);
- break;
- }
-
- for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
- if (wm8350_wdt_cfgs[i].time == time)
- break;
- if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
- ret = -EINVAL;
- else
- ret = wm8350_wdt_set_timeout(wm8350,
- wm8350_wdt_cfgs[i].val);
- break;
-
- case WDIOC_GETTIMEOUT:
- reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
- reg &= WM8350_WDOG_TO_MASK;
- for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
- if (wm8350_wdt_cfgs[i].val == reg)
- break;
- if (i == ARRAY_SIZE(wm8350_wdt_cfgs)) {
- dev_warn(wm8350->dev,
- "Unknown watchdog configuration: %x\n", reg);
- ret = -EINVAL;
- } else
- ret = put_user(wm8350_wdt_cfgs[i].time, p);
-
- }
-
- return ret;
-}
-
-static const struct file_operations wm8350_wdt_fops = {
+static const struct watchdog_ops wm8350_wdt_ops = {
.owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = wm8350_wdt_write,
- .unlocked_ioctl = wm8350_wdt_ioctl,
- .open = wm8350_wdt_open,
- .release = wm8350_wdt_release,
+ .start = wm8350_wdt_start,
+ .stop = wm8350_wdt_stop,
+ .ping = wm8350_wdt_ping,
+ .set_timeout = wm8350_wdt_set_timeout,
};
-static struct miscdevice wm8350_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &wm8350_wdt_fops,
+static struct watchdog_device wm8350_wdt = {
+ .info = &wm8350_wdt_info,
+ .ops = &wm8350_wdt_ops,
+ .timeout = 4,
+ .min_timeout = 1,
+ .max_timeout = 4,
};
static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
@@ -288,18 +149,18 @@ static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
return -ENODEV;
}
- /* Default to 4s timeout */
- wm8350_wdt_set_timeout(wm8350, 0x05);
+ watchdog_set_nowayout(&wm8350_wdt, nowayout);
+ watchdog_set_drvdata(&wm8350_wdt, wm8350);
- wm8350_wdt_miscdev.parent = &pdev->dev;
+ /* Default to 4s timeout */
+ wm8350_wdt_set_timeout(&wm8350_wdt, 4);
- return misc_register(&wm8350_wdt_miscdev);
+ return watchdog_register_device(&wm8350_wdt);
}
static int __devexit wm8350_wdt_remove(struct platform_device *pdev)
{
- misc_deregister(&wm8350_wdt_miscdev);
-
+ watchdog_unregister_device(&wm8350_wdt);
return 0;
}
diff --git a/drivers/watchdog/xen_wdt.c b/drivers/watchdog/xen_wdt.c
index 49bd9d395562..e4a25b51165c 100644
--- a/drivers/watchdog/xen_wdt.c
+++ b/drivers/watchdog/xen_wdt.c
@@ -9,9 +9,10 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "wdt"
#define DRV_VERSION "0.01"
-#define PFX DRV_NAME ": "
#include <linux/bug.h>
#include <linux/errno.h>
@@ -131,16 +132,17 @@ static int xen_wdt_open(struct inode *inode, struct file *file)
static int xen_wdt_release(struct inode *inode, struct file *file)
{
+ int err = 0;
+
if (expect_release)
- xen_wdt_stop();
+ err = xen_wdt_stop();
else {
- printk(KERN_CRIT PFX
- "unexpected close, not stopping watchdog!\n");
+ pr_crit("unexpected close, not stopping watchdog!\n");
xen_wdt_kick();
}
- is_active = false;
+ is_active = err;
expect_release = false;
- return 0;
+ return err;
}
static ssize_t xen_wdt_write(struct file *file, const char __user *data,
@@ -251,30 +253,27 @@ static int __devinit xen_wdt_probe(struct platform_device *dev)
case -EINVAL:
if (!timeout) {
timeout = WATCHDOG_TIMEOUT;
- printk(KERN_INFO PFX
- "timeout value invalid, using %d\n", timeout);
+ pr_info("timeout value invalid, using %d\n", timeout);
}
ret = misc_register(&xen_wdt_miscdev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (%d)\n",
+ pr_err("cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
break;
}
- printk(KERN_INFO PFX
- "initialized (timeout=%ds, nowayout=%d)\n",
- timeout, nowayout);
+ pr_info("initialized (timeout=%ds, nowayout=%d)\n",
+ timeout, nowayout);
break;
case -ENOSYS:
- printk(KERN_INFO PFX "not supported\n");
+ pr_info("not supported\n");
ret = -ENODEV;
break;
default:
- printk(KERN_INFO PFX "bogus return value %d\n", ret);
+ pr_info("bogus return value %d\n", ret);
break;
}
@@ -299,11 +298,18 @@ static void xen_wdt_shutdown(struct platform_device *dev)
static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
{
- return xen_wdt_stop();
+ typeof(wdt.id) id = wdt.id;
+ int rc = xen_wdt_stop();
+
+ wdt.id = id;
+ return rc;
}
static int xen_wdt_resume(struct platform_device *dev)
{
+ if (!wdt.id)
+ return 0;
+ wdt.id = 0;
return xen_wdt_start();
}
@@ -326,7 +332,7 @@ static int __init xen_wdt_init_module(void)
if (!xen_domain())
return -ENODEV;
- printk(KERN_INFO PFX "Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
+ pr_info("Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
err = platform_driver_register(&xen_wdt_driver);
if (err)
@@ -346,7 +352,7 @@ static void __exit xen_wdt_cleanup_module(void)
{
platform_device_unregister(platform_device);
platform_driver_unregister(&xen_wdt_driver);
- printk(KERN_INFO PFX "module unloaded\n");
+ pr_info("module unloaded\n");
}
module_init(xen_wdt_init_module);