Merge tag 'driver-core-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 15 Dec 2014 00:10:09 +0000 (16:10 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 15 Dec 2014 00:10:09 +0000 (16:10 -0800)
Pull driver core update from Greg KH:
 "Here's the set of driver core patches for 3.19-rc1.

  They are dominated by the removal of the .owner field in platform
  drivers.  They touch a lot of files, but they are "simple" changes,
  just removing a line in a structure.

  Other than that, a few minor driver core and debugfs changes.  There
  are some ath9k patches coming in through this tree that have been
  acked by the wireless maintainers as they relied on the debugfs
  changes.

  Everything has been in linux-next for a while"

* tag 'driver-core-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (324 commits)
  Revert "ath: ath9k: use debugfs_create_devm_seqfile() helper for seq_file entries"
  fs: debugfs: add forward declaration for struct device type
  firmware class: Deletion of an unnecessary check before the function call "vunmap"
  firmware loader: fix hung task warning dump
  devcoredump: provide a one-way disable function
  device: Add dev_<level>_once variants
  ath: ath9k: use debugfs_create_devm_seqfile() helper for seq_file entries
  ath: use seq_file api for ath9k debugfs files
  debugfs: add helper function to create device related seq_file
  drivers/base: cacheinfo: remove noisy error boot message
  Revert "core: platform: add warning if driver has no owner"
  drivers: base: support cpu cache information interface to userspace via sysfs
  drivers: base: add cpu_device_create to support per-cpu devices
  topology: replace custom attribute macros with standard DEVICE_ATTR*
  cpumask: factor out show_cpumap into separate helper function
  driver core: Fix unbalanced device reference in drivers_probe
  driver core: fix race with userland in device_add()
  sysfs/kernfs: make read requests on pre-alloc files use the buffer.
  sysfs/kernfs: allow attributes to request write buffer be pre-allocated.
  fs: sysfs: return EGBIG on write if offset is larger than file size
  ...

418 files changed:
1  2 
arch/arm/common/sa1111.c
arch/arm/mach-davinci/cpuidle.c
arch/arm/mach-imx/mmdc.c
arch/arm/mach-pxa/pxa3xx-ulpi.c
arch/mips/lantiq/xway/xrx200_phy_fw.c
arch/mips/pci/pci-ar71xx.c
arch/mips/pci/pci-ar724x.c
arch/mips/pci/pci-rt3883.c
arch/powerpc/platforms/85xx/sgy_cts1000.c
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/ppc4xx_hsta_msi.c
arch/powerpc/sysdev/ppc4xx_msi.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/sparc/kernel/pci_schizo.c
drivers/acpi/apei/ghes.c
drivers/ata/ahci_sunxi.c
drivers/ata/sata_fsl.c
drivers/ata/sata_rcar.c
drivers/base/Makefile
drivers/base/core.c
drivers/base/platform.c
drivers/bus/brcmstb_gisb.c
drivers/bus/omap_l3_noc.c
drivers/char/hw_random/atmel-rng.c
drivers/char/hw_random/exynos-rng.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/clk/clk-s2mps11.c
drivers/cpufreq/arm_big_little_dt.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/exynos5440-cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpuidle/cpuidle-at91.c
drivers/cpuidle/cpuidle-calxeda.c
drivers/cpuidle/cpuidle-exynos.c
drivers/cpuidle/cpuidle-kirkwood.c
drivers/cpuidle/cpuidle-mvebu-v7.c
drivers/cpuidle/cpuidle-ux500.c
drivers/cpuidle/cpuidle-zynq.c
drivers/crypto/bfin_crc.c
drivers/crypto/caam/jr.c
drivers/crypto/sahara.c
drivers/crypto/ux500/cryp/cryp_core.c
drivers/crypto/ux500/hash/hash_core.c
drivers/dma/edma.c
drivers/dma/fsl-edma.c
drivers/dma/fsldma.c
drivers/dma/omap-dma.c
drivers/dma/sa11x0-dma.c
drivers/dma/sh/shdmac.c
drivers/dma/sirf-dma.c
drivers/dma/ste_dma40.c
drivers/edac/ppc4xx_edac.c
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-cs5535.c
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-grgpio.c
drivers/gpio/gpio-msm-v1.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-mxs.c
drivers/gpio/gpio-sch.c
drivers/gpio/gpio-spear-spics.c
drivers/gpio/gpio-stp-xway.c
drivers/gpio/gpio-tb10x.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-tz1090.c
drivers/gpio/gpio-vr41xx.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/hsi/controllers/omap_ssi.c
drivers/hsi/controllers/omap_ssi_port.c
drivers/hwmon/ibmpowernv.c
drivers/hwmon/iio_hwmon.c
drivers/hwmon/nct6775.c
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-exynos5.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-isch.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-parport-light.c
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-rk3x.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-simtec.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/busses/scx200_acb.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/samsung-keypad.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/iommu/arm-smmu.c
drivers/iommu/exynos-iommu.c
drivers/iommu/ipmmu-vmsa.c
drivers/leds/leds-gpio.c
drivers/mailbox/omap-mailbox.c
drivers/media/platform/blackfin/bfin_capture.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/davinci/vpbe.c
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos4-is/fimc-core.c
drivers/media/platform/exynos4-is/fimc-is-i2c.c
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-lite.c
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/fsl-viu.c
drivers/media/platform/mx2_emmaprp.c
drivers/media/platform/s3c-camif/camif-core.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-tv/hdmi_drv.c
drivers/media/platform/s5p-tv/sdo_drv.c
drivers/media/platform/sh_vou.c
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/mx3_camera.c
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/platform/soc_camera/sh_mobile_csi2.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/soc_camera/soc_camera_platform.c
drivers/media/platform/vim2m.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/si4713/radio-platform-si4713.c
drivers/memory/omap-gpmc.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/syscon.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/twl4030-power.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/tmio_mmc.c
drivers/net/can/c_can/c_can_platform.c
drivers/net/can/flexcan.c
drivers/net/can/rcar_can.c
drivers/net/can/xilinx_can.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/natsemi/macsonic.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sunhme.c
drivers/net/ethernet/wiznet/w5100.c
drivers/net/ethernet/wiznet/w5300.c
drivers/net/ieee802154/fakelb.c
drivers/net/irda/ali-ircc.c
drivers/net/phy/mdio-mux-gpio.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/mac80211_hwsim.c
drivers/pci/host/pci-dra7xx.c
drivers/pci/host/pci-exynos.c
drivers/pci/host/pci-host-generic.c
drivers/pci/host/pci-imx6.c
drivers/pci/host/pci-keystone.c
drivers/pci/host/pci-mvebu.c
drivers/pci/host/pci-tegra.c
drivers/pci/host/pci-xgene.c
drivers/pci/host/pcie-rcar.c
drivers/pci/host/pcie-spear13xx.c
drivers/pci/host/pcie-xilinx.c
drivers/pci/pci-sysfs.c
drivers/pcmcia/sa1100_generic.c
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/nomadik/pinctrl-abx500.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-bcm281xx.c
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/pinctrl-tb10x.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/spear/pinctrl-plgpio.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/ideapad-laptop.c
drivers/power/ab8500_fg.c
drivers/power/charger-manager.c
drivers/regulator/88pm8607.c
drivers/regulator/anatop-regulator.c
drivers/regulator/arizona-ldo1.c
drivers/regulator/arizona-micsupp.c
drivers/regulator/da9052-regulator.c
drivers/regulator/da9063-regulator.c
drivers/regulator/dummy.c
drivers/regulator/fixed.c
drivers/regulator/gpio-regulator.c
drivers/regulator/max77686.c
drivers/regulator/max77693.c
drivers/regulator/max77802.c
drivers/regulator/max8997.c
drivers/regulator/max8998.c
drivers/regulator/pwm-regulator.c
drivers/regulator/qcom_rpm-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/s2mpa01.c
drivers/regulator/s2mps11.c
drivers/regulator/s5m8767.c
drivers/regulator/stw481x-vmmc.c
drivers/regulator/ti-abb-regulator.c
drivers/regulator/tps65090-regulator.c
drivers/regulator/tps65218-regulator.c
drivers/regulator/twl-regulator.c
drivers/regulator/vexpress.c
drivers/regulator/wm8994-regulator.c
drivers/remoteproc/omap_remoteproc.c
drivers/reset/reset-socfpga.c
drivers/rtc/rtc-ab8500.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-sirfsoc.c
drivers/rtc/rtc-snvs.c
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/soc/ti/knav_qmss_queue.c
drivers/spi/spi-atmel.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-gpio.c
drivers/spi/spi-mxs.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sirf.c
drivers/spi/spi-txx9.c
drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
drivers/thermal/imx_thermal.c
drivers/thermal/samsung/exynos_tmu.c
drivers/tty/ehv_bytechan.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_em.c
drivers/tty/serial/ar933x_uart.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/bcm63xx_uart.c
drivers/tty/serial/bfin_uart.c
drivers/tty/serial/clps711x.c
drivers/tty/serial/cpm_uart/cpm_uart_core.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/imx.c
drivers/tty/serial/lantiq.c
drivers/tty/serial/mcf.c
drivers/tty/serial/mpsc.c
drivers/tty/serial/msm_serial.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/pmac_zilog.c
drivers/tty/serial/pnx8xxx_uart.c
drivers/tty/serial/pxa.c
drivers/tty/serial/sa1100.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sirfsoc_uart.c
drivers/tty/serial/sunsab.c
drivers/tty/serial/sunsu.c
drivers/tty/serial/sunzilog.c
drivers/tty/serial/timbuart.c
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/usbmisc_imx.c
drivers/usb/gadget/legacy/hid.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/bcm63xx_udc.c
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/gadget/udc/fotg210-udc.c
drivers/usb/gadget/udc/fsl_qe_udc.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/fusb300_udc.c
drivers/usb/gadget/udc/gr_udc.c
drivers/usb/gadget/udc/lpc32xx_udc.c
drivers/usb/gadget/udc/m66592-udc.c
drivers/usb/gadget/udc/mv_u3d_core.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/gadget/udc/pxa25x_udc.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/gadget/udc/s3c-hsudc.c
drivers/usb/gadget/udc/s3c2410_udc.c
drivers/usb/host/ehci-exynos.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-w90x900.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-exynos.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-platform.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-spear.c
drivers/usb/host/u132-hcd.c
drivers/usb/misc/usb3503.c
drivers/usb/musb/musb_core.c
drivers/usb/phy/phy-ab8500-usb.c
drivers/usb/phy/phy-am335x-control.c
drivers/usb/phy/phy-generic.c
drivers/usb/phy/phy-gpio-vbus-usb.c
drivers/usb/phy/phy-isp1301-omap.c
drivers/usb/phy/phy-mv-usb.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/phy/phy-tahvo.c
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/usbip/vhci_hcd.c
drivers/video/fbdev/exynos/exynos_mipi_dsi.c
drivers/video/fbdev/mmp/hw/mmp_ctrl.c
drivers/video/fbdev/mx3fb.c
drivers/video/fbdev/omap2/displays-new/connector-dvi.c
drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
drivers/video/fbdev/omap2/dss/dispc.c
drivers/video/fbdev/omap2/dss/dpi.c
drivers/video/fbdev/omap2/dss/dsi.c
drivers/video/fbdev/omap2/dss/dss.c
drivers/video/fbdev/omap2/dss/hdmi4.c
drivers/video/fbdev/omap2/dss/hdmi5.c
drivers/video/fbdev/omap2/dss/sdi.c
drivers/video/fbdev/sa1100fb.c
drivers/video/fbdev/sh_mobile_lcdcfb.c
drivers/video/fbdev/simplefb.c
drivers/video/fbdev/sm501fb.c
drivers/virtio/virtio_mmio.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/s3c2410_wdt.c
fs/debugfs/file.c
fs/pstore/ram.c
include/linux/bitmap.h
include/linux/debugfs.h
include/linux/device.h
lib/bitmap.c
net/dsa/dsa.c
net/rfkill/rfkill-gpio.c
sound/atmel/abdac.c
sound/atmel/ac97c.c
sound/drivers/mts64.c
sound/drivers/virmidi.c
sound/mips/sgio2audio.c
sound/soc/au1x/ac97c.c
sound/soc/au1x/psc-ac97.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/cq93vc.c
sound/soc/codecs/hdmi.c
sound/soc/codecs/sirf-audio-codec.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-spdif.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-wm8962.c
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/generic/simple-card.c
sound/soc/intel/broadwell.c
sound/soc/intel/haswell.c
sound/soc/intel/sst-haswell-pcm.c
sound/soc/intel/sst-mfld-platform-pcm.c
sound/soc/jz4740/qi_lb60.c
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/samsung/ac97.c
sound/soc/samsung/i2s.c
sound/soc/samsung/odroidx2_max98090.c
sound/soc/samsung/snow.c
sound/soc/sh/hac.c
sound/soc/soc-core.c
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra_rt5640.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/txx9/txx9aclc.c
sound/soc/ux500/mop500.c
sound/sparc/cs4231.c

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -4,7 -4,7 +4,7 @@@ obj-y                    := component.o core.o bus.o dd.
                           driver.o class.o platform.o \
                           cpu.o firmware.o init.o map.o devres.o \
                           attribute_container.o transport_class.o \
-                          topology.o container.o property.o
 -                         topology.o container.o cacheinfo.o
++                         topology.o container.o property.o cacheinfo.o
  obj-$(CONFIG_DEVTMPFS)        += devtmpfs.o
  obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
  obj-y                 += power/
Simple merge
Simple merge
@@@ -387,11 -273,10 +387,10 @@@ static const struct dev_pm_ops brcmstb_
  };
  
  static struct platform_driver brcmstb_gisb_arb_driver = {
 -      .probe  = brcmstb_gisb_arb_probe,
        .driver = {
                .name   = "brcm-gisb-arb",
-               .owner  = THIS_MODULE,
                .of_match_table = brcmstb_gisb_arb_of_match,
 +              .pm     = &brcmstb_gisb_arb_pm_ops,
        },
  };
  
@@@ -358,8 -300,6 +358,7 @@@ static struct platform_driver omap_l3_d
        .probe          = omap_l3_probe,
        .driver         = {
                .name           = "omap_l3_noc",
-               .owner          = THIS_MODULE,
 +              .pm             = L3_DEV_PM_OPS,
                .of_match_table = of_match_ptr(l3_noc_match),
        },
  };
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -301,24 -309,50 +301,23 @@@ static int ibmpowernv_probe(struct plat
        return PTR_ERR_OR_ZERO(hwmon_dev);
  }
  
 -static struct platform_driver ibmpowernv_driver = {
 -      .driver = {
 -              .name = DRVNAME,
 +static const struct platform_device_id opal_sensor_driver_ids[] = {
 +      {
 +              .name = "opal-sensor",
        },
 +      { }
  };
 +MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
  
 -static int __init ibmpowernv_init(void)
 -{
 -      int err;
 -
 -      pdevice = platform_device_alloc(DRVNAME, 0);
 -      if (!pdevice) {
 -              pr_err("Device allocation failed\n");
 -              err = -ENOMEM;
 -              goto exit;
 -      }
 -
 -      err = platform_device_add(pdevice);
 -      if (err) {
 -              pr_err("Device addition failed (%d)\n", err);
 -              goto exit_device_put;
 -      }
 -
 -      err = platform_driver_probe(&ibmpowernv_driver, ibmpowernv_probe);
 -      if (err) {
 -              pr_err("Platfrom driver probe failed\n");
 -              goto exit_device_del;
 -      }
 -
 -      return 0;
 -
 -exit_device_del:
 -      platform_device_del(pdevice);
 -exit_device_put:
 -      platform_device_put(pdevice);
 -exit:
 -      return err;
 -}
 +static struct platform_driver ibmpowernv_driver = {
 +      .probe          = ibmpowernv_probe,
 +      .id_table       = opal_sensor_driver_ids,
 +      .driver         = {
-               .owner  = THIS_MODULE,
 +              .name   = DRVNAME,
 +      },
 +};
  
 -static void __exit ibmpowernv_exit(void)
 -{
 -      platform_driver_unregister(&ibmpowernv_driver);
 -      platform_device_unregister(pdevice);
 -}
 +module_platform_driver(ibmpowernv_driver);
  
  MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
  MODULE_DESCRIPTION("IBM POWERNV platform sensors");
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -297,8 -307,7 +297,7 @@@ static struct platform_driver gpio_keys
        .probe  = gpio_keys_polled_probe,
        .driver = {
                .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
 -              .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
 +              .of_match_table = gpio_keys_polled_of_match,
        },
  };
  module_platform_driver(gpio_keys_polled_driver);
Simple merge
Simple merge
Simple merge
@@@ -291,8 -287,7 +291,7 @@@ static struct platform_driver gpio_led_
        .remove         = gpio_led_remove,
        .driver         = {
                .name   = "leds-gpio",
-               .owner  = THIS_MODULE,
 -              .of_match_table = of_match_ptr(of_gpio_leds_match),
 +              .of_match_table = of_gpio_leds_match,
        },
  };
  
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 1105c11,0000000..d9d844a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1089 -1,0 +1,1088 @@@
-               .owner  = THIS_MODULE,
 +/*
 + * A virtual v4l2-mem2mem example device.
 + *
 + * This is a virtual device driver for testing mem-to-mem videobuf framework.
 + * It simulates a device that uses memory buffers for both source and
 + * destination, processes the data and issues an "irq" (simulated by a timer).
 + * The device is capable of multi-instance, multi-buffer-per-transaction
 + * operation (via the mem2mem framework).
 + *
 + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
 + * Pawel Osciak, <pawel@osciak.com>
 + * Marek Szyprowski, <m.szyprowski@samsung.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
 + */
 +#include <linux/module.h>
 +#include <linux/delay.h>
 +#include <linux/fs.h>
 +#include <linux/timer.h>
 +#include <linux/sched.h>
 +#include <linux/slab.h>
 +
 +#include <linux/platform_device.h>
 +#include <media/v4l2-mem2mem.h>
 +#include <media/v4l2-device.h>
 +#include <media/v4l2-ioctl.h>
 +#include <media/v4l2-ctrls.h>
 +#include <media/v4l2-event.h>
 +#include <media/videobuf2-vmalloc.h>
 +
 +MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
 +MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
 +MODULE_LICENSE("GPL");
 +MODULE_VERSION("0.1.1");
 +MODULE_ALIAS("mem2mem_testdev");
 +
 +static unsigned debug;
 +module_param(debug, uint, 0644);
 +MODULE_PARM_DESC(debug, "activates debug info");
 +
 +#define MIN_W 32
 +#define MIN_H 32
 +#define MAX_W 640
 +#define MAX_H 480
 +#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
 +
 +/* Flags that indicate a format can be used for capture/output */
 +#define MEM2MEM_CAPTURE       (1 << 0)
 +#define MEM2MEM_OUTPUT        (1 << 1)
 +
 +#define MEM2MEM_NAME          "vim2m"
 +
 +/* Per queue */
 +#define MEM2MEM_DEF_NUM_BUFS  VIDEO_MAX_FRAME
 +/* In bytes, per queue */
 +#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024)
 +
 +/* Default transaction time in msec */
 +#define MEM2MEM_DEF_TRANSTIME 40
 +#define MEM2MEM_COLOR_STEP    (0xff >> 4)
 +#define MEM2MEM_NUM_TILES     8
 +
 +/* Flags that indicate processing mode */
 +#define MEM2MEM_HFLIP (1 << 0)
 +#define MEM2MEM_VFLIP (1 << 1)
 +
 +#define dprintk(dev, fmt, arg...) \
 +      v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
 +
 +
 +static void vim2m_dev_release(struct device *dev)
 +{}
 +
 +static struct platform_device vim2m_pdev = {
 +      .name           = MEM2MEM_NAME,
 +      .dev.release    = vim2m_dev_release,
 +};
 +
 +struct vim2m_fmt {
 +      char    *name;
 +      u32     fourcc;
 +      int     depth;
 +      /* Types the format can be used for */
 +      u32     types;
 +};
 +
 +static struct vim2m_fmt formats[] = {
 +      {
 +              .name   = "RGB565 (BE)",
 +              .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
 +              .depth  = 16,
 +              /* Both capture and output format */
 +              .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 +      },
 +      {
 +              .name   = "4:2:2, packed, YUYV",
 +              .fourcc = V4L2_PIX_FMT_YUYV,
 +              .depth  = 16,
 +              /* Output-only format */
 +              .types  = MEM2MEM_OUTPUT,
 +      },
 +};
 +
 +#define NUM_FORMATS ARRAY_SIZE(formats)
 +
 +/* Per-queue, driver-specific private data */
 +struct vim2m_q_data {
 +      unsigned int            width;
 +      unsigned int            height;
 +      unsigned int            sizeimage;
 +      unsigned int            sequence;
 +      struct vim2m_fmt        *fmt;
 +};
 +
 +enum {
 +      V4L2_M2M_SRC = 0,
 +      V4L2_M2M_DST = 1,
 +};
 +
 +#define V4L2_CID_TRANS_TIME_MSEC      (V4L2_CID_USER_BASE + 0x1000)
 +#define V4L2_CID_TRANS_NUM_BUFS               (V4L2_CID_USER_BASE + 0x1001)
 +
 +static struct vim2m_fmt *find_format(struct v4l2_format *f)
 +{
 +      struct vim2m_fmt *fmt;
 +      unsigned int k;
 +
 +      for (k = 0; k < NUM_FORMATS; k++) {
 +              fmt = &formats[k];
 +              if (fmt->fourcc == f->fmt.pix.pixelformat)
 +                      break;
 +      }
 +
 +      if (k == NUM_FORMATS)
 +              return NULL;
 +
 +      return &formats[k];
 +}
 +
 +struct vim2m_dev {
 +      struct v4l2_device      v4l2_dev;
 +      struct video_device     *vfd;
 +
 +      atomic_t                num_inst;
 +      struct mutex            dev_mutex;
 +      spinlock_t              irqlock;
 +
 +      struct timer_list       timer;
 +
 +      struct v4l2_m2m_dev     *m2m_dev;
 +};
 +
 +struct vim2m_ctx {
 +      struct v4l2_fh          fh;
 +      struct vim2m_dev        *dev;
 +
 +      struct v4l2_ctrl_handler hdl;
 +
 +      /* Processed buffers in this transaction */
 +      u8                      num_processed;
 +
 +      /* Transaction length (i.e. how many buffers per transaction) */
 +      u32                     translen;
 +      /* Transaction time (i.e. simulated processing time) in milliseconds */
 +      u32                     transtime;
 +
 +      /* Abort requested by m2m */
 +      int                     aborting;
 +
 +      /* Processing mode */
 +      int                     mode;
 +
 +      enum v4l2_colorspace    colorspace;
 +
 +      /* Source and destination queue data */
 +      struct vim2m_q_data   q_data[2];
 +};
 +
 +static inline struct vim2m_ctx *file2ctx(struct file *file)
 +{
 +      return container_of(file->private_data, struct vim2m_ctx, fh);
 +}
 +
 +static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx,
 +                                       enum v4l2_buf_type type)
 +{
 +      switch (type) {
 +      case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 +              return &ctx->q_data[V4L2_M2M_SRC];
 +      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 +              return &ctx->q_data[V4L2_M2M_DST];
 +      default:
 +              BUG();
 +      }
 +      return NULL;
 +}
 +
 +
 +static int device_process(struct vim2m_ctx *ctx,
 +                        struct vb2_buffer *in_vb,
 +                        struct vb2_buffer *out_vb)
 +{
 +      struct vim2m_dev *dev = ctx->dev;
 +      struct vim2m_q_data *q_data;
 +      u8 *p_in, *p_out;
 +      int x, y, t, w;
 +      int tile_w, bytes_left;
 +      int width, height, bytesperline;
 +
 +      q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 +
 +      width   = q_data->width;
 +      height  = q_data->height;
 +      bytesperline    = (q_data->width * q_data->fmt->depth) >> 3;
 +
 +      p_in = vb2_plane_vaddr(in_vb, 0);
 +      p_out = vb2_plane_vaddr(out_vb, 0);
 +      if (!p_in || !p_out) {
 +              v4l2_err(&dev->v4l2_dev,
 +                       "Acquiring kernel pointers to buffers failed\n");
 +              return -EFAULT;
 +      }
 +
 +      if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) {
 +              v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
 +              return -EINVAL;
 +      }
 +
 +      tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
 +              / MEM2MEM_NUM_TILES;
 +      bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
 +      w = 0;
 +
 +      out_vb->v4l2_buf.sequence = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
 +      in_vb->v4l2_buf.sequence = q_data->sequence++;
 +      memcpy(&out_vb->v4l2_buf.timestamp,
 +                      &in_vb->v4l2_buf.timestamp,
 +                      sizeof(struct timeval));
 +      if (in_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TIMECODE)
 +              memcpy(&out_vb->v4l2_buf.timecode, &in_vb->v4l2_buf.timecode,
 +                      sizeof(struct v4l2_timecode));
 +      out_vb->v4l2_buf.field = in_vb->v4l2_buf.field;
 +      out_vb->v4l2_buf.flags = in_vb->v4l2_buf.flags &
 +              (V4L2_BUF_FLAG_TIMECODE |
 +               V4L2_BUF_FLAG_KEYFRAME |
 +               V4L2_BUF_FLAG_PFRAME |
 +               V4L2_BUF_FLAG_BFRAME |
 +               V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
 +
 +      switch (ctx->mode) {
 +      case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
 +              p_out += bytesperline * height - bytes_left;
 +              for (y = 0; y < height; ++y) {
 +                      for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 +                              if (w & 0x1) {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *--p_out = *p_in++ +
 +                                                      MEM2MEM_COLOR_STEP;
 +                              } else {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *--p_out = *p_in++ -
 +                                                      MEM2MEM_COLOR_STEP;
 +                              }
 +                              ++w;
 +                      }
 +                      p_in += bytes_left;
 +                      p_out -= bytes_left;
 +              }
 +              break;
 +
 +      case MEM2MEM_HFLIP:
 +              for (y = 0; y < height; ++y) {
 +                      p_out += MEM2MEM_NUM_TILES * tile_w;
 +                      for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 +                              if (w & 0x01) {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *--p_out = *p_in++ +
 +                                                      MEM2MEM_COLOR_STEP;
 +                              } else {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *--p_out = *p_in++ -
 +                                                      MEM2MEM_COLOR_STEP;
 +                              }
 +                              ++w;
 +                      }
 +                      p_in += bytes_left;
 +                      p_out += bytesperline;
 +              }
 +              break;
 +
 +      case MEM2MEM_VFLIP:
 +              p_out += bytesperline * (height - 1);
 +              for (y = 0; y < height; ++y) {
 +                      for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 +                              if (w & 0x1) {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *p_out++ = *p_in++ +
 +                                                      MEM2MEM_COLOR_STEP;
 +                              } else {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *p_out++ = *p_in++ -
 +                                                      MEM2MEM_COLOR_STEP;
 +                              }
 +                              ++w;
 +                      }
 +                      p_in += bytes_left;
 +                      p_out += bytes_left - 2 * bytesperline;
 +              }
 +              break;
 +
 +      default:
 +              for (y = 0; y < height; ++y) {
 +                      for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 +                              if (w & 0x1) {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *p_out++ = *p_in++ +
 +                                                      MEM2MEM_COLOR_STEP;
 +                              } else {
 +                                      for (x = 0; x < tile_w; ++x)
 +                                              *p_out++ = *p_in++ -
 +                                                      MEM2MEM_COLOR_STEP;
 +                              }
 +                              ++w;
 +                      }
 +                      p_in += bytes_left;
 +                      p_out += bytes_left;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +static void schedule_irq(struct vim2m_dev *dev, int msec_timeout)
 +{
 +      dprintk(dev, "Scheduling a simulated irq\n");
 +      mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
 +}
 +
 +/*
 + * mem2mem callbacks
 + */
 +
 +/**
 + * job_ready() - check whether an instance is ready to be scheduled to run
 + */
 +static int job_ready(void *priv)
 +{
 +      struct vim2m_ctx *ctx = priv;
 +
 +      if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen
 +          || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) {
 +              dprintk(ctx->dev, "Not enough buffers available\n");
 +              return 0;
 +      }
 +
 +      return 1;
 +}
 +
 +static void job_abort(void *priv)
 +{
 +      struct vim2m_ctx *ctx = priv;
 +
 +      /* Will cancel the transaction in the next interrupt handler */
 +      ctx->aborting = 1;
 +}
 +
 +/* device_run() - prepares and starts the device
 + *
 + * This simulates all the immediate preparations required before starting
 + * a device. This will be called by the framework when it decides to schedule
 + * a particular instance.
 + */
 +static void device_run(void *priv)
 +{
 +      struct vim2m_ctx *ctx = priv;
 +      struct vim2m_dev *dev = ctx->dev;
 +      struct vb2_buffer *src_buf, *dst_buf;
 +
 +      src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 +      dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 +
 +      device_process(ctx, src_buf, dst_buf);
 +
 +      /* Run a timer, which simulates a hardware irq  */
 +      schedule_irq(dev, ctx->transtime);
 +}
 +
 +static void device_isr(unsigned long priv)
 +{
 +      struct vim2m_dev *vim2m_dev = (struct vim2m_dev *)priv;
 +      struct vim2m_ctx *curr_ctx;
 +      struct vb2_buffer *src_vb, *dst_vb;
 +      unsigned long flags;
 +
 +      curr_ctx = v4l2_m2m_get_curr_priv(vim2m_dev->m2m_dev);
 +
 +      if (NULL == curr_ctx) {
 +              pr_err("Instance released before the end of transaction\n");
 +              return;
 +      }
 +
 +      src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
 +      dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
 +
 +      curr_ctx->num_processed++;
 +
 +      spin_lock_irqsave(&vim2m_dev->irqlock, flags);
 +      v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
 +      v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
 +      spin_unlock_irqrestore(&vim2m_dev->irqlock, flags);
 +
 +      if (curr_ctx->num_processed == curr_ctx->translen
 +          || curr_ctx->aborting) {
 +              dprintk(curr_ctx->dev, "Finishing transaction\n");
 +              curr_ctx->num_processed = 0;
 +              v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
 +      } else {
 +              device_run(curr_ctx);
 +      }
 +}
 +
 +/*
 + * video ioctls
 + */
 +static int vidioc_querycap(struct file *file, void *priv,
 +                         struct v4l2_capability *cap)
 +{
 +      strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
 +      strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
 +      snprintf(cap->bus_info, sizeof(cap->bus_info),
 +                      "platform:%s", MEM2MEM_NAME);
 +      cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
 +      cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 +      return 0;
 +}
 +
 +static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
 +{
 +      int i, num;
 +      struct vim2m_fmt *fmt;
 +
 +      num = 0;
 +
 +      for (i = 0; i < NUM_FORMATS; ++i) {
 +              if (formats[i].types & type) {
 +                      /* index-th format of type type found ? */
 +                      if (num == f->index)
 +                              break;
 +                      /* Correct type but haven't reached our index yet,
 +                       * just increment per-type index */
 +                      ++num;
 +              }
 +      }
 +
 +      if (i < NUM_FORMATS) {
 +              /* Format found */
 +              fmt = &formats[i];
 +              strncpy(f->description, fmt->name, sizeof(f->description) - 1);
 +              f->pixelformat = fmt->fourcc;
 +              return 0;
 +      }
 +
 +      /* Format not found */
 +      return -EINVAL;
 +}
 +
 +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 +                                 struct v4l2_fmtdesc *f)
 +{
 +      return enum_fmt(f, MEM2MEM_CAPTURE);
 +}
 +
 +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
 +                                 struct v4l2_fmtdesc *f)
 +{
 +      return enum_fmt(f, MEM2MEM_OUTPUT);
 +}
 +
 +static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
 +{
 +      struct vb2_queue *vq;
 +      struct vim2m_q_data *q_data;
 +
 +      vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
 +      if (!vq)
 +              return -EINVAL;
 +
 +      q_data = get_q_data(ctx, f->type);
 +
 +      f->fmt.pix.width        = q_data->width;
 +      f->fmt.pix.height       = q_data->height;
 +      f->fmt.pix.field        = V4L2_FIELD_NONE;
 +      f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
 +      f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
 +      f->fmt.pix.sizeimage    = q_data->sizeimage;
 +      f->fmt.pix.colorspace   = ctx->colorspace;
 +
 +      return 0;
 +}
 +
 +static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
 +                              struct v4l2_format *f)
 +{
 +      return vidioc_g_fmt(file2ctx(file), f);
 +}
 +
 +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 +                              struct v4l2_format *f)
 +{
 +      return vidioc_g_fmt(file2ctx(file), f);
 +}
 +
 +static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt)
 +{
 +      /* V4L2 specification suggests the driver corrects the format struct
 +       * if any of the dimensions is unsupported */
 +      if (f->fmt.pix.height < MIN_H)
 +              f->fmt.pix.height = MIN_H;
 +      else if (f->fmt.pix.height > MAX_H)
 +              f->fmt.pix.height = MAX_H;
 +
 +      if (f->fmt.pix.width < MIN_W)
 +              f->fmt.pix.width = MIN_W;
 +      else if (f->fmt.pix.width > MAX_W)
 +              f->fmt.pix.width = MAX_W;
 +
 +      f->fmt.pix.width &= ~DIM_ALIGN_MASK;
 +      f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
 +      f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 +      f->fmt.pix.field = V4L2_FIELD_NONE;
 +
 +      return 0;
 +}
 +
 +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 +                                struct v4l2_format *f)
 +{
 +      struct vim2m_fmt *fmt;
 +      struct vim2m_ctx *ctx = file2ctx(file);
 +
 +      fmt = find_format(f);
 +      if (!fmt) {
 +              f->fmt.pix.pixelformat = formats[0].fourcc;
 +              fmt = find_format(f);
 +      }
 +      if (!(fmt->types & MEM2MEM_CAPTURE)) {
 +              v4l2_err(&ctx->dev->v4l2_dev,
 +                       "Fourcc format (0x%08x) invalid.\n",
 +                       f->fmt.pix.pixelformat);
 +              return -EINVAL;
 +      }
 +      f->fmt.pix.colorspace = ctx->colorspace;
 +
 +      return vidioc_try_fmt(f, fmt);
 +}
 +
 +static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
 +                                struct v4l2_format *f)
 +{
 +      struct vim2m_fmt *fmt;
 +      struct vim2m_ctx *ctx = file2ctx(file);
 +
 +      fmt = find_format(f);
 +      if (!fmt) {
 +              f->fmt.pix.pixelformat = formats[0].fourcc;
 +              fmt = find_format(f);
 +      }
 +      if (!(fmt->types & MEM2MEM_OUTPUT)) {
 +              v4l2_err(&ctx->dev->v4l2_dev,
 +                       "Fourcc format (0x%08x) invalid.\n",
 +                       f->fmt.pix.pixelformat);
 +              return -EINVAL;
 +      }
 +      if (!f->fmt.pix.colorspace)
 +              f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
 +
 +      return vidioc_try_fmt(f, fmt);
 +}
 +
 +static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
 +{
 +      struct vim2m_q_data *q_data;
 +      struct vb2_queue *vq;
 +
 +      vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
 +      if (!vq)
 +              return -EINVAL;
 +
 +      q_data = get_q_data(ctx, f->type);
 +      if (!q_data)
 +              return -EINVAL;
 +
 +      if (vb2_is_busy(vq)) {
 +              v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
 +              return -EBUSY;
 +      }
 +
 +      q_data->fmt             = find_format(f);
 +      q_data->width           = f->fmt.pix.width;
 +      q_data->height          = f->fmt.pix.height;
 +      q_data->sizeimage       = q_data->width * q_data->height
 +                              * q_data->fmt->depth >> 3;
 +
 +      dprintk(ctx->dev,
 +              "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
 +              f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
 +
 +      return 0;
 +}
 +
 +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 +                              struct v4l2_format *f)
 +{
 +      int ret;
 +
 +      ret = vidioc_try_fmt_vid_cap(file, priv, f);
 +      if (ret)
 +              return ret;
 +
 +      return vidioc_s_fmt(file2ctx(file), f);
 +}
 +
 +static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
 +                              struct v4l2_format *f)
 +{
 +      struct vim2m_ctx *ctx = file2ctx(file);
 +      int ret;
 +
 +      ret = vidioc_try_fmt_vid_out(file, priv, f);
 +      if (ret)
 +              return ret;
 +
 +      ret = vidioc_s_fmt(file2ctx(file), f);
 +      if (!ret)
 +              ctx->colorspace = f->fmt.pix.colorspace;
 +      return ret;
 +}
 +
 +static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl)
 +{
 +      struct vim2m_ctx *ctx =
 +              container_of(ctrl->handler, struct vim2m_ctx, hdl);
 +
 +      switch (ctrl->id) {
 +      case V4L2_CID_HFLIP:
 +              if (ctrl->val)
 +                      ctx->mode |= MEM2MEM_HFLIP;
 +              else
 +                      ctx->mode &= ~MEM2MEM_HFLIP;
 +              break;
 +
 +      case V4L2_CID_VFLIP:
 +              if (ctrl->val)
 +                      ctx->mode |= MEM2MEM_VFLIP;
 +              else
 +                      ctx->mode &= ~MEM2MEM_VFLIP;
 +              break;
 +
 +      case V4L2_CID_TRANS_TIME_MSEC:
 +              ctx->transtime = ctrl->val;
 +              break;
 +
 +      case V4L2_CID_TRANS_NUM_BUFS:
 +              ctx->translen = ctrl->val;
 +              break;
 +
 +      default:
 +              v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
 +              return -EINVAL;
 +      }
 +
 +      return 0;
 +}
 +
 +static const struct v4l2_ctrl_ops vim2m_ctrl_ops = {
 +      .s_ctrl = vim2m_s_ctrl,
 +};
 +
 +
 +static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
 +      .vidioc_querycap        = vidioc_querycap,
 +
 +      .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 +      .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
 +      .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
 +      .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
 +
 +      .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
 +      .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
 +      .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
 +      .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
 +
 +      .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
 +      .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
 +      .vidioc_qbuf            = v4l2_m2m_ioctl_qbuf,
 +      .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
 +      .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
 +
 +      .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
 +      .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
 +
 +      .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 +      .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 +};
 +
 +
 +/*
 + * Queue operations
 + */
 +
 +static int vim2m_queue_setup(struct vb2_queue *vq,
 +                              const struct v4l2_format *fmt,
 +                              unsigned int *nbuffers, unsigned int *nplanes,
 +                              unsigned int sizes[], void *alloc_ctxs[])
 +{
 +      struct vim2m_ctx *ctx = vb2_get_drv_priv(vq);
 +      struct vim2m_q_data *q_data;
 +      unsigned int size, count = *nbuffers;
 +
 +      q_data = get_q_data(ctx, vq->type);
 +
 +      size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
 +
 +      while (size * count > MEM2MEM_VID_MEM_LIMIT)
 +              (count)--;
 +
 +      *nplanes = 1;
 +      *nbuffers = count;
 +      sizes[0] = size;
 +
 +      /*
 +       * videobuf2-vmalloc allocator is context-less so no need to set
 +       * alloc_ctxs array.
 +       */
 +
 +      dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
 +
 +      return 0;
 +}
 +
 +static int vim2m_buf_prepare(struct vb2_buffer *vb)
 +{
 +      struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 +      struct vim2m_q_data *q_data;
 +
 +      dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
 +
 +      q_data = get_q_data(ctx, vb->vb2_queue->type);
 +      if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
 +              if (vb->v4l2_buf.field == V4L2_FIELD_ANY)
 +                      vb->v4l2_buf.field = V4L2_FIELD_NONE;
 +              if (vb->v4l2_buf.field != V4L2_FIELD_NONE) {
 +                      dprintk(ctx->dev, "%s field isn't supported\n",
 +                                      __func__);
 +                      return -EINVAL;
 +              }
 +      }
 +
 +      if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
 +              dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
 +                              __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage);
 +              return -EINVAL;
 +      }
 +
 +      vb2_set_plane_payload(vb, 0, q_data->sizeimage);
 +
 +      return 0;
 +}
 +
 +static void vim2m_buf_queue(struct vb2_buffer *vb)
 +{
 +      struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 +
 +      v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
 +}
 +
 +static int vim2m_start_streaming(struct vb2_queue *q, unsigned count)
 +{
 +      struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
 +      struct vim2m_q_data *q_data = get_q_data(ctx, q->type);
 +
 +      q_data->sequence = 0;
 +      return 0;
 +}
 +
 +static void vim2m_stop_streaming(struct vb2_queue *q)
 +{
 +      struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
 +      struct vb2_buffer *vb;
 +      unsigned long flags;
 +
 +      for (;;) {
 +              if (V4L2_TYPE_IS_OUTPUT(q->type))
 +                      vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
 +              else
 +                      vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 +              if (vb == NULL)
 +                      return;
 +              spin_lock_irqsave(&ctx->dev->irqlock, flags);
 +              v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
 +              spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
 +      }
 +}
 +
 +static struct vb2_ops vim2m_qops = {
 +      .queue_setup     = vim2m_queue_setup,
 +      .buf_prepare     = vim2m_buf_prepare,
 +      .buf_queue       = vim2m_buf_queue,
 +      .start_streaming = vim2m_start_streaming,
 +      .stop_streaming  = vim2m_stop_streaming,
 +      .wait_prepare    = vb2_ops_wait_prepare,
 +      .wait_finish     = vb2_ops_wait_finish,
 +};
 +
 +static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 +{
 +      struct vim2m_ctx *ctx = priv;
 +      int ret;
 +
 +      src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
 +      src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
 +      src_vq->drv_priv = ctx;
 +      src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 +      src_vq->ops = &vim2m_qops;
 +      src_vq->mem_ops = &vb2_vmalloc_memops;
 +      src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 +      src_vq->lock = &ctx->dev->dev_mutex;
 +
 +      ret = vb2_queue_init(src_vq);
 +      if (ret)
 +              return ret;
 +
 +      dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 +      dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
 +      dst_vq->drv_priv = ctx;
 +      dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 +      dst_vq->ops = &vim2m_qops;
 +      dst_vq->mem_ops = &vb2_vmalloc_memops;
 +      dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 +      dst_vq->lock = &ctx->dev->dev_mutex;
 +
 +      return vb2_queue_init(dst_vq);
 +}
 +
 +static const struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = {
 +      .ops = &vim2m_ctrl_ops,
 +      .id = V4L2_CID_TRANS_TIME_MSEC,
 +      .name = "Transaction Time (msec)",
 +      .type = V4L2_CTRL_TYPE_INTEGER,
 +      .def = MEM2MEM_DEF_TRANSTIME,
 +      .min = 1,
 +      .max = 10001,
 +      .step = 1,
 +};
 +
 +static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = {
 +      .ops = &vim2m_ctrl_ops,
 +      .id = V4L2_CID_TRANS_NUM_BUFS,
 +      .name = "Buffers Per Transaction",
 +      .type = V4L2_CTRL_TYPE_INTEGER,
 +      .def = 1,
 +      .min = 1,
 +      .max = MEM2MEM_DEF_NUM_BUFS,
 +      .step = 1,
 +};
 +
 +/*
 + * File operations
 + */
 +static int vim2m_open(struct file *file)
 +{
 +      struct vim2m_dev *dev = video_drvdata(file);
 +      struct vim2m_ctx *ctx = NULL;
 +      struct v4l2_ctrl_handler *hdl;
 +      int rc = 0;
 +
 +      if (mutex_lock_interruptible(&dev->dev_mutex))
 +              return -ERESTARTSYS;
 +      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 +      if (!ctx) {
 +              rc = -ENOMEM;
 +              goto open_unlock;
 +      }
 +
 +      v4l2_fh_init(&ctx->fh, video_devdata(file));
 +      file->private_data = &ctx->fh;
 +      ctx->dev = dev;
 +      hdl = &ctx->hdl;
 +      v4l2_ctrl_handler_init(hdl, 4);
 +      v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
 +      v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
 +      v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
 +      v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL);
 +      if (hdl->error) {
 +              rc = hdl->error;
 +              v4l2_ctrl_handler_free(hdl);
 +              goto open_unlock;
 +      }
 +      ctx->fh.ctrl_handler = hdl;
 +      v4l2_ctrl_handler_setup(hdl);
 +
 +      ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
 +      ctx->q_data[V4L2_M2M_SRC].width = 640;
 +      ctx->q_data[V4L2_M2M_SRC].height = 480;
 +      ctx->q_data[V4L2_M2M_SRC].sizeimage =
 +              ctx->q_data[V4L2_M2M_SRC].width *
 +              ctx->q_data[V4L2_M2M_SRC].height *
 +              (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
 +      ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
 +      ctx->colorspace = V4L2_COLORSPACE_REC709;
 +
 +      ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
 +
 +      if (IS_ERR(ctx->fh.m2m_ctx)) {
 +              rc = PTR_ERR(ctx->fh.m2m_ctx);
 +
 +              v4l2_ctrl_handler_free(hdl);
 +              kfree(ctx);
 +              goto open_unlock;
 +      }
 +
 +      v4l2_fh_add(&ctx->fh);
 +      atomic_inc(&dev->num_inst);
 +
 +      dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
 +              ctx, ctx->fh.m2m_ctx);
 +
 +open_unlock:
 +      mutex_unlock(&dev->dev_mutex);
 +      return rc;
 +}
 +
 +static int vim2m_release(struct file *file)
 +{
 +      struct vim2m_dev *dev = video_drvdata(file);
 +      struct vim2m_ctx *ctx = file2ctx(file);
 +
 +      dprintk(dev, "Releasing instance %p\n", ctx);
 +
 +      v4l2_fh_del(&ctx->fh);
 +      v4l2_fh_exit(&ctx->fh);
 +      v4l2_ctrl_handler_free(&ctx->hdl);
 +      mutex_lock(&dev->dev_mutex);
 +      v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
 +      mutex_unlock(&dev->dev_mutex);
 +      kfree(ctx);
 +
 +      atomic_dec(&dev->num_inst);
 +
 +      return 0;
 +}
 +
 +static const struct v4l2_file_operations vim2m_fops = {
 +      .owner          = THIS_MODULE,
 +      .open           = vim2m_open,
 +      .release        = vim2m_release,
 +      .poll           = v4l2_m2m_fop_poll,
 +      .unlocked_ioctl = video_ioctl2,
 +      .mmap           = v4l2_m2m_fop_mmap,
 +};
 +
 +static struct video_device vim2m_videodev = {
 +      .name           = MEM2MEM_NAME,
 +      .vfl_dir        = VFL_DIR_M2M,
 +      .fops           = &vim2m_fops,
 +      .ioctl_ops      = &vim2m_ioctl_ops,
 +      .minor          = -1,
 +      .release        = video_device_release,
 +};
 +
 +static struct v4l2_m2m_ops m2m_ops = {
 +      .device_run     = device_run,
 +      .job_ready      = job_ready,
 +      .job_abort      = job_abort,
 +};
 +
 +static int vim2m_probe(struct platform_device *pdev)
 +{
 +      struct vim2m_dev *dev;
 +      struct video_device *vfd;
 +      int ret;
 +
 +      dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
 +      if (!dev)
 +              return -ENOMEM;
 +
 +      spin_lock_init(&dev->irqlock);
 +
 +      ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
 +      if (ret)
 +              return ret;
 +
 +      atomic_set(&dev->num_inst, 0);
 +      mutex_init(&dev->dev_mutex);
 +
 +      vfd = video_device_alloc();
 +      if (!vfd) {
 +              v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
 +              ret = -ENOMEM;
 +              goto unreg_dev;
 +      }
 +
 +      *vfd = vim2m_videodev;
 +      vfd->lock = &dev->dev_mutex;
 +      vfd->v4l2_dev = &dev->v4l2_dev;
 +
 +      ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
 +      if (ret) {
 +              v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
 +              goto rel_vdev;
 +      }
 +
 +      video_set_drvdata(vfd, dev);
 +      snprintf(vfd->name, sizeof(vfd->name), "%s", vim2m_videodev.name);
 +      dev->vfd = vfd;
 +      v4l2_info(&dev->v4l2_dev,
 +                      "Device registered as /dev/video%d\n", vfd->num);
 +
 +      setup_timer(&dev->timer, device_isr, (long)dev);
 +      platform_set_drvdata(pdev, dev);
 +
 +      dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
 +      if (IS_ERR(dev->m2m_dev)) {
 +              v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
 +              ret = PTR_ERR(dev->m2m_dev);
 +              goto err_m2m;
 +      }
 +
 +      return 0;
 +
 +err_m2m:
 +      v4l2_m2m_release(dev->m2m_dev);
 +      video_unregister_device(dev->vfd);
 +rel_vdev:
 +      video_device_release(vfd);
 +unreg_dev:
 +      v4l2_device_unregister(&dev->v4l2_dev);
 +
 +      return ret;
 +}
 +
 +static int vim2m_remove(struct platform_device *pdev)
 +{
 +      struct vim2m_dev *dev = platform_get_drvdata(pdev);
 +
 +      v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
 +      v4l2_m2m_release(dev->m2m_dev);
 +      del_timer_sync(&dev->timer);
 +      video_unregister_device(dev->vfd);
 +      v4l2_device_unregister(&dev->v4l2_dev);
 +
 +      return 0;
 +}
 +
 +static struct platform_driver vim2m_pdrv = {
 +      .probe          = vim2m_probe,
 +      .remove         = vim2m_remove,
 +      .driver         = {
 +              .name   = MEM2MEM_NAME,
 +      },
 +};
 +
 +static void __exit vim2m_exit(void)
 +{
 +      platform_driver_unregister(&vim2m_pdrv);
 +      platform_device_unregister(&vim2m_pdev);
 +}
 +
 +static int __init vim2m_init(void)
 +{
 +      int ret;
 +
 +      ret = platform_device_register(&vim2m_pdev);
 +      if (ret)
 +              return ret;
 +
 +      ret = platform_driver_register(&vim2m_pdrv);
 +      if (ret)
 +              platform_device_unregister(&vim2m_pdev);
 +
 +      return 0;
 +}
 +
 +module_init(vim2m_init);
 +module_exit(vim2m_exit);
Simple merge
index ffc5e60,0000000..24696f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,2092 -1,0 +1,2091 @@@
-               .owner  = THIS_MODULE,
 +/*
 + * GPMC support functions
 + *
 + * Copyright (C) 2005-2006 Nokia Corporation
 + *
 + * Author: Juha Yrjola
 + *
 + * Copyright (C) 2009 Texas Instruments
 + * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.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.
 + */
 +#undef DEBUG
 +
 +#include <linux/irq.h>
 +#include <linux/kernel.h>
 +#include <linux/init.h>
 +#include <linux/err.h>
 +#include <linux/clk.h>
 +#include <linux/ioport.h>
 +#include <linux/spinlock.h>
 +#include <linux/io.h>
 +#include <linux/module.h>
 +#include <linux/interrupt.h>
 +#include <linux/platform_device.h>
 +#include <linux/of.h>
 +#include <linux/of_address.h>
 +#include <linux/of_mtd.h>
 +#include <linux/of_device.h>
 +#include <linux/omap-gpmc.h>
 +#include <linux/mtd/nand.h>
 +#include <linux/pm_runtime.h>
 +
 +#include <linux/platform_data/mtd-nand-omap2.h>
 +#include <linux/platform_data/mtd-onenand-omap2.h>
 +
 +#include <asm/mach-types.h>
 +
 +#define       DEVICE_NAME             "omap-gpmc"
 +
 +/* GPMC register offsets */
 +#define GPMC_REVISION         0x00
 +#define GPMC_SYSCONFIG                0x10
 +#define GPMC_SYSSTATUS                0x14
 +#define GPMC_IRQSTATUS                0x18
 +#define GPMC_IRQENABLE                0x1c
 +#define GPMC_TIMEOUT_CONTROL  0x40
 +#define GPMC_ERR_ADDRESS      0x44
 +#define GPMC_ERR_TYPE         0x48
 +#define GPMC_CONFIG           0x50
 +#define GPMC_STATUS           0x54
 +#define GPMC_PREFETCH_CONFIG1 0x1e0
 +#define GPMC_PREFETCH_CONFIG2 0x1e4
 +#define GPMC_PREFETCH_CONTROL 0x1ec
 +#define GPMC_PREFETCH_STATUS  0x1f0
 +#define GPMC_ECC_CONFIG               0x1f4
 +#define GPMC_ECC_CONTROL      0x1f8
 +#define GPMC_ECC_SIZE_CONFIG  0x1fc
 +#define GPMC_ECC1_RESULT        0x200
 +#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */
 +#define       GPMC_ECC_BCH_RESULT_1   0x244   /* not available on OMAP2 */
 +#define       GPMC_ECC_BCH_RESULT_2   0x248   /* not available on OMAP2 */
 +#define       GPMC_ECC_BCH_RESULT_3   0x24c   /* not available on OMAP2 */
 +#define       GPMC_ECC_BCH_RESULT_4   0x300   /* not available on OMAP2 */
 +#define       GPMC_ECC_BCH_RESULT_5   0x304   /* not available on OMAP2 */
 +#define       GPMC_ECC_BCH_RESULT_6   0x308   /* not available on OMAP2 */
 +
 +/* GPMC ECC control settings */
 +#define GPMC_ECC_CTRL_ECCCLEAR                0x100
 +#define GPMC_ECC_CTRL_ECCDISABLE      0x000
 +#define GPMC_ECC_CTRL_ECCREG1         0x001
 +#define GPMC_ECC_CTRL_ECCREG2         0x002
 +#define GPMC_ECC_CTRL_ECCREG3         0x003
 +#define GPMC_ECC_CTRL_ECCREG4         0x004
 +#define GPMC_ECC_CTRL_ECCREG5         0x005
 +#define GPMC_ECC_CTRL_ECCREG6         0x006
 +#define GPMC_ECC_CTRL_ECCREG7         0x007
 +#define GPMC_ECC_CTRL_ECCREG8         0x008
 +#define GPMC_ECC_CTRL_ECCREG9         0x009
 +
 +#define GPMC_CONFIG_LIMITEDADDRESS            BIT(1)
 +
 +#define       GPMC_CONFIG2_CSEXTRADELAY               BIT(7)
 +#define       GPMC_CONFIG3_ADVEXTRADELAY              BIT(7)
 +#define       GPMC_CONFIG4_OEEXTRADELAY               BIT(7)
 +#define       GPMC_CONFIG4_WEEXTRADELAY               BIT(23)
 +#define       GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN        BIT(6)
 +#define       GPMC_CONFIG6_CYCLE2CYCLESAMECSEN        BIT(7)
 +
 +#define GPMC_CS0_OFFSET               0x60
 +#define GPMC_CS_SIZE          0x30
 +#define       GPMC_BCH_SIZE           0x10
 +
 +#define GPMC_MEM_END          0x3FFFFFFF
 +
 +#define GPMC_CHUNK_SHIFT      24              /* 16 MB */
 +#define GPMC_SECTION_SHIFT    28              /* 128 MB */
 +
 +#define CS_NUM_SHIFT          24
 +#define ENABLE_PREFETCH               (0x1 << 7)
 +#define DMA_MPU_MODE          2
 +
 +#define       GPMC_REVISION_MAJOR(l)          ((l >> 4) & 0xf)
 +#define       GPMC_REVISION_MINOR(l)          (l & 0xf)
 +
 +#define       GPMC_HAS_WR_ACCESS              0x1
 +#define       GPMC_HAS_WR_DATA_MUX_BUS        0x2
 +#define       GPMC_HAS_MUX_AAD                0x4
 +
 +#define GPMC_NR_WAITPINS              4
 +
 +#define GPMC_CS_CONFIG1               0x00
 +#define GPMC_CS_CONFIG2               0x04
 +#define GPMC_CS_CONFIG3               0x08
 +#define GPMC_CS_CONFIG4               0x0c
 +#define GPMC_CS_CONFIG5               0x10
 +#define GPMC_CS_CONFIG6               0x14
 +#define GPMC_CS_CONFIG7               0x18
 +#define GPMC_CS_NAND_COMMAND  0x1c
 +#define GPMC_CS_NAND_ADDRESS  0x20
 +#define GPMC_CS_NAND_DATA     0x24
 +
 +/* Control Commands */
 +#define GPMC_CONFIG_RDY_BSY   0x00000001
 +#define GPMC_CONFIG_DEV_SIZE  0x00000002
 +#define GPMC_CONFIG_DEV_TYPE  0x00000003
 +#define GPMC_SET_IRQ_STATUS   0x00000004
 +
 +#define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 +#define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
 +#define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
 +#define GPMC_CONFIG1_READTYPE_SYNC      (1 << 29)
 +#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
 +#define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
 +#define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
 +#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
 +#define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
 +#define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
 +#define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
 +#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
 +#define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 +#define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
 +#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
 +#define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
 +#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
 +#define GPMC_CONFIG1_MUXTYPE(val)       ((val & 3) << 8)
 +#define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
 +#define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
 +#define GPMC_CONFIG1_FCLK_DIV2          (GPMC_CONFIG1_FCLK_DIV(1))
 +#define GPMC_CONFIG1_FCLK_DIV3          (GPMC_CONFIG1_FCLK_DIV(2))
 +#define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 +#define GPMC_CONFIG7_CSVALID          (1 << 6)
 +
 +#define GPMC_DEVICETYPE_NOR           0
 +#define GPMC_DEVICETYPE_NAND          2
 +#define GPMC_CONFIG_WRITEPROTECT      0x00000010
 +#define WR_RD_PIN_MONITORING          0x00600000
 +
 +#define GPMC_ENABLE_IRQ               0x0000000d
 +
 +/* ECC commands */
 +#define GPMC_ECC_READ         0 /* Reset Hardware ECC for read */
 +#define GPMC_ECC_WRITE                1 /* Reset Hardware ECC for write */
 +#define GPMC_ECC_READSYN      2 /* Reset before syndrom is read back */
 +
 +/* XXX: Only NAND irq has been considered,currently these are the only ones used
 + */
 +#define       GPMC_NR_IRQ             2
 +
 +struct gpmc_cs_data {
 +      const char *name;
 +
 +#define GPMC_CS_RESERVED      (1 << 0)
 +      u32 flags;
 +
 +      struct resource mem;
 +};
 +
 +struct gpmc_client_irq        {
 +      unsigned                irq;
 +      u32                     bitmask;
 +};
 +
 +/* Structure to save gpmc cs context */
 +struct gpmc_cs_config {
 +      u32 config1;
 +      u32 config2;
 +      u32 config3;
 +      u32 config4;
 +      u32 config5;
 +      u32 config6;
 +      u32 config7;
 +      int is_valid;
 +};
 +
 +/*
 + * Structure to save/restore gpmc context
 + * to support core off on OMAP3
 + */
 +struct omap3_gpmc_regs {
 +      u32 sysconfig;
 +      u32 irqenable;
 +      u32 timeout_ctrl;
 +      u32 config;
 +      u32 prefetch_config1;
 +      u32 prefetch_config2;
 +      u32 prefetch_control;
 +      struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 +};
 +
 +static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
 +static struct irq_chip gpmc_irq_chip;
 +static int gpmc_irq_start;
 +
 +static struct resource        gpmc_mem_root;
 +static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
 +static DEFINE_SPINLOCK(gpmc_mem_lock);
 +/* Define chip-selects as reserved by default until probe completes */
 +static unsigned int gpmc_cs_num = GPMC_CS_NUM;
 +static unsigned int gpmc_nr_waitpins;
 +static struct device *gpmc_dev;
 +static int gpmc_irq;
 +static resource_size_t phys_base, mem_size;
 +static unsigned gpmc_capability;
 +static void __iomem *gpmc_base;
 +
 +static struct clk *gpmc_l3_clk;
 +
 +static irqreturn_t gpmc_handle_irq(int irq, void *dev);
 +
 +static void gpmc_write_reg(int idx, u32 val)
 +{
 +      writel_relaxed(val, gpmc_base + idx);
 +}
 +
 +static u32 gpmc_read_reg(int idx)
 +{
 +      return readl_relaxed(gpmc_base + idx);
 +}
 +
 +void gpmc_cs_write_reg(int cs, int idx, u32 val)
 +{
 +      void __iomem *reg_addr;
 +
 +      reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
 +      writel_relaxed(val, reg_addr);
 +}
 +
 +static u32 gpmc_cs_read_reg(int cs, int idx)
 +{
 +      void __iomem *reg_addr;
 +
 +      reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
 +      return readl_relaxed(reg_addr);
 +}
 +
 +/* TODO: Add support for gpmc_fck to clock framework and use it */
 +static unsigned long gpmc_get_fclk_period(void)
 +{
 +      unsigned long rate = clk_get_rate(gpmc_l3_clk);
 +
 +      rate /= 1000;
 +      rate = 1000000000 / rate;       /* In picoseconds */
 +
 +      return rate;
 +}
 +
 +static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
 +{
 +      unsigned long tick_ps;
 +
 +      /* Calculate in picosecs to yield more exact results */
 +      tick_ps = gpmc_get_fclk_period();
 +
 +      return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 +}
 +
 +static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 +{
 +      unsigned long tick_ps;
 +
 +      /* Calculate in picosecs to yield more exact results */
 +      tick_ps = gpmc_get_fclk_period();
 +
 +      return (time_ps + tick_ps - 1) / tick_ps;
 +}
 +
 +unsigned int gpmc_ticks_to_ns(unsigned int ticks)
 +{
 +      return ticks * gpmc_get_fclk_period() / 1000;
 +}
 +
 +static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
 +{
 +      return ticks * gpmc_get_fclk_period();
 +}
 +
 +static unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
 +{
 +      unsigned long ticks = gpmc_ps_to_ticks(time_ps);
 +
 +      return ticks * gpmc_get_fclk_period();
 +}
 +
 +static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
 +{
 +      u32 l;
 +
 +      l = gpmc_cs_read_reg(cs, reg);
 +      if (value)
 +              l |= mask;
 +      else
 +              l &= ~mask;
 +      gpmc_cs_write_reg(cs, reg, l);
 +}
 +
 +static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
 +{
 +      gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG1,
 +                         GPMC_CONFIG1_TIME_PARA_GRAN,
 +                         p->time_para_granularity);
 +      gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG2,
 +                         GPMC_CONFIG2_CSEXTRADELAY, p->cs_extra_delay);
 +      gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG3,
 +                         GPMC_CONFIG3_ADVEXTRADELAY, p->adv_extra_delay);
 +      gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
 +                         GPMC_CONFIG4_OEEXTRADELAY, p->oe_extra_delay);
 +      gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG4,
 +                         GPMC_CONFIG4_OEEXTRADELAY, p->we_extra_delay);
 +      gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
 +                         GPMC_CONFIG6_CYCLE2CYCLESAMECSEN,
 +                         p->cycle2cyclesamecsen);
 +      gpmc_cs_modify_reg(cs, GPMC_CS_CONFIG6,
 +                         GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN,
 +                         p->cycle2cyclediffcsen);
 +}
 +
 +#ifdef DEBUG
 +static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 +                             bool raw, bool noval, int shift,
 +                             const char *name)
 +{
 +      u32 l;
 +      int nr_bits, max_value, mask;
 +
 +      l = gpmc_cs_read_reg(cs, reg);
 +      nr_bits = end_bit - st_bit + 1;
 +      max_value = (1 << nr_bits) - 1;
 +      mask = max_value << st_bit;
 +      l = (l & mask) >> st_bit;
 +      if (shift)
 +              l = (shift << l);
 +      if (noval && (l == 0))
 +              return 0;
 +      if (!raw) {
 +              unsigned int time_ns_min, time_ns, time_ns_max;
 +
 +              time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
 +              time_ns = gpmc_ticks_to_ns(l);
 +              time_ns_max = gpmc_ticks_to_ns(l + 1 > max_value ?
 +                                             max_value : l + 1);
 +              pr_info("gpmc,%s = <%u> (%u - %u ns, %i ticks)\n",
 +                      name, time_ns, time_ns_min, time_ns_max, l);
 +      } else {
 +              pr_info("gpmc,%s = <%u>\n", name, l);
 +      }
 +
 +      return l;
 +}
 +
 +#define GPMC_PRINT_CONFIG(cs, config) \
 +      pr_info("cs%i %s: 0x%08x\n", cs, #config, \
 +              gpmc_cs_read_reg(cs, config))
 +#define GPMC_GET_RAW(reg, st, end, field) \
 +      get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 0, 0, field)
 +#define GPMC_GET_RAW_BOOL(reg, st, end, field) \
 +      get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, 0, field)
 +#define GPMC_GET_RAW_SHIFT(reg, st, end, shift, field) \
 +      get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, (shift), field)
 +#define GPMC_GET_TICKS(reg, st, end, field) \
 +      get_gpmc_timing_reg(cs, (reg), (st), (end), 0, 0, 0, field)
 +
 +static void gpmc_show_regs(int cs, const char *desc)
 +{
 +      pr_info("gpmc cs%i %s:\n", cs, desc);
 +      GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG1);
 +      GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG2);
 +      GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG3);
 +      GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG4);
 +      GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG5);
 +      GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG6);
 +}
 +
 +/*
 + * Note that gpmc,wait-pin handing wrongly assumes bit 8 is available,
 + * see commit c9fb809.
 + */
 +static void gpmc_cs_show_timings(int cs, const char *desc)
 +{
 +      gpmc_show_regs(cs, desc);
 +
 +      pr_info("gpmc cs%i access configuration:\n", cs);
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1,  4,  4, "time-para-granularity");
 +      GPMC_GET_RAW(GPMC_CS_CONFIG1,  8,  9, "mux-add-data");
 +      GPMC_GET_RAW(GPMC_CS_CONFIG1, 12, 13, "device-width");
 +      GPMC_GET_RAW(GPMC_CS_CONFIG1, 16, 17, "wait-pin");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 21, 21, "wait-on-write");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 22, 22, "wait-on-read");
 +      GPMC_GET_RAW_SHIFT(GPMC_CS_CONFIG1, 23, 24, 4, "burst-length");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 27, 27, "sync-write");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 28, 28, "burst-write");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 29, 29, "gpmc,sync-read");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 30, 30, "burst-read");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 31, 31, "burst-wrap");
 +
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG2,  7,  7, "cs-extra-delay");
 +
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG3,  7,  7, "adv-extra-delay");
 +
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4, 23, 23, "we-extra-delay");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4,  7,  7, "oe-extra-delay");
 +
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6,  7,  7, "cycle2cycle-samecsen");
 +      GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6,  6,  6, "cycle2cycle-diffcsen");
 +
 +      pr_info("gpmc cs%i timings configuration:\n", cs);
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG2,  0,  3, "cs-on-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG2,  8, 12, "cs-rd-off-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG2, 16, 20, "cs-wr-off-ns");
 +
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG3,  0,  3, "adv-on-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG3,  8, 12, "adv-rd-off-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG3, 16, 20, "adv-wr-off-ns");
 +
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG4,  0,  3, "oe-on-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG4,  8, 12, "oe-off-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG4, 16, 19, "we-on-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG4, 24, 28, "we-off-ns");
 +
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG5,  0,  4, "rd-cycle-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG5,  8, 12, "wr-cycle-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG5, 16, 20, "access-ns");
 +
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG5, 24, 27, "page-burst-access-ns");
 +
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG6, 0, 3, "bus-turnaround-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG6, 8, 11, "cycle2cycle-delay-ns");
 +
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG1, 18, 19, "wait-monitoring-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG1, 25, 26, "clk-activation-ns");
 +
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG6, 16, 19, "wr-data-mux-bus-ns");
 +      GPMC_GET_TICKS(GPMC_CS_CONFIG6, 24, 28, "wr-access-ns");
 +}
 +#else
 +static inline void gpmc_cs_show_timings(int cs, const char *desc)
 +{
 +}
 +#endif
 +
 +static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 +                             int time, const char *name)
 +{
 +      u32 l;
 +      int ticks, mask, nr_bits;
 +
 +      if (time == 0)
 +              ticks = 0;
 +      else
 +              ticks = gpmc_ns_to_ticks(time);
 +      nr_bits = end_bit - st_bit + 1;
 +      mask = (1 << nr_bits) - 1;
 +
 +      if (ticks > mask) {
 +              pr_err("%s: GPMC error! CS%d: %s: %d ns, %d ticks > %d\n",
 +                     __func__, cs, name, time, ticks, mask);
 +
 +              return -1;
 +      }
 +
 +      l = gpmc_cs_read_reg(cs, reg);
 +#ifdef DEBUG
 +      printk(KERN_INFO
 +              "GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
 +             cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
 +                      (l >> st_bit) & mask, time);
 +#endif
 +      l &= ~(mask << st_bit);
 +      l |= ticks << st_bit;
 +      gpmc_cs_write_reg(cs, reg, l);
 +
 +      return 0;
 +}
 +
 +#define GPMC_SET_ONE(reg, st, end, field) \
 +      if (set_gpmc_timing_reg(cs, (reg), (st), (end),         \
 +                      t->field, #field) < 0)                  \
 +              return -1
 +
 +int gpmc_calc_divider(unsigned int sync_clk)
 +{
 +      int div;
 +      u32 l;
 +
 +      l = sync_clk + (gpmc_get_fclk_period() - 1);
 +      div = l / gpmc_get_fclk_period();
 +      if (div > 4)
 +              return -1;
 +      if (div <= 0)
 +              div = 1;
 +
 +      return div;
 +}
 +
 +int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 +{
 +      int div;
 +      u32 l;
 +
 +      gpmc_cs_show_timings(cs, "before gpmc_cs_set_timings");
 +      div = gpmc_calc_divider(t->sync_clk);
 +      if (div < 0)
 +              return div;
 +
 +      GPMC_SET_ONE(GPMC_CS_CONFIG2,  0,  3, cs_on);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG2,  8, 12, cs_rd_off);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
 +
 +      GPMC_SET_ONE(GPMC_CS_CONFIG3,  0,  3, adv_on);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG3,  8, 12, adv_rd_off);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
 +
 +      GPMC_SET_ONE(GPMC_CS_CONFIG4,  0,  3, oe_on);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG4,  8, 12, oe_off);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
 +
 +      GPMC_SET_ONE(GPMC_CS_CONFIG5,  0,  4, rd_cycle);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG5,  8, 12, wr_cycle);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
 +
 +      GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
 +
 +      GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
 +
 +      GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
 +      GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
 +
 +      if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
 +              GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
 +      if (gpmc_capability & GPMC_HAS_WR_ACCESS)
 +              GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
 +
 +      /* caller is expected to have initialized CONFIG1 to cover
 +       * at least sync vs async
 +       */
 +      l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 +      if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 +#ifdef DEBUG
 +              printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
 +                              cs, (div * gpmc_get_fclk_period()) / 1000, div);
 +#endif
 +              l &= ~0x03;
 +              l |= (div - 1);
 +              gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 +      }
 +
 +      gpmc_cs_bool_timings(cs, &t->bool_timings);
 +      gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings");
 +
 +      return 0;
 +}
 +
 +static int gpmc_cs_set_memconf(int cs, u32 base, u32 size)
 +{
 +      u32 l;
 +      u32 mask;
 +
 +      /*
 +       * Ensure that base address is aligned on a
 +       * boundary equal to or greater than size.
 +       */
 +      if (base & (size - 1))
 +              return -EINVAL;
 +
 +      mask = (1 << GPMC_SECTION_SHIFT) - size;
 +      l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
 +      l &= ~0x3f;
 +      l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
 +      l &= ~(0x0f << 8);
 +      l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
 +      l |= GPMC_CONFIG7_CSVALID;
 +      gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
 +
 +      return 0;
 +}
 +
 +static void gpmc_cs_enable_mem(int cs)
 +{
 +      u32 l;
 +
 +      l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
 +      l |= GPMC_CONFIG7_CSVALID;
 +      gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
 +}
 +
 +static void gpmc_cs_disable_mem(int cs)
 +{
 +      u32 l;
 +
 +      l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
 +      l &= ~GPMC_CONFIG7_CSVALID;
 +      gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
 +}
 +
 +static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
 +{
 +      u32 l;
 +      u32 mask;
 +
 +      l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
 +      *base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
 +      mask = (l >> 8) & 0x0f;
 +      *size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
 +}
 +
 +static int gpmc_cs_mem_enabled(int cs)
 +{
 +      u32 l;
 +
 +      l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
 +      return l & GPMC_CONFIG7_CSVALID;
 +}
 +
 +static void gpmc_cs_set_reserved(int cs, int reserved)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +
 +      gpmc->flags |= GPMC_CS_RESERVED;
 +}
 +
 +static bool gpmc_cs_reserved(int cs)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +
 +      return gpmc->flags & GPMC_CS_RESERVED;
 +}
 +
 +static void gpmc_cs_set_name(int cs, const char *name)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +
 +      gpmc->name = name;
 +}
 +
 +const char *gpmc_cs_get_name(int cs)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +
 +      return gpmc->name;
 +}
 +
 +static unsigned long gpmc_mem_align(unsigned long size)
 +{
 +      int order;
 +
 +      size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
 +      order = GPMC_CHUNK_SHIFT - 1;
 +      do {
 +              size >>= 1;
 +              order++;
 +      } while (size);
 +      size = 1 << order;
 +      return size;
 +}
 +
 +static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +      struct resource *res = &gpmc->mem;
 +      int r;
 +
 +      size = gpmc_mem_align(size);
 +      spin_lock(&gpmc_mem_lock);
 +      res->start = base;
 +      res->end = base + size - 1;
 +      r = request_resource(&gpmc_mem_root, res);
 +      spin_unlock(&gpmc_mem_lock);
 +
 +      return r;
 +}
 +
 +static int gpmc_cs_delete_mem(int cs)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +      struct resource *res = &gpmc->mem;
 +      int r;
 +
 +      spin_lock(&gpmc_mem_lock);
 +      r = release_resource(res);
 +      res->start = 0;
 +      res->end = 0;
 +      spin_unlock(&gpmc_mem_lock);
 +
 +      return r;
 +}
 +
 +/**
 + * gpmc_cs_remap - remaps a chip-select physical base address
 + * @cs:               chip-select to remap
 + * @base:     physical base address to re-map chip-select to
 + *
 + * Re-maps a chip-select to a new physical base address specified by
 + * "base". Returns 0 on success and appropriate negative error code
 + * on failure.
 + */
 +static int gpmc_cs_remap(int cs, u32 base)
 +{
 +      int ret;
 +      u32 old_base, size;
 +
 +      if (cs > gpmc_cs_num) {
 +              pr_err("%s: requested chip-select is disabled\n", __func__);
 +              return -ENODEV;
 +      }
 +
 +      /*
 +       * Make sure we ignore any device offsets from the GPMC partition
 +       * allocated for the chip select and that the new base confirms
 +       * to the GPMC 16MB minimum granularity.
 +       */ 
 +      base &= ~(SZ_16M - 1);
 +
 +      gpmc_cs_get_memconf(cs, &old_base, &size);
 +      if (base == old_base)
 +              return 0;
 +
 +      ret = gpmc_cs_delete_mem(cs);
 +      if (ret < 0)
 +              return ret;
 +
 +      ret = gpmc_cs_insert_mem(cs, base, size);
 +      if (ret < 0)
 +              return ret;
 +
 +      ret = gpmc_cs_set_memconf(cs, base, size);
 +
 +      return ret;
 +}
 +
 +int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +      struct resource *res = &gpmc->mem;
 +      int r = -1;
 +
 +      if (cs > gpmc_cs_num) {
 +              pr_err("%s: requested chip-select is disabled\n", __func__);
 +              return -ENODEV;
 +      }
 +      size = gpmc_mem_align(size);
 +      if (size > (1 << GPMC_SECTION_SHIFT))
 +              return -ENOMEM;
 +
 +      spin_lock(&gpmc_mem_lock);
 +      if (gpmc_cs_reserved(cs)) {
 +              r = -EBUSY;
 +              goto out;
 +      }
 +      if (gpmc_cs_mem_enabled(cs))
 +              r = adjust_resource(res, res->start & ~(size - 1), size);
 +      if (r < 0)
 +              r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
 +                                    size, NULL, NULL);
 +      if (r < 0)
 +              goto out;
 +
 +      /* Disable CS while changing base address and size mask */
 +      gpmc_cs_disable_mem(cs);
 +
 +      r = gpmc_cs_set_memconf(cs, res->start, resource_size(res));
 +      if (r < 0) {
 +              release_resource(res);
 +              goto out;
 +      }
 +
 +      /* Enable CS */
 +      gpmc_cs_enable_mem(cs);
 +      *base = res->start;
 +      gpmc_cs_set_reserved(cs, 1);
 +out:
 +      spin_unlock(&gpmc_mem_lock);
 +      return r;
 +}
 +EXPORT_SYMBOL(gpmc_cs_request);
 +
 +void gpmc_cs_free(int cs)
 +{
 +      struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
 +      struct resource *res = &gpmc->mem;
 +
 +      spin_lock(&gpmc_mem_lock);
 +      if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
 +              printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
 +              BUG();
 +              spin_unlock(&gpmc_mem_lock);
 +              return;
 +      }
 +      gpmc_cs_disable_mem(cs);
 +      if (res->flags)
 +              release_resource(res);
 +      gpmc_cs_set_reserved(cs, 0);
 +      spin_unlock(&gpmc_mem_lock);
 +}
 +EXPORT_SYMBOL(gpmc_cs_free);
 +
 +/**
 + * gpmc_configure - write request to configure gpmc
 + * @cmd: command type
 + * @wval: value to write
 + * @return status of the operation
 + */
 +int gpmc_configure(int cmd, int wval)
 +{
 +      u32 regval;
 +
 +      switch (cmd) {
 +      case GPMC_ENABLE_IRQ:
 +              gpmc_write_reg(GPMC_IRQENABLE, wval);
 +              break;
 +
 +      case GPMC_SET_IRQ_STATUS:
 +              gpmc_write_reg(GPMC_IRQSTATUS, wval);
 +              break;
 +
 +      case GPMC_CONFIG_WP:
 +              regval = gpmc_read_reg(GPMC_CONFIG);
 +              if (wval)
 +                      regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
 +              else
 +                      regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
 +              gpmc_write_reg(GPMC_CONFIG, regval);
 +              break;
 +
 +      default:
 +              pr_err("%s: command not supported\n", __func__);
 +              return -EINVAL;
 +      }
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL(gpmc_configure);
 +
 +void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 +{
 +      int i;
 +
 +      reg->gpmc_status = gpmc_base + GPMC_STATUS;
 +      reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
 +                              GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
 +      reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
 +                              GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs;
 +      reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET +
 +                              GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs;
 +      reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
 +      reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
 +      reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
 +      reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
 +      reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
 +      reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
 +      reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
 +      reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
 +
 +      for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
 +              reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
 +                                         GPMC_BCH_SIZE * i;
 +              reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
 +                                         GPMC_BCH_SIZE * i;
 +              reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
 +                                         GPMC_BCH_SIZE * i;
 +              reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
 +                                         GPMC_BCH_SIZE * i;
 +              reg->gpmc_bch_result4[i] = gpmc_base + GPMC_ECC_BCH_RESULT_4 +
 +                                         i * GPMC_BCH_SIZE;
 +              reg->gpmc_bch_result5[i] = gpmc_base + GPMC_ECC_BCH_RESULT_5 +
 +                                         i * GPMC_BCH_SIZE;
 +              reg->gpmc_bch_result6[i] = gpmc_base + GPMC_ECC_BCH_RESULT_6 +
 +                                         i * GPMC_BCH_SIZE;
 +      }
 +}
 +
 +int gpmc_get_client_irq(unsigned irq_config)
 +{
 +      int i;
 +
 +      if (hweight32(irq_config) > 1)
 +              return 0;
 +
 +      for (i = 0; i < GPMC_NR_IRQ; i++)
 +              if (gpmc_client_irq[i].bitmask & irq_config)
 +                      return gpmc_client_irq[i].irq;
 +
 +      return 0;
 +}
 +
 +static int gpmc_irq_endis(unsigned irq, bool endis)
 +{
 +      int i;
 +      u32 regval;
 +
 +      for (i = 0; i < GPMC_NR_IRQ; i++)
 +              if (irq == gpmc_client_irq[i].irq) {
 +                      regval = gpmc_read_reg(GPMC_IRQENABLE);
 +                      if (endis)
 +                              regval |= gpmc_client_irq[i].bitmask;
 +                      else
 +                              regval &= ~gpmc_client_irq[i].bitmask;
 +                      gpmc_write_reg(GPMC_IRQENABLE, regval);
 +                      break;
 +              }
 +
 +      return 0;
 +}
 +
 +static void gpmc_irq_disable(struct irq_data *p)
 +{
 +      gpmc_irq_endis(p->irq, false);
 +}
 +
 +static void gpmc_irq_enable(struct irq_data *p)
 +{
 +      gpmc_irq_endis(p->irq, true);
 +}
 +
 +static void gpmc_irq_noop(struct irq_data *data) { }
 +
 +static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
 +
 +static int gpmc_setup_irq(void)
 +{
 +      int i;
 +      u32 regval;
 +
 +      if (!gpmc_irq)
 +              return -EINVAL;
 +
 +      gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
 +      if (gpmc_irq_start < 0) {
 +              pr_err("irq_alloc_descs failed\n");
 +              return gpmc_irq_start;
 +      }
 +
 +      gpmc_irq_chip.name = "gpmc";
 +      gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
 +      gpmc_irq_chip.irq_enable = gpmc_irq_enable;
 +      gpmc_irq_chip.irq_disable = gpmc_irq_disable;
 +      gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
 +      gpmc_irq_chip.irq_ack = gpmc_irq_noop;
 +      gpmc_irq_chip.irq_mask = gpmc_irq_noop;
 +      gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
 +
 +      gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
 +      gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
 +
 +      for (i = 0; i < GPMC_NR_IRQ; i++) {
 +              gpmc_client_irq[i].irq = gpmc_irq_start + i;
 +              irq_set_chip_and_handler(gpmc_client_irq[i].irq,
 +                                      &gpmc_irq_chip, handle_simple_irq);
 +              set_irq_flags(gpmc_client_irq[i].irq,
 +                              IRQF_VALID | IRQF_NOAUTOEN);
 +      }
 +
 +      /* Disable interrupts */
 +      gpmc_write_reg(GPMC_IRQENABLE, 0);
 +
 +      /* clear interrupts */
 +      regval = gpmc_read_reg(GPMC_IRQSTATUS);
 +      gpmc_write_reg(GPMC_IRQSTATUS, regval);
 +
 +      return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
 +}
 +
 +static int gpmc_free_irq(void)
 +{
 +      int i;
 +
 +      if (gpmc_irq)
 +              free_irq(gpmc_irq, NULL);
 +
 +      for (i = 0; i < GPMC_NR_IRQ; i++) {
 +              irq_set_handler(gpmc_client_irq[i].irq, NULL);
 +              irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
 +              irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
 +      }
 +
 +      irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
 +
 +      return 0;
 +}
 +
 +static void gpmc_mem_exit(void)
 +{
 +      int cs;
 +
 +      for (cs = 0; cs < gpmc_cs_num; cs++) {
 +              if (!gpmc_cs_mem_enabled(cs))
 +                      continue;
 +              gpmc_cs_delete_mem(cs);
 +      }
 +
 +}
 +
 +static void gpmc_mem_init(void)
 +{
 +      int cs;
 +
 +      /*
 +       * The first 1MB of GPMC address space is typically mapped to
 +       * the internal ROM. Never allocate the first page, to
 +       * facilitate bug detection; even if we didn't boot from ROM.
 +       */
 +      gpmc_mem_root.start = SZ_1M;
 +      gpmc_mem_root.end = GPMC_MEM_END;
 +
 +      /* Reserve all regions that has been set up by bootloader */
 +      for (cs = 0; cs < gpmc_cs_num; cs++) {
 +              u32 base, size;
 +
 +              if (!gpmc_cs_mem_enabled(cs))
 +                      continue;
 +              gpmc_cs_get_memconf(cs, &base, &size);
 +              if (gpmc_cs_insert_mem(cs, base, size)) {
 +                      pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
 +                              __func__, cs, base, base + size);
 +                      gpmc_cs_disable_mem(cs);
 +              }
 +      }
 +}
 +
 +static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
 +{
 +      u32 temp;
 +      int div;
 +
 +      div = gpmc_calc_divider(sync_clk);
 +      temp = gpmc_ps_to_ticks(time_ps);
 +      temp = (temp + div - 1) / div;
 +      return gpmc_ticks_to_ps(temp * div);
 +}
 +
 +/* XXX: can the cycles be avoided ? */
 +static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 +                                     struct gpmc_device_timings *dev_t,
 +                                     bool mux)
 +{
 +      u32 temp;
 +
 +      /* adv_rd_off */
 +      temp = dev_t->t_avdp_r;
 +      /* XXX: mux check required ? */
 +      if (mux) {
 +              /* XXX: t_avdp not to be required for sync, only added for tusb
 +               * this indirectly necessitates requirement of t_avdp_r and
 +               * t_avdp_w instead of having a single t_avdp
 +               */
 +              temp = max_t(u32, temp, gpmc_t->clk_activation + dev_t->t_avdh);
 +              temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 +      }
 +      gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
 +
 +      /* oe_on */
 +      temp = dev_t->t_oeasu; /* XXX: remove this ? */
 +      if (mux) {
 +              temp = max_t(u32, temp, gpmc_t->clk_activation + dev_t->t_ach);
 +              temp = max_t(u32, temp, gpmc_t->adv_rd_off +
 +                              gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
 +      }
 +      gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 +
 +      /* access */
 +      /* XXX: any scope for improvement ?, by combining oe_on
 +       * and clk_activation, need to check whether
 +       * access = clk_activation + round to sync clk ?
 +       */
 +      temp = max_t(u32, dev_t->t_iaa, dev_t->cyc_iaa * gpmc_t->sync_clk);
 +      temp += gpmc_t->clk_activation;
 +      if (dev_t->cyc_oe)
 +              temp = max_t(u32, temp, gpmc_t->oe_on +
 +                              gpmc_ticks_to_ps(dev_t->cyc_oe));
 +      gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 +
 +      gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
 +      gpmc_t->cs_rd_off = gpmc_t->oe_off;
 +
 +      /* rd_cycle */
 +      temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
 +      temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
 +                                                      gpmc_t->access;
 +      /* XXX: barter t_ce_rdyz with t_cez_r ? */
 +      if (dev_t->t_ce_rdyz)
 +              temp = max_t(u32, temp, gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
 +      gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
 +
 +      return 0;
 +}
 +
 +static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 +                                      struct gpmc_device_timings *dev_t,
 +                                      bool mux)
 +{
 +      u32 temp;
 +
 +      /* adv_wr_off */
 +      temp = dev_t->t_avdp_w;
 +      if (mux) {
 +              temp = max_t(u32, temp,
 +                      gpmc_t->clk_activation + dev_t->t_avdh);
 +              temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 +      }
 +      gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
 +
 +      /* wr_data_mux_bus */
 +      temp = max_t(u32, dev_t->t_weasu,
 +                      gpmc_t->clk_activation + dev_t->t_rdyo);
 +      /* XXX: shouldn't mux be kept as a whole for wr_data_mux_bus ?,
 +       * and in that case remember to handle we_on properly
 +       */
 +      if (mux) {
 +              temp = max_t(u32, temp,
 +                      gpmc_t->adv_wr_off + dev_t->t_aavdh);
 +              temp = max_t(u32, temp, gpmc_t->adv_wr_off +
 +                              gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 +      }
 +      gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 +
 +      /* we_on */
 +      if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
 +              gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
 +      else
 +              gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
 +
 +      /* wr_access */
 +      /* XXX: gpmc_capability check reqd ? , even if not, will not harm */
 +      gpmc_t->wr_access = gpmc_t->access;
 +
 +      /* we_off */
 +      temp = gpmc_t->we_on + dev_t->t_wpl;
 +      temp = max_t(u32, temp,
 +                      gpmc_t->wr_access + gpmc_ticks_to_ps(1));
 +      temp = max_t(u32, temp,
 +              gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
 +      gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 +
 +      gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
 +                                                      dev_t->t_wph);
 +
 +      /* wr_cycle */
 +      temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
 +      temp += gpmc_t->wr_access;
 +      /* XXX: barter t_ce_rdyz with t_cez_w ? */
 +      if (dev_t->t_ce_rdyz)
 +              temp = max_t(u32, temp,
 +                               gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
 +      gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 +
 +      return 0;
 +}
 +
 +static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 +                                      struct gpmc_device_timings *dev_t,
 +                                      bool mux)
 +{
 +      u32 temp;
 +
 +      /* adv_rd_off */
 +      temp = dev_t->t_avdp_r;
 +      if (mux)
 +              temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 +      gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
 +
 +      /* oe_on */
 +      temp = dev_t->t_oeasu;
 +      if (mux)
 +              temp = max_t(u32, temp,
 +                      gpmc_t->adv_rd_off + dev_t->t_aavdh);
 +      gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 +
 +      /* access */
 +      temp = max_t(u32, dev_t->t_iaa, /* XXX: remove t_iaa in async ? */
 +                              gpmc_t->oe_on + dev_t->t_oe);
 +      temp = max_t(u32, temp,
 +                              gpmc_t->cs_on + dev_t->t_ce);
 +      temp = max_t(u32, temp,
 +                              gpmc_t->adv_on + dev_t->t_aa);
 +      gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 +
 +      gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
 +      gpmc_t->cs_rd_off = gpmc_t->oe_off;
 +
 +      /* rd_cycle */
 +      temp = max_t(u32, dev_t->t_rd_cycle,
 +                      gpmc_t->cs_rd_off + dev_t->t_cez_r);
 +      temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
 +      gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
 +
 +      return 0;
 +}
 +
 +static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 +                                       struct gpmc_device_timings *dev_t,
 +                                       bool mux)
 +{
 +      u32 temp;
 +
 +      /* adv_wr_off */
 +      temp = dev_t->t_avdp_w;
 +      if (mux)
 +              temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 +      gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
 +
 +      /* wr_data_mux_bus */
 +      temp = dev_t->t_weasu;
 +      if (mux) {
 +              temp = max_t(u32, temp, gpmc_t->adv_wr_off + dev_t->t_aavdh);
 +              temp = max_t(u32, temp, gpmc_t->adv_wr_off +
 +                              gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 +      }
 +      gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 +
 +      /* we_on */
 +      if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
 +              gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
 +      else
 +              gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
 +
 +      /* we_off */
 +      temp = gpmc_t->we_on + dev_t->t_wpl;
 +      gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 +
 +      gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
 +                                                      dev_t->t_wph);
 +
 +      /* wr_cycle */
 +      temp = max_t(u32, dev_t->t_wr_cycle,
 +                              gpmc_t->cs_wr_off + dev_t->t_cez_w);
 +      gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 +
 +      return 0;
 +}
 +
 +static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
 +                      struct gpmc_device_timings *dev_t)
 +{
 +      u32 temp;
 +
 +      gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
 +                                              gpmc_get_fclk_period();
 +
 +      gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
 +                                      dev_t->t_bacc,
 +                                      gpmc_t->sync_clk);
 +
 +      temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
 +      gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
 +
 +      if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
 +              return 0;
 +
 +      if (dev_t->ce_xdelay)
 +              gpmc_t->bool_timings.cs_extra_delay = true;
 +      if (dev_t->avd_xdelay)
 +              gpmc_t->bool_timings.adv_extra_delay = true;
 +      if (dev_t->oe_xdelay)
 +              gpmc_t->bool_timings.oe_extra_delay = true;
 +      if (dev_t->we_xdelay)
 +              gpmc_t->bool_timings.we_extra_delay = true;
 +
 +      return 0;
 +}
 +
 +static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
 +                                  struct gpmc_device_timings *dev_t,
 +                                  bool sync)
 +{
 +      u32 temp;
 +
 +      /* cs_on */
 +      gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
 +
 +      /* adv_on */
 +      temp = dev_t->t_avdasu;
 +      if (dev_t->t_ce_avd)
 +              temp = max_t(u32, temp,
 +                              gpmc_t->cs_on + dev_t->t_ce_avd);
 +      gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
 +
 +      if (sync)
 +              gpmc_calc_sync_common_timings(gpmc_t, dev_t);
 +
 +      return 0;
 +}
 +
 +/* TODO: remove this function once all peripherals are confirmed to
 + * work with generic timing. Simultaneously gpmc_cs_set_timings()
 + * has to be modified to handle timings in ps instead of ns
 +*/
 +static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
 +{
 +      t->cs_on /= 1000;
 +      t->cs_rd_off /= 1000;
 +      t->cs_wr_off /= 1000;
 +      t->adv_on /= 1000;
 +      t->adv_rd_off /= 1000;
 +      t->adv_wr_off /= 1000;
 +      t->we_on /= 1000;
 +      t->we_off /= 1000;
 +      t->oe_on /= 1000;
 +      t->oe_off /= 1000;
 +      t->page_burst_access /= 1000;
 +      t->access /= 1000;
 +      t->rd_cycle /= 1000;
 +      t->wr_cycle /= 1000;
 +      t->bus_turnaround /= 1000;
 +      t->cycle2cycle_delay /= 1000;
 +      t->wait_monitoring /= 1000;
 +      t->clk_activation /= 1000;
 +      t->wr_access /= 1000;
 +      t->wr_data_mux_bus /= 1000;
 +}
 +
 +int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 +                    struct gpmc_settings *gpmc_s,
 +                    struct gpmc_device_timings *dev_t)
 +{
 +      bool mux = false, sync = false;
 +
 +      if (gpmc_s) {
 +              mux = gpmc_s->mux_add_data ? true : false;
 +              sync = (gpmc_s->sync_read || gpmc_s->sync_write);
 +      }
 +
 +      memset(gpmc_t, 0, sizeof(*gpmc_t));
 +
 +      gpmc_calc_common_timings(gpmc_t, dev_t, sync);
 +
 +      if (gpmc_s && gpmc_s->sync_read)
 +              gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
 +      else
 +              gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
 +
 +      if (gpmc_s && gpmc_s->sync_write)
 +              gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
 +      else
 +              gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
 +
 +      /* TODO: remove, see function definition */
 +      gpmc_convert_ps_to_ns(gpmc_t);
 +
 +      return 0;
 +}
 +
 +/**
 + * gpmc_cs_program_settings - programs non-timing related settings
 + * @cs:               GPMC chip-select to program
 + * @p:                pointer to GPMC settings structure
 + *
 + * Programs non-timing related settings for a GPMC chip-select, such as
 + * bus-width, burst configuration, etc. Function should be called once
 + * for each chip-select that is being used and must be called before
 + * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
 + * register will be initialised to zero by this function. Returns 0 on
 + * success and appropriate negative error code on failure.
 + */
 +int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
 +{
 +      u32 config1;
 +
 +      if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
 +              pr_err("%s: invalid width %d!", __func__, p->device_width);
 +              return -EINVAL;
 +      }
 +
 +      /* Address-data multiplexing not supported for NAND devices */
 +      if (p->device_nand && p->mux_add_data) {
 +              pr_err("%s: invalid configuration!\n", __func__);
 +              return -EINVAL;
 +      }
 +
 +      if ((p->mux_add_data > GPMC_MUX_AD) ||
 +          ((p->mux_add_data == GPMC_MUX_AAD) &&
 +           !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
 +              pr_err("%s: invalid multiplex configuration!\n", __func__);
 +              return -EINVAL;
 +      }
 +
 +      /* Page/burst mode supports lengths of 4, 8 and 16 bytes */
 +      if (p->burst_read || p->burst_write) {
 +              switch (p->burst_len) {
 +              case GPMC_BURST_4:
 +              case GPMC_BURST_8:
 +              case GPMC_BURST_16:
 +                      break;
 +              default:
 +                      pr_err("%s: invalid page/burst-length (%d)\n",
 +                             __func__, p->burst_len);
 +                      return -EINVAL;
 +              }
 +      }
 +
 +      if (p->wait_pin > gpmc_nr_waitpins) {
 +              pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
 +              return -EINVAL;
 +      }
 +
 +      config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
 +
 +      if (p->sync_read)
 +              config1 |= GPMC_CONFIG1_READTYPE_SYNC;
 +      if (p->sync_write)
 +              config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
 +      if (p->wait_on_read)
 +              config1 |= GPMC_CONFIG1_WAIT_READ_MON;
 +      if (p->wait_on_write)
 +              config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
 +      if (p->wait_on_read || p->wait_on_write)
 +              config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
 +      if (p->device_nand)
 +              config1 |= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
 +      if (p->mux_add_data)
 +              config1 |= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
 +      if (p->burst_read)
 +              config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
 +      if (p->burst_write)
 +              config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
 +      if (p->burst_read || p->burst_write) {
 +              config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
 +              config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
 +      }
 +
 +      gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
 +
 +      return 0;
 +}
 +
 +#ifdef CONFIG_OF
 +static const struct of_device_id gpmc_dt_ids[] = {
 +      { .compatible = "ti,omap2420-gpmc" },
 +      { .compatible = "ti,omap2430-gpmc" },
 +      { .compatible = "ti,omap3430-gpmc" },   /* omap3430 & omap3630 */
 +      { .compatible = "ti,omap4430-gpmc" },   /* omap4430 & omap4460 & omap543x */
 +      { .compatible = "ti,am3352-gpmc" },     /* am335x devices */
 +      { }
 +};
 +MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
 +
 +/**
 + * gpmc_read_settings_dt - read gpmc settings from device-tree
 + * @np:               pointer to device-tree node for a gpmc child device
 + * @p:                pointer to gpmc settings structure
 + *
 + * Reads the GPMC settings for a GPMC child device from device-tree and
 + * stores them in the GPMC settings structure passed. The GPMC settings
 + * structure is initialised to zero by this function and so any
 + * previously stored settings will be cleared.
 + */
 +void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
 +{
 +      memset(p, 0, sizeof(struct gpmc_settings));
 +
 +      p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
 +      p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
 +      of_property_read_u32(np, "gpmc,device-width", &p->device_width);
 +      of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
 +
 +      if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
 +              p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
 +              p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
 +              p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
 +              if (!p->burst_read && !p->burst_write)
 +                      pr_warn("%s: page/burst-length set but not used!\n",
 +                              __func__);
 +      }
 +
 +      if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
 +              p->wait_on_read = of_property_read_bool(np,
 +                                                      "gpmc,wait-on-read");
 +              p->wait_on_write = of_property_read_bool(np,
 +                                                       "gpmc,wait-on-write");
 +              if (!p->wait_on_read && !p->wait_on_write)
 +                      pr_debug("%s: rd/wr wait monitoring not enabled!\n",
 +                               __func__);
 +      }
 +}
 +
 +static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 +                                              struct gpmc_timings *gpmc_t)
 +{
 +      struct gpmc_bool_timings *p;
 +
 +      if (!np || !gpmc_t)
 +              return;
 +
 +      memset(gpmc_t, 0, sizeof(*gpmc_t));
 +
 +      /* minimum clock period for syncronous mode */
 +      of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
 +
 +      /* chip select timtings */
 +      of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
 +      of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
 +      of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
 +
 +      /* ADV signal timings */
 +      of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
 +      of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
 +      of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
 +
 +      /* WE signal timings */
 +      of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
 +      of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
 +
 +      /* OE signal timings */
 +      of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
 +      of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
 +
 +      /* access and cycle timings */
 +      of_property_read_u32(np, "gpmc,page-burst-access-ns",
 +                           &gpmc_t->page_burst_access);
 +      of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
 +      of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
 +      of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
 +      of_property_read_u32(np, "gpmc,bus-turnaround-ns",
 +                           &gpmc_t->bus_turnaround);
 +      of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
 +                           &gpmc_t->cycle2cycle_delay);
 +      of_property_read_u32(np, "gpmc,wait-monitoring-ns",
 +                           &gpmc_t->wait_monitoring);
 +      of_property_read_u32(np, "gpmc,clk-activation-ns",
 +                           &gpmc_t->clk_activation);
 +
 +      /* only applicable to OMAP3+ */
 +      of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
 +      of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
 +                           &gpmc_t->wr_data_mux_bus);
 +
 +      /* bool timing parameters */
 +      p = &gpmc_t->bool_timings;
 +
 +      p->cycle2cyclediffcsen =
 +              of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
 +      p->cycle2cyclesamecsen =
 +              of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
 +      p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
 +      p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
 +      p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
 +      p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
 +      p->time_para_granularity =
 +              of_property_read_bool(np, "gpmc,time-para-granularity");
 +}
 +
 +#if IS_ENABLED(CONFIG_MTD_NAND)
 +
 +static const char * const nand_xfer_types[] = {
 +      [NAND_OMAP_PREFETCH_POLLED]             = "prefetch-polled",
 +      [NAND_OMAP_POLLED]                      = "polled",
 +      [NAND_OMAP_PREFETCH_DMA]                = "prefetch-dma",
 +      [NAND_OMAP_PREFETCH_IRQ]                = "prefetch-irq",
 +};
 +
 +static int gpmc_probe_nand_child(struct platform_device *pdev,
 +                               struct device_node *child)
 +{
 +      u32 val;
 +      const char *s;
 +      struct gpmc_timings gpmc_t;
 +      struct omap_nand_platform_data *gpmc_nand_data;
 +
 +      if (of_property_read_u32(child, "reg", &val) < 0) {
 +              dev_err(&pdev->dev, "%s has no 'reg' property\n",
 +                      child->full_name);
 +              return -ENODEV;
 +      }
 +
 +      gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
 +                                    GFP_KERNEL);
 +      if (!gpmc_nand_data)
 +              return -ENOMEM;
 +
 +      gpmc_nand_data->cs = val;
 +      gpmc_nand_data->of_node = child;
 +
 +      /* Detect availability of ELM module */
 +      gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
 +      if (gpmc_nand_data->elm_of_node == NULL)
 +              gpmc_nand_data->elm_of_node =
 +                                      of_parse_phandle(child, "elm_id", 0);
 +
 +      /* select ecc-scheme for NAND */
 +      if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
 +              pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
 +              return -ENODEV;
 +      }
 +
 +      if (!strcmp(s, "sw"))
 +              gpmc_nand_data->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
 +      else if (!strcmp(s, "ham1") ||
 +               !strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
 +              gpmc_nand_data->ecc_opt =
 +                              OMAP_ECC_HAM1_CODE_HW;
 +      else if (!strcmp(s, "bch4"))
 +              if (gpmc_nand_data->elm_of_node)
 +                      gpmc_nand_data->ecc_opt =
 +                              OMAP_ECC_BCH4_CODE_HW;
 +              else
 +                      gpmc_nand_data->ecc_opt =
 +                              OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
 +      else if (!strcmp(s, "bch8"))
 +              if (gpmc_nand_data->elm_of_node)
 +                      gpmc_nand_data->ecc_opt =
 +                              OMAP_ECC_BCH8_CODE_HW;
 +              else
 +                      gpmc_nand_data->ecc_opt =
 +                              OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
 +      else if (!strcmp(s, "bch16"))
 +              if (gpmc_nand_data->elm_of_node)
 +                      gpmc_nand_data->ecc_opt =
 +                              OMAP_ECC_BCH16_CODE_HW;
 +              else
 +                      pr_err("%s: BCH16 requires ELM support\n", __func__);
 +      else
 +              pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
 +
 +      /* select data transfer mode for NAND controller */
 +      if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
 +              for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
 +                      if (!strcasecmp(s, nand_xfer_types[val])) {
 +                              gpmc_nand_data->xfer_type = val;
 +                              break;
 +                      }
 +
 +      gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child);
 +
 +      val = of_get_nand_bus_width(child);
 +      if (val == 16)
 +              gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
 +
 +      gpmc_read_timings_dt(child, &gpmc_t);
 +      gpmc_nand_init(gpmc_nand_data, &gpmc_t);
 +
 +      return 0;
 +}
 +#else
 +static int gpmc_probe_nand_child(struct platform_device *pdev,
 +                               struct device_node *child)
 +{
 +      return 0;
 +}
 +#endif
 +
 +#if IS_ENABLED(CONFIG_MTD_ONENAND)
 +static int gpmc_probe_onenand_child(struct platform_device *pdev,
 +                               struct device_node *child)
 +{
 +      u32 val;
 +      struct omap_onenand_platform_data *gpmc_onenand_data;
 +
 +      if (of_property_read_u32(child, "reg", &val) < 0) {
 +              dev_err(&pdev->dev, "%s has no 'reg' property\n",
 +                      child->full_name);
 +              return -ENODEV;
 +      }
 +
 +      gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
 +                                       GFP_KERNEL);
 +      if (!gpmc_onenand_data)
 +              return -ENOMEM;
 +
 +      gpmc_onenand_data->cs = val;
 +      gpmc_onenand_data->of_node = child;
 +      gpmc_onenand_data->dma_channel = -1;
 +
 +      if (!of_property_read_u32(child, "dma-channel", &val))
 +              gpmc_onenand_data->dma_channel = val;
 +
 +      gpmc_onenand_init(gpmc_onenand_data);
 +
 +      return 0;
 +}
 +#else
 +static int gpmc_probe_onenand_child(struct platform_device *pdev,
 +                                  struct device_node *child)
 +{
 +      return 0;
 +}
 +#endif
 +
 +/**
 + * gpmc_probe_generic_child - configures the gpmc for a child device
 + * @pdev:     pointer to gpmc platform device
 + * @child:    pointer to device-tree node for child device
 + *
 + * Allocates and configures a GPMC chip-select for a child device.
 + * Returns 0 on success and appropriate negative error code on failure.
 + */
 +static int gpmc_probe_generic_child(struct platform_device *pdev,
 +                              struct device_node *child)
 +{
 +      struct gpmc_settings gpmc_s;
 +      struct gpmc_timings gpmc_t;
 +      struct resource res;
 +      unsigned long base;
 +      const char *name;
 +      int ret, cs;
 +      u32 val;
 +
 +      if (of_property_read_u32(child, "reg", &cs) < 0) {
 +              dev_err(&pdev->dev, "%s has no 'reg' property\n",
 +                      child->full_name);
 +              return -ENODEV;
 +      }
 +
 +      if (of_address_to_resource(child, 0, &res) < 0) {
 +              dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
 +                      child->full_name);
 +              return -ENODEV;
 +      }
 +
 +      /*
 +       * Check if we have multiple instances of the same device
 +       * on a single chip select. If so, use the already initialized
 +       * timings.
 +       */
 +      name = gpmc_cs_get_name(cs);
 +      if (name && child->name && of_node_cmp(child->name, name) == 0)
 +                      goto no_timings;
 +
 +      ret = gpmc_cs_request(cs, resource_size(&res), &base);
 +      if (ret < 0) {
 +              dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
 +              return ret;
 +      }
 +      gpmc_cs_set_name(cs, child->name);
 +
 +      gpmc_read_settings_dt(child, &gpmc_s);
 +      gpmc_read_timings_dt(child, &gpmc_t);
 +
 +      /*
 +       * For some GPMC devices we still need to rely on the bootloader
 +       * timings because the devices can be connected via FPGA.
 +       * REVISIT: Add timing support from slls644g.pdf.
 +       */
 +      if (!gpmc_t.cs_rd_off) {
 +              WARN(1, "enable GPMC debug to configure .dts timings for CS%i\n",
 +                      cs);
 +              gpmc_cs_show_timings(cs,
 +                                   "please add GPMC bootloader timings to .dts");
 +              goto no_timings;
 +      }
 +
 +      /* CS must be disabled while making changes to gpmc configuration */
 +      gpmc_cs_disable_mem(cs);
 +
 +      /*
 +       * FIXME: gpmc_cs_request() will map the CS to an arbitary
 +       * location in the gpmc address space. When booting with
 +       * device-tree we want the NOR flash to be mapped to the
 +       * location specified in the device-tree blob. So remap the
 +       * CS to this location. Once DT migration is complete should
 +       * just make gpmc_cs_request() map a specific address.
 +       */
 +      ret = gpmc_cs_remap(cs, res.start);
 +      if (ret < 0) {
 +              dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
 +                      cs, &res.start);
 +              goto err;
 +      }
 +
 +      ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
 +      if (ret < 0)
 +              goto err;
 +
 +      ret = gpmc_cs_program_settings(cs, &gpmc_s);
 +      if (ret < 0)
 +              goto err;
 +
 +      ret = gpmc_cs_set_timings(cs, &gpmc_t);
 +      if (ret) {
 +              dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n",
 +                      child->name);
 +              goto err;
 +      }
 +
 +      /* Clear limited address i.e. enable A26-A11 */
 +      val = gpmc_read_reg(GPMC_CONFIG);
 +      val &= ~GPMC_CONFIG_LIMITEDADDRESS;
 +      gpmc_write_reg(GPMC_CONFIG, val);
 +
 +      /* Enable CS region */
 +      gpmc_cs_enable_mem(cs);
 +
 +no_timings:
 +      if (of_platform_device_create(child, NULL, &pdev->dev))
 +              return 0;
 +
 +      dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
 +      ret = -ENODEV;
 +
 +err:
 +      gpmc_cs_free(cs);
 +
 +      return ret;
 +}
 +
 +static int gpmc_probe_dt(struct platform_device *pdev)
 +{
 +      int ret;
 +      struct device_node *child;
 +      const struct of_device_id *of_id =
 +              of_match_device(gpmc_dt_ids, &pdev->dev);
 +
 +      if (!of_id)
 +              return 0;
 +
 +      ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
 +                                 &gpmc_cs_num);
 +      if (ret < 0) {
 +              pr_err("%s: number of chip-selects not defined\n", __func__);
 +              return ret;
 +      } else if (gpmc_cs_num < 1) {
 +              pr_err("%s: all chip-selects are disabled\n", __func__);
 +              return -EINVAL;
 +      } else if (gpmc_cs_num > GPMC_CS_NUM) {
 +              pr_err("%s: number of supported chip-selects cannot be > %d\n",
 +                                       __func__, GPMC_CS_NUM);
 +              return -EINVAL;
 +      }
 +
 +      ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
 +                                 &gpmc_nr_waitpins);
 +      if (ret < 0) {
 +              pr_err("%s: number of wait pins not found!\n", __func__);
 +              return ret;
 +      }
 +
 +      for_each_available_child_of_node(pdev->dev.of_node, child) {
 +
 +              if (!child->name)
 +                      continue;
 +
 +              if (of_node_cmp(child->name, "nand") == 0)
 +                      ret = gpmc_probe_nand_child(pdev, child);
 +              else if (of_node_cmp(child->name, "onenand") == 0)
 +                      ret = gpmc_probe_onenand_child(pdev, child);
 +              else if (of_node_cmp(child->name, "ethernet") == 0 ||
 +                       of_node_cmp(child->name, "nor") == 0 ||
 +                       of_node_cmp(child->name, "uart") == 0)
 +                      ret = gpmc_probe_generic_child(pdev, child);
 +
 +              if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
 +                       __func__, child->full_name))
 +                      of_node_put(child);
 +      }
 +
 +      return 0;
 +}
 +#else
 +static int gpmc_probe_dt(struct platform_device *pdev)
 +{
 +      return 0;
 +}
 +#endif
 +
 +static int gpmc_probe(struct platform_device *pdev)
 +{
 +      int rc;
 +      u32 l;
 +      struct resource *res;
 +
 +      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 +      if (res == NULL)
 +              return -ENOENT;
 +
 +      phys_base = res->start;
 +      mem_size = resource_size(res);
 +
 +      gpmc_base = devm_ioremap_resource(&pdev->dev, res);
 +      if (IS_ERR(gpmc_base))
 +              return PTR_ERR(gpmc_base);
 +
 +      res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 +      if (res == NULL)
 +              dev_warn(&pdev->dev, "Failed to get resource: irq\n");
 +      else
 +              gpmc_irq = res->start;
 +
 +      gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck");
 +      if (IS_ERR(gpmc_l3_clk)) {
 +              dev_err(&pdev->dev, "Failed to get GPMC fck\n");
 +              gpmc_irq = 0;
 +              return PTR_ERR(gpmc_l3_clk);
 +      }
 +
 +      if (!clk_get_rate(gpmc_l3_clk)) {
 +              dev_err(&pdev->dev, "Invalid GPMC fck clock rate\n");
 +              return -EINVAL;
 +      }
 +
 +      pm_runtime_enable(&pdev->dev);
 +      pm_runtime_get_sync(&pdev->dev);
 +
 +      gpmc_dev = &pdev->dev;
 +
 +      l = gpmc_read_reg(GPMC_REVISION);
 +
 +      /*
 +       * FIXME: Once device-tree migration is complete the below flags
 +       * should be populated based upon the device-tree compatible
 +       * string. For now just use the IP revision. OMAP3+ devices have
 +       * the wr_access and wr_data_mux_bus register fields. OMAP4+
 +       * devices support the addr-addr-data multiplex protocol.
 +       *
 +       * GPMC IP revisions:
 +       * - OMAP24xx                   = 2.0
 +       * - OMAP3xxx                   = 5.0
 +       * - OMAP44xx/54xx/AM335x       = 6.0
 +       */
 +      if (GPMC_REVISION_MAJOR(l) > 0x4)
 +              gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
 +      if (GPMC_REVISION_MAJOR(l) > 0x5)
 +              gpmc_capability |= GPMC_HAS_MUX_AAD;
 +      dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
 +               GPMC_REVISION_MINOR(l));
 +
 +      gpmc_mem_init();
 +
 +      if (gpmc_setup_irq() < 0)
 +              dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
 +
 +      if (!pdev->dev.of_node) {
 +              gpmc_cs_num      = GPMC_CS_NUM;
 +              gpmc_nr_waitpins = GPMC_NR_WAITPINS;
 +      }
 +
 +      rc = gpmc_probe_dt(pdev);
 +      if (rc < 0) {
 +              pm_runtime_put_sync(&pdev->dev);
 +              dev_err(gpmc_dev, "failed to probe DT parameters\n");
 +              return rc;
 +      }
 +
 +      return 0;
 +}
 +
 +static int gpmc_remove(struct platform_device *pdev)
 +{
 +      gpmc_free_irq();
 +      gpmc_mem_exit();
 +      pm_runtime_put_sync(&pdev->dev);
 +      pm_runtime_disable(&pdev->dev);
 +      gpmc_dev = NULL;
 +      return 0;
 +}
 +
 +#ifdef CONFIG_PM_SLEEP
 +static int gpmc_suspend(struct device *dev)
 +{
 +      omap3_gpmc_save_context();
 +      pm_runtime_put_sync(dev);
 +      return 0;
 +}
 +
 +static int gpmc_resume(struct device *dev)
 +{
 +      pm_runtime_get_sync(dev);
 +      omap3_gpmc_restore_context();
 +      return 0;
 +}
 +#endif
 +
 +static SIMPLE_DEV_PM_OPS(gpmc_pm_ops, gpmc_suspend, gpmc_resume);
 +
 +static struct platform_driver gpmc_driver = {
 +      .probe          = gpmc_probe,
 +      .remove         = gpmc_remove,
 +      .driver         = {
 +              .name   = DEVICE_NAME,
 +              .of_match_table = of_match_ptr(gpmc_dt_ids),
 +              .pm     = &gpmc_pm_ops,
 +      },
 +};
 +
 +static __init int gpmc_init(void)
 +{
 +      return platform_driver_register(&gpmc_driver);
 +}
 +
 +static __exit void gpmc_exit(void)
 +{
 +      platform_driver_unregister(&gpmc_driver);
 +
 +}
 +
 +postcore_initcall(gpmc_init);
 +module_exit(gpmc_exit);
 +
 +static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 +{
 +      int i;
 +      u32 regval;
 +
 +      regval = gpmc_read_reg(GPMC_IRQSTATUS);
 +
 +      if (!regval)
 +              return IRQ_NONE;
 +
 +      for (i = 0; i < GPMC_NR_IRQ; i++)
 +              if (regval & gpmc_client_irq[i].bitmask)
 +                      generic_handle_irq(gpmc_client_irq[i].irq);
 +
 +      gpmc_write_reg(GPMC_IRQSTATUS, regval);
 +
 +      return IRQ_HANDLED;
 +}
 +
 +static struct omap3_gpmc_regs gpmc_context;
 +
 +void omap3_gpmc_save_context(void)
 +{
 +      int i;
 +
 +      gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
 +      gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
 +      gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
 +      gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
 +      gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
 +      gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
 +      gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
 +      for (i = 0; i < gpmc_cs_num; i++) {
 +              gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
 +              if (gpmc_context.cs_context[i].is_valid) {
 +                      gpmc_context.cs_context[i].config1 =
 +                              gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
 +                      gpmc_context.cs_context[i].config2 =
 +                              gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
 +                      gpmc_context.cs_context[i].config3 =
 +                              gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
 +                      gpmc_context.cs_context[i].config4 =
 +                              gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
 +                      gpmc_context.cs_context[i].config5 =
 +                              gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
 +                      gpmc_context.cs_context[i].config6 =
 +                              gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
 +                      gpmc_context.cs_context[i].config7 =
 +                              gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
 +              }
 +      }
 +}
 +
 +void omap3_gpmc_restore_context(void)
 +{
 +      int i;
 +
 +      gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
 +      gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
 +      gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
 +      gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
 +      gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
 +      gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
 +      gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
 +      for (i = 0; i < gpmc_cs_num; i++) {
 +              if (gpmc_context.cs_context[i].is_valid) {
 +                      gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
 +                              gpmc_context.cs_context[i].config1);
 +                      gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
 +                              gpmc_context.cs_context[i].config2);
 +                      gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
 +                              gpmc_context.cs_context[i].config3);
 +                      gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
 +                              gpmc_context.cs_context[i].config4);
 +                      gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
 +                              gpmc_context.cs_context[i].config5);
 +                      gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
 +                              gpmc_context.cs_context[i].config6);
 +                      gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
 +                              gpmc_context.cs_context[i].config7);
 +              }
 +      }
 +}
Simple merge
Simple merge
Simple merge
@@@ -219,7 -166,7 +219,6 @@@ static const struct platform_device_id 
  static struct platform_driver syscon_driver = {
        .driver = {
                .name = "syscon",
-               .owner = THIS_MODULE,
 -              .of_match_table = of_syscon_match,
        },
        .probe          = syscon_probe,
        .id_table       = syscon_ids,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -832,57 -758,42 +758,46 @@@ static int read_file_misc(struct seq_fi
                        continue;
                ath9k_calculate_iter_data(sc, ctx, &iter_data);
  
-               len += scnprintf(buf + len, sizeof(buf) - len,
-                       "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i WDS: %i",
-                       i++, (int)(ctx->assigned), iter_data.naps,
-                       iter_data.nstations,
-                       iter_data.nmeshes, iter_data.nwds);
-               len += scnprintf(buf + len, sizeof(buf) - len,
-                       " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
-                       iter_data.nadhocs, sc->cur_chan->nvifs, sc->nbcnvifs);
+               seq_printf(file,
 -                         "VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i",
 -                         i++, iter_data.naps, iter_data.nstations,
++                         "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i WDS: %i",
++                         i++, (int)(ctx->assigned), iter_data.naps,
++                         iter_data.nstations,
+                          iter_data.nmeshes, iter_data.nwds);
+               seq_printf(file, " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
+                          iter_data.nadhocs, sc->cur_chan->nvifs,
+                          sc->nbcnvifs);
        }
  
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-       return retval;
+       return 0;
  }
  
- static ssize_t read_file_reset(struct file *file, char __user *user_buf,
-                              size_t count, loff_t *ppos)
+ static int read_file_reset(struct seq_file *file, void *data)
  {
-       struct ath_softc *sc = file->private_data;
+       struct ath_softc *sc = file->private;
 +      static const char * const reset_cause[__RESET_TYPE_MAX] = {
 +              [RESET_TYPE_BB_HANG] = "Baseband Hang",
 +              [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog",
 +              [RESET_TYPE_FATAL_INT] = "Fatal HW Error",
 +              [RESET_TYPE_TX_ERROR] = "TX HW error",
 +              [RESET_TYPE_TX_GTT] = "Transmit timeout",
 +              [RESET_TYPE_TX_HANG] = "TX Path Hang",
 +              [RESET_TYPE_PLL_HANG] = "PLL RX Hang",
 +              [RESET_TYPE_MAC_HANG] = "MAC Hang",
 +              [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
 +              [RESET_TYPE_MCI] = "MCI Reset",
 +              [RESET_TYPE_CALIBRATION] = "Calibration error",
 +      };
-       char buf[512];
-       unsigned int len = 0;
 +      int i;
  
 -      seq_printf(file, "%17s: %2d\n", "Baseband Hang",
 -                 sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
 -      seq_printf(file, "%17s: %2d\n", "Baseband Watchdog",
 -                 sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
 -      seq_printf(file, "%17s: %2d\n", "Fatal HW Error",
 -                 sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
 -      seq_printf(file, "%17s: %2d\n", "TX HW error",
 -                 sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
 -      seq_printf(file, "%17s: %2d\n", "TX Path Hang",
 -                 sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
 -      seq_printf(file, "%17s: %2d\n", "PLL RX Hang",
 -                 sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
 -      seq_printf(file, "%17s: %2d\n", "MAC Hang",
 -                 sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
 -      seq_printf(file, "%17s: %2d\n", "Stuck Beacon",
 -                 sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
 -      seq_printf(file, "%17s: %2d\n", "MCI Reset",
 -                 sc->debug.stats.reset[RESET_TYPE_MCI]);
 +      for (i = 0; i < ARRAY_SIZE(reset_cause); i++) {
 +              if (!reset_cause[i])
 +                  continue;
 +
-               len += scnprintf(buf + len, sizeof(buf) - len,
-                                "%17s: %2d\n", reset_cause[i],
-                                sc->debug.stats.reset[i]);
++              seq_printf(file, "%17s: %2d\n", reset_cause[i],
++                         sc->debug.stats.reset[i]);
 +      }
  
-       if (len > sizeof(buf))
-               len = sizeof(buf);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       return 0;
  }
  
  void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 7db0004,0000000..5afe03e
mode 100644,000000..100644
--- /dev/null
@@@ -1,625 -1,0 +1,624 @@@
-               .owner  = THIS_MODULE,
 +/*
 + * Pinctrl GPIO driver for Intel Baytrail
 + * Copyright (c) 2012-2013, Intel Corporation.
 + *
 + * Author: Mathias Nyman <mathias.nyman@linux.intel.com>
 + *
 + * 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, write to the Free Software Foundation, Inc.,
 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/types.h>
 +#include <linux/bitops.h>
 +#include <linux/interrupt.h>
 +#include <linux/gpio.h>
 +#include <linux/acpi.h>
 +#include <linux/platform_device.h>
 +#include <linux/seq_file.h>
 +#include <linux/io.h>
 +#include <linux/pm_runtime.h>
 +#include <linux/pinctrl/pinctrl.h>
 +
 +/* memory mapped register offsets */
 +#define BYT_CONF0_REG         0x000
 +#define BYT_CONF1_REG         0x004
 +#define BYT_VAL_REG           0x008
 +#define BYT_DFT_REG           0x00c
 +#define BYT_INT_STAT_REG      0x800
 +
 +/* BYT_CONF0_REG register bits */
 +#define BYT_IODEN             BIT(31)
 +#define BYT_DIRECT_IRQ_EN     BIT(27)
 +#define BYT_TRIG_NEG          BIT(26)
 +#define BYT_TRIG_POS          BIT(25)
 +#define BYT_TRIG_LVL          BIT(24)
 +#define BYT_PULL_STR_SHIFT    9
 +#define BYT_PULL_STR_MASK     (3 << BYT_PULL_STR_SHIFT)
 +#define BYT_PULL_STR_2K               (0 << BYT_PULL_STR_SHIFT)
 +#define BYT_PULL_STR_10K      (1 << BYT_PULL_STR_SHIFT)
 +#define BYT_PULL_STR_20K      (2 << BYT_PULL_STR_SHIFT)
 +#define BYT_PULL_STR_40K      (3 << BYT_PULL_STR_SHIFT)
 +#define BYT_PULL_ASSIGN_SHIFT 7
 +#define BYT_PULL_ASSIGN_MASK  (3 << BYT_PULL_ASSIGN_SHIFT)
 +#define BYT_PULL_ASSIGN_UP    (1 << BYT_PULL_ASSIGN_SHIFT)
 +#define BYT_PULL_ASSIGN_DOWN  (2 << BYT_PULL_ASSIGN_SHIFT)
 +#define BYT_PIN_MUX           0x07
 +
 +/* BYT_VAL_REG register bits */
 +#define BYT_INPUT_EN          BIT(2)  /* 0: input enabled (active low)*/
 +#define BYT_OUTPUT_EN         BIT(1)  /* 0: output enabled (active low)*/
 +#define BYT_LEVEL             BIT(0)
 +
 +#define BYT_DIR_MASK          (BIT(1) | BIT(2))
 +#define BYT_TRIG_MASK         (BIT(26) | BIT(25) | BIT(24))
 +
 +#define BYT_NGPIO_SCORE               102
 +#define BYT_NGPIO_NCORE               28
 +#define BYT_NGPIO_SUS         44
 +
 +#define BYT_SCORE_ACPI_UID    "1"
 +#define BYT_NCORE_ACPI_UID    "2"
 +#define BYT_SUS_ACPI_UID      "3"
 +
 +/*
 + * Baytrail gpio controller consist of three separate sub-controllers called
 + * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
 + *
 + * GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace does
 + * _not_ correspond to the first gpio register at controller's gpio base.
 + * There is no logic or pattern in mapping gpio numbers to registers (pads) so
 + * each sub-controller needs to have its own mapping table
 + */
 +
 +/* score_pins[gpio_nr] = pad_nr */
 +
 +static unsigned const score_pins[BYT_NGPIO_SCORE] = {
 +      85, 89, 93, 96, 99, 102, 98, 101, 34, 37,
 +      36, 38, 39, 35, 40, 84, 62, 61, 64, 59,
 +      54, 56, 60, 55, 63, 57, 51, 50, 53, 47,
 +      52, 49, 48, 43, 46, 41, 45, 42, 58, 44,
 +      95, 105, 70, 68, 67, 66, 69, 71, 65, 72,
 +      86, 90, 88, 92, 103, 77, 79, 83, 78, 81,
 +      80, 82, 13, 12, 15, 14, 17, 18, 19, 16,
 +      2, 1, 0, 4, 6, 7, 9, 8, 33, 32,
 +      31, 30, 29, 27, 25, 28, 26, 23, 21, 20,
 +      24, 22, 5, 3, 10, 11, 106, 87, 91, 104,
 +      97, 100,
 +};
 +
 +static unsigned const ncore_pins[BYT_NGPIO_NCORE] = {
 +      19, 18, 17, 20, 21, 22, 24, 25, 23, 16,
 +      14, 15, 12, 26, 27, 1, 4, 8, 11, 0,
 +      3, 6, 10, 13, 2, 5, 9, 7,
 +};
 +
 +static unsigned const sus_pins[BYT_NGPIO_SUS] = {
 +      29, 33, 30, 31, 32, 34, 36, 35, 38, 37,
 +      18, 7, 11, 20, 17, 1, 8, 10, 19, 12,
 +      0, 2, 23, 39, 28, 27, 22, 21, 24, 25,
 +      26, 51, 56, 54, 49, 55, 48, 57, 50, 58,
 +      52, 53, 59, 40,
 +};
 +
 +static struct pinctrl_gpio_range byt_ranges[] = {
 +      {
 +              .name = BYT_SCORE_ACPI_UID, /* match with acpi _UID in probe */
 +              .npins = BYT_NGPIO_SCORE,
 +              .pins = score_pins,
 +      },
 +      {
 +              .name = BYT_NCORE_ACPI_UID,
 +              .npins = BYT_NGPIO_NCORE,
 +              .pins = ncore_pins,
 +      },
 +      {
 +              .name = BYT_SUS_ACPI_UID,
 +              .npins = BYT_NGPIO_SUS,
 +              .pins = sus_pins,
 +      },
 +      {
 +      },
 +};
 +
 +struct byt_gpio {
 +      struct gpio_chip                chip;
 +      struct platform_device          *pdev;
 +      spinlock_t                      lock;
 +      void __iomem                    *reg_base;
 +      struct pinctrl_gpio_range       *range;
 +};
 +
 +#define to_byt_gpio(c)        container_of(c, struct byt_gpio, chip)
 +
 +static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
 +                               int reg)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(chip);
 +      u32 reg_offset;
 +
 +      if (reg == BYT_INT_STAT_REG)
 +              reg_offset = (offset / 32) * 4;
 +      else
 +              reg_offset = vg->range->pins[offset] * 16;
 +
 +      return vg->reg_base + reg_offset + reg;
 +}
 +
 +static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
 +{
 +      /* SCORE pin 92-93 */
 +      if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
 +              offset >= 92 && offset <= 93)
 +              return true;
 +
 +      /* SUS pin 11-21 */
 +      if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
 +              offset >= 11 && offset <= 21)
 +              return true;
 +
 +      return false;
 +}
 +
 +static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(chip);
 +      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
 +      u32 value;
 +      bool special;
 +
 +      /*
 +       * In most cases, func pin mux 000 means GPIO function.
 +       * But, some pins may have func pin mux 001 represents
 +       * GPIO function. Only allow user to export pin with
 +       * func pin mux preset as GPIO function by BIOS/FW.
 +       */
 +      value = readl(reg) & BYT_PIN_MUX;
 +      special = is_special_pin(vg, offset);
 +      if ((special && value != 1) || (!special && value)) {
 +              dev_err(&vg->pdev->dev,
 +                      "pin %u cannot be used as GPIO.\n", offset);
 +              return -EINVAL;
 +      }
 +
 +      pm_runtime_get(&vg->pdev->dev);
 +
 +      return 0;
 +}
 +
 +static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(chip);
 +      void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
 +      u32 value;
 +
 +      /* clear interrupt triggering */
 +      value = readl(reg);
 +      value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
 +      writel(value, reg);
 +
 +      pm_runtime_put(&vg->pdev->dev);
 +}
 +
 +static int byt_irq_type(struct irq_data *d, unsigned type)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(irq_data_get_irq_chip_data(d));
 +      u32 offset = irqd_to_hwirq(d);
 +      u32 value;
 +      unsigned long flags;
 +      void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
 +
 +      if (offset >= vg->chip.ngpio)
 +              return -EINVAL;
 +
 +      spin_lock_irqsave(&vg->lock, flags);
 +      value = readl(reg);
 +
 +      WARN(value & BYT_DIRECT_IRQ_EN,
 +              "Bad pad config for io mode, force direct_irq_en bit clearing");
 +
 +      /* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits
 +       * are used to indicate high and low level triggering
 +       */
 +      value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
 +                 BYT_TRIG_LVL);
 +
 +      switch (type) {
 +      case IRQ_TYPE_LEVEL_HIGH:
 +              value |= BYT_TRIG_LVL;
 +      case IRQ_TYPE_EDGE_RISING:
 +              value |= BYT_TRIG_POS;
 +              break;
 +      case IRQ_TYPE_LEVEL_LOW:
 +              value |= BYT_TRIG_LVL;
 +      case IRQ_TYPE_EDGE_FALLING:
 +              value |= BYT_TRIG_NEG;
 +              break;
 +      case IRQ_TYPE_EDGE_BOTH:
 +              value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
 +              break;
 +      }
 +      writel(value, reg);
 +
 +      spin_unlock_irqrestore(&vg->lock, flags);
 +
 +      return 0;
 +}
 +
 +static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
 +{
 +      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
 +      return readl(reg) & BYT_LEVEL;
 +}
 +
 +static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(chip);
 +      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
 +      unsigned long flags;
 +      u32 old_val;
 +
 +      spin_lock_irqsave(&vg->lock, flags);
 +
 +      old_val = readl(reg);
 +
 +      if (value)
 +              writel(old_val | BYT_LEVEL, reg);
 +      else
 +              writel(old_val & ~BYT_LEVEL, reg);
 +
 +      spin_unlock_irqrestore(&vg->lock, flags);
 +}
 +
 +static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(chip);
 +      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
 +      unsigned long flags;
 +      u32 value;
 +
 +      spin_lock_irqsave(&vg->lock, flags);
 +
 +      value = readl(reg) | BYT_DIR_MASK;
 +      value &= ~BYT_INPUT_EN;         /* active low */
 +      writel(value, reg);
 +
 +      spin_unlock_irqrestore(&vg->lock, flags);
 +
 +      return 0;
 +}
 +
 +static int byt_gpio_direction_output(struct gpio_chip *chip,
 +                                   unsigned gpio, int value)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(chip);
 +      void __iomem *conf_reg = byt_gpio_reg(chip, gpio, BYT_CONF0_REG);
 +      void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
 +      unsigned long flags;
 +      u32 reg_val;
 +
 +      spin_lock_irqsave(&vg->lock, flags);
 +
 +      /*
 +       * Before making any direction modifications, do a check if gpio
 +       * is set for direct IRQ.  On baytrail, setting GPIO to output does
 +       * not make sense, so let's at least warn the caller before they shoot
 +       * themselves in the foot.
 +       */
 +      WARN(readl(conf_reg) & BYT_DIRECT_IRQ_EN,
 +              "Potential Error: Setting GPIO with direct_irq_en to output");
 +
 +      reg_val = readl(reg) | BYT_DIR_MASK;
 +      reg_val &= ~(BYT_OUTPUT_EN | BYT_INPUT_EN);
 +
 +      if (value)
 +              writel(reg_val | BYT_LEVEL, reg);
 +      else
 +              writel(reg_val & ~BYT_LEVEL, reg);
 +
 +      spin_unlock_irqrestore(&vg->lock, flags);
 +
 +      return 0;
 +}
 +
 +static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 +{
 +      struct byt_gpio *vg = to_byt_gpio(chip);
 +      int i;
 +      unsigned long flags;
 +      u32 conf0, val, offs;
 +
 +      spin_lock_irqsave(&vg->lock, flags);
 +
 +      for (i = 0; i < vg->chip.ngpio; i++) {
 +              const char *pull_str = NULL;
 +              const char *pull = NULL;
 +              const char *label;
 +              offs = vg->range->pins[i] * 16;
 +              conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG);
 +              val = readl(vg->reg_base + offs + BYT_VAL_REG);
 +
 +              label = gpiochip_is_requested(chip, i);
 +              if (!label)
 +                      label = "Unrequested";
 +
 +              switch (conf0 & BYT_PULL_ASSIGN_MASK) {
 +              case BYT_PULL_ASSIGN_UP:
 +                      pull = "up";
 +                      break;
 +              case BYT_PULL_ASSIGN_DOWN:
 +                      pull = "down";
 +                      break;
 +              }
 +
 +              switch (conf0 & BYT_PULL_STR_MASK) {
 +              case BYT_PULL_STR_2K:
 +                      pull_str = "2k";
 +                      break;
 +              case BYT_PULL_STR_10K:
 +                      pull_str = "10k";
 +                      break;
 +              case BYT_PULL_STR_20K:
 +                      pull_str = "20k";
 +                      break;
 +              case BYT_PULL_STR_40K:
 +                      pull_str = "40k";
 +                      break;
 +              }
 +
 +              seq_printf(s,
 +                         " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s",
 +                         i,
 +                         label,
 +                         val & BYT_INPUT_EN ? "  " : "in",
 +                         val & BYT_OUTPUT_EN ? "   " : "out",
 +                         val & BYT_LEVEL ? "hi" : "lo",
 +                         vg->range->pins[i], offs,
 +                         conf0 & 0x7,
 +                         conf0 & BYT_TRIG_NEG ? " fall" : "     ",
 +                         conf0 & BYT_TRIG_POS ? " rise" : "     ",
 +                         conf0 & BYT_TRIG_LVL ? " level" : "      ");
 +
 +              if (pull && pull_str)
 +                      seq_printf(s, " %-4s %-3s", pull, pull_str);
 +              else
 +                      seq_puts(s, "          ");
 +
 +              if (conf0 & BYT_IODEN)
 +                      seq_puts(s, " open-drain");
 +
 +              seq_puts(s, "\n");
 +      }
 +      spin_unlock_irqrestore(&vg->lock, flags);
 +}
 +
 +static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 +{
 +      struct irq_data *data = irq_desc_get_irq_data(desc);
 +      struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
 +      struct irq_chip *chip = irq_data_get_irq_chip(data);
 +      u32 base, pin, mask;
 +      void __iomem *reg;
 +      u32 pending;
 +      unsigned virq;
 +      int looplimit = 0;
 +
 +      /* check from GPIO controller which pin triggered the interrupt */
 +      for (base = 0; base < vg->chip.ngpio; base += 32) {
 +
 +              reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
 +
 +              while ((pending = readl(reg))) {
 +                      pin = __ffs(pending);
 +                      mask = BIT(pin);
 +                      /* Clear before handling so we can't lose an edge */
 +                      writel(mask, reg);
 +
 +                      virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
 +                      generic_handle_irq(virq);
 +
 +                      /* In case bios or user sets triggering incorretly a pin
 +                       * might remain in "interrupt triggered" state.
 +                       */
 +                      if (looplimit++ > 32) {
 +                              dev_err(&vg->pdev->dev,
 +                                      "Gpio %d interrupt flood, disabling\n",
 +                                      base + pin);
 +
 +                              reg = byt_gpio_reg(&vg->chip, base + pin,
 +                                                 BYT_CONF0_REG);
 +                              mask = readl(reg);
 +                              mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
 +                                        BYT_TRIG_LVL);
 +                              writel(mask, reg);
 +                              mask = readl(reg); /* flush */
 +                              break;
 +                      }
 +              }
 +      }
 +      chip->irq_eoi(data);
 +}
 +
 +static void byt_irq_unmask(struct irq_data *d)
 +{
 +}
 +
 +static void byt_irq_mask(struct irq_data *d)
 +{
 +}
 +
 +static struct irq_chip byt_irqchip = {
 +      .name = "BYT-GPIO",
 +      .irq_mask = byt_irq_mask,
 +      .irq_unmask = byt_irq_unmask,
 +      .irq_set_type = byt_irq_type,
 +      .flags = IRQCHIP_SKIP_SET_WAKE,
 +};
 +
 +static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 +{
 +      void __iomem *reg;
 +      u32 base, value;
 +
 +      /* clear interrupt status trigger registers */
 +      for (base = 0; base < vg->chip.ngpio; base += 32) {
 +              reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
 +              writel(0xffffffff, reg);
 +              /* make sure trigger bits are cleared, if not then a pin
 +                 might be misconfigured in bios */
 +              value = readl(reg);
 +              if (value)
 +                      dev_err(&vg->pdev->dev,
 +                              "GPIO interrupt error, pins misconfigured\n");
 +      }
 +}
 +
 +static int byt_gpio_probe(struct platform_device *pdev)
 +{
 +      struct byt_gpio *vg;
 +      struct gpio_chip *gc;
 +      struct resource *mem_rc, *irq_rc;
 +      struct device *dev = &pdev->dev;
 +      struct acpi_device *acpi_dev;
 +      struct pinctrl_gpio_range *range;
 +      acpi_handle handle = ACPI_HANDLE(dev);
 +      int ret;
 +
 +      if (acpi_bus_get_device(handle, &acpi_dev))
 +              return -ENODEV;
 +
 +      vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL);
 +      if (!vg) {
 +              dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n");
 +              return -ENOMEM;
 +      }
 +
 +      for (range = byt_ranges; range->name; range++) {
 +              if (!strcmp(acpi_dev->pnp.unique_id, range->name)) {
 +                      vg->chip.ngpio = range->npins;
 +                      vg->range = range;
 +                      break;
 +              }
 +      }
 +
 +      if (!vg->chip.ngpio || !vg->range)
 +              return -ENODEV;
 +
 +      vg->pdev = pdev;
 +      platform_set_drvdata(pdev, vg);
 +
 +      mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 +      vg->reg_base = devm_ioremap_resource(dev, mem_rc);
 +      if (IS_ERR(vg->reg_base))
 +              return PTR_ERR(vg->reg_base);
 +
 +      spin_lock_init(&vg->lock);
 +
 +      gc = &vg->chip;
 +      gc->label = dev_name(&pdev->dev);
 +      gc->owner = THIS_MODULE;
 +      gc->request = byt_gpio_request;
 +      gc->free = byt_gpio_free;
 +      gc->direction_input = byt_gpio_direction_input;
 +      gc->direction_output = byt_gpio_direction_output;
 +      gc->get = byt_gpio_get;
 +      gc->set = byt_gpio_set;
 +      gc->dbg_show = byt_gpio_dbg_show;
 +      gc->base = -1;
 +      gc->can_sleep = false;
 +      gc->dev = dev;
 +
 +      ret = gpiochip_add(gc);
 +      if (ret) {
 +              dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
 +              return ret;
 +      }
 +
 +      /* set up interrupts  */
 +      irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 +      if (irq_rc && irq_rc->start) {
 +              byt_gpio_irq_init_hw(vg);
 +              ret = gpiochip_irqchip_add(gc, &byt_irqchip, 0,
 +                                         handle_simple_irq, IRQ_TYPE_NONE);
 +              if (ret) {
 +                      dev_err(dev, "failed to add irqchip\n");
 +                      gpiochip_remove(gc);
 +                      return ret;
 +              }
 +
 +              gpiochip_set_chained_irqchip(gc, &byt_irqchip,
 +                                           (unsigned)irq_rc->start,
 +                                           byt_gpio_irq_handler);
 +      }
 +
 +      pm_runtime_enable(dev);
 +
 +      return 0;
 +}
 +
 +static int byt_gpio_runtime_suspend(struct device *dev)
 +{
 +      return 0;
 +}
 +
 +static int byt_gpio_runtime_resume(struct device *dev)
 +{
 +      return 0;
 +}
 +
 +static const struct dev_pm_ops byt_gpio_pm_ops = {
 +      .runtime_suspend = byt_gpio_runtime_suspend,
 +      .runtime_resume = byt_gpio_runtime_resume,
 +};
 +
 +static const struct acpi_device_id byt_gpio_acpi_match[] = {
 +      { "INT33B2", 0 },
 +      { "INT33FC", 0 },
 +      { }
 +};
 +MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match);
 +
 +static int byt_gpio_remove(struct platform_device *pdev)
 +{
 +      struct byt_gpio *vg = platform_get_drvdata(pdev);
 +
 +      pm_runtime_disable(&pdev->dev);
 +      gpiochip_remove(&vg->chip);
 +
 +      return 0;
 +}
 +
 +static struct platform_driver byt_gpio_driver = {
 +      .probe          = byt_gpio_probe,
 +      .remove         = byt_gpio_remove,
 +      .driver         = {
 +              .name   = "byt_gpio",
 +              .pm     = &byt_gpio_pm_ops,
 +              .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match),
 +      },
 +};
 +
 +static int __init byt_gpio_init(void)
 +{
 +      return platform_driver_register(&byt_gpio_driver);
 +}
 +subsys_initcall(byt_gpio_init);
 +
 +static void __exit byt_gpio_exit(void)
 +{
 +      platform_driver_unregister(&byt_gpio_driver);
 +}
 +module_exit(byt_gpio_exit);
Simple merge
Simple merge
@@@ -2053,8 -1982,6 +2053,7 @@@ static struct platform_driver rockchip_
        .probe          = rockchip_pinctrl_probe,
        .driver = {
                .name   = "rockchip-pinctrl",
-               .owner  = THIS_MODULE,
 +              .pm = &rockchip_pinctrl_dev_pm_ops,
                .of_match_table = rockchip_pinctrl_dt_match,
        },
  };
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -525,9 -446,7 +525,8 @@@ static struct platform_driver at91_rtc_
        .shutdown       = at91_rtc_shutdown,
        .driver         = {
                .name   = "rtc-at91sam9",
-               .owner  = THIS_MODULE,
                .pm     = &at91_rtc_pm_ops,
 +              .of_match_table = of_match_ptr(at91_rtc_dt_ids),
        },
  };
  
@@@ -718,8 -568,7 +718,7 @@@ static struct platform_driver omap_rtc_
        .remove         = __exit_p(omap_rtc_remove),
        .shutdown       = omap_rtc_shutdown,
        .driver         = {
 -              .name   = DRIVER_NAME,
 +              .name   = "omap_rtc",
-               .owner  = THIS_MODULE,
                .pm     = &omap_rtc_pm_ops,
                .of_match_table = omap_rtc_of_match,
        },
Simple merge
@@@ -367,8 -327,7 +367,7 @@@ MODULE_DEVICE_TABLE(of, snvs_dt_ids)
  static struct platform_driver snvs_rtc_driver = {
        .driver = {
                .name   = "snvs_rtc",
-               .owner  = THIS_MODULE,
 -              .pm     = &snvs_rtc_pm_ops,
 +              .pm     = SNVS_RTC_PM_OPS,
                .of_match_table = snvs_dt_ids,
        },
        .probe          = snvs_rtc_probe,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -342,8 -295,8 +342,7 @@@ static struct of_device_id of_platform_
  static struct platform_driver of_platform_serial_driver = {
        .driver = {
                .name = "of_serial",
-               .owner = THIS_MODULE,
                .of_match_table = of_platform_serial_table,
 -              .pm = &of_serial_pm_ops,
        },
        .probe = of_platform_serial_probe,
        .remove = of_platform_serial_remove,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -247,9 -215,7 +247,8 @@@ static struct platform_driver ci_hdrc_i
        .remove = ci_hdrc_imx_remove,
        .driver = {
                .name = "imx_usb",
-               .owner = THIS_MODULE,
                .of_match_table = ci_hdrc_imx_dt_ids,
 +              .pm = &ci_hdrc_imx_pm_ops,
         },
  };
  
@@@ -867,8 -751,6 +867,7 @@@ static struct platform_driver ci_hdrc_d
        .remove = ci_hdrc_remove,
        .driver = {
                .name   = "ci_hdrc",
-               .owner  = THIS_MODULE,
 +              .pm     = &ci_pm_ops,
        },
  };
  
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -2591,8 -2614,6 +2591,7 @@@ MODULE_ALIAS("platform:pxa27x-udc")
  static struct platform_driver udc_driver = {
        .driver         = {
                .name   = "pxa27x-udc",
-               .owner  = THIS_MODULE,
 +              .of_match_table = of_match_ptr(udc_pxa_dt_ids),
        },
        .probe          = pxa_udc_probe,
        .remove         = pxa_udc_remove,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc fs/pstore/ram.c
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc lib/bitmap.c
Simple merge
diff --cc net/dsa/dsa.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -1170,9 -899,6 +1170,7 @@@ static const struct dev_pm_ops hsw_pcm_
  static struct platform_driver hsw_pcm_driver = {
        .driver = {
                .name = "haswell-pcm-audio",
-               .owner = THIS_MODULE,
 +              .pm = &hsw_pcm_pm,
        },
  
        .probe = hsw_pcm_dev_probe,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge